From fc124714c3901df07d324e5d7bce02db92f9bb64 Mon Sep 17 00:00:00 2001 From: aa-g Date: Wed, 19 May 2021 18:54:41 +0200 Subject: [PATCH 001/598] [WIP] Add CDeformationDriver --- .../include/drivers/CDeformationDriver.hpp | 63 +++ SU2_DEF/src/drivers/CDeformationDriver.cpp | 501 ++++++++++++++++++ SU2_PY/pySU2/Makefile.am | 21 +- SU2_PY/pySU2/pySU2.i | 10 +- SU2_PY/pySU2/pySU2ad.i | 8 +- 5 files changed, 585 insertions(+), 18 deletions(-) create mode 100644 SU2_DEF/include/drivers/CDeformationDriver.hpp create mode 100644 SU2_DEF/src/drivers/CDeformationDriver.cpp diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp new file mode 100644 index 00000000000..afd9a5abb8d --- /dev/null +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -0,0 +1,63 @@ +/*! + * \file CDeformationDriver.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 7.1.1 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once +#include "../../../SU2_CFD/include/drivers/CDriver.hpp" + +/*! + * \class CDeformationDriver + * \brief Class for driving single-zone solvers. + * \author R. Sanchez + * \version 7.1.1 "Blackbird" + */ +class CDeformationDriver : public CDriver { +protected: + + unsigned long TimeIter; + +public: + + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CDeformationDriver(char* confFile, + SU2_Comm MPICommunicator); + + /*! + * \brief Destructor of the class. + */ + ~CDeformationDriver(void) override; + + /*! + * \brief [Overload] Launch the computation for single-zone problems. + */ + void RunSolver(); + +}; diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp new file mode 100644 index 00000000000..0aa20dff8a8 --- /dev/null +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -0,0 +1,501 @@ +/*! + * \file SU2_DEF.cpp + * \brief Main file of Mesh Deformation Code (SU2_DEF). + * \author F. Palacios, T. Economon + * \version 7.1.1 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + + +#include "../../include/drivers/CDeformationDriver.hpp" +#include "../../../Common/include/geometry/CPhysicalGeometry.hpp" +#include "../../../SU2_CFD/include/output/COutput.hpp" +#include "../../../SU2_CFD/include/output/CMeshOutput.hpp" +using namespace std; + +CDeformationDriver::CDeformationDriver(char* confFile, + SU2_Comm MPICommunicator) : CDriver(confFile, + 1, + MPICommunicator, + false) { + + /*--- Initialize the counter for TimeIter ---*/ + TimeIter = 0; +} + +CDeformationDriver::~CDeformationDriver(void) { + +} + +void CDeformationDriver::RunSolver() { + + + unsigned short iZone, nZone = SINGLE_ZONE; + su2double StartTime = 0.0, StopTime = 0.0, UsedTime = 0.0; + char config_file_name[MAX_STRING_SIZE]; + int rank, size; + string str; + + rank = SU2_MPI::GetRank(); + size = SU2_MPI::GetSize(); + + /*--- Pointer to different structures that will be used throughout + the entire code ---*/ + + CConfig **config_container = nullptr; + CGeometry **geometry_container = nullptr; + CSurfaceMovement **surface_movement = nullptr; + CVolumetricMovement **grid_movement = nullptr; + COutput **output = nullptr; + CConfig *driver_config = nullptr; + + /*--- Read the name and format of the input mesh file to get from the mesh + file the number of zones and dimensions from the numerical grid (required + for variables allocation) ---*/ + + CConfig *config = nullptr; + config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); + + nZone = config->GetnZone(); + + /*--- Definition of the containers per zones ---*/ + + config_container = new CConfig*[nZone]; + geometry_container = new CGeometry*[nZone]; + surface_movement = new CSurfaceMovement*[nZone]; + grid_movement = new CVolumetricMovement*[nZone]; + output = new COutput*[nZone]; + + driver_config = nullptr; + + for (iZone = 0; iZone < nZone; iZone++) { + config_container[iZone] = nullptr; + geometry_container[iZone] = nullptr; + surface_movement[iZone] = nullptr; + grid_movement[iZone] = nullptr; + output[iZone] = nullptr; + } + + /*--- Initialize the configuration of the driver ---*/ + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF, false); + + /*--- Initialize a char to store the zone filename ---*/ + char zone_file_name[MAX_STRING_SIZE]; + + /*--- Loop over all zones to initialize the various classes. In most + cases, nZone is equal to one. This represents the solution of a partial + differential equation on a single block, unstructured mesh. ---*/ + + for (iZone = 0; iZone < nZone; iZone++) { + + /*--- Definition of the configuration option class for all zones. In this + constructor, the input configuration file is parsed and all options are + read and stored. ---*/ + + if (driver_config->GetnConfigFiles() > 0){ + strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); + config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); + } + else{ + config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); + } + config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); + } + + /*--- Set the multizone part of the problem. ---*/ + if (driver_config->GetMultizone_Problem()){ + for (iZone = 0; iZone < nZone; iZone++) { + /*--- Set the interface markers for multizone ---*/ + config_container[iZone]->SetMultizone(driver_config, config_container); + } + } + + for (iZone = 0; iZone < nZone; iZone++) { + + /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ + + CGeometry *geometry_aux = nullptr; + + /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ + + geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); + + /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ + + geometry_aux->SetColorGrid_Parallel(config_container[iZone]); + + /*--- Build the grid data structures using the ParMETIS coloring. ---*/ + + geometry_container[iZone] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); + + /*--- Deallocate the memory of geometry_aux ---*/ + + delete geometry_aux; + + /*--- Add the Send/Receive boundaries ---*/ + + geometry_container[iZone]->SetSendReceive(config_container[iZone]); + + /*--- Add the Send/Receive boundaries ---*/ + + geometry_container[iZone]->SetBoundaries(config_container[iZone]); + + } + + /*--- Set up a timer for performance benchmarking (preprocessing time is included) ---*/ + + StartTime = SU2_MPI::Wtime(); + + for (iZone = 0; iZone < nZone; iZone++) { + + /*--- Computational grid preprocesing ---*/ + + if (rank == MASTER_NODE) cout << endl << "----------------------- Preprocessing computations ----------------------" << endl; + + /*--- Compute elements surrounding points, points surrounding points ---*/ + + if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); + + /*--- Check the orientation before computing geometrical quantities ---*/ + + geometry_container[iZone]->SetBoundVolume(); + if (config_container[iZone]->GetReorientElements()) { + if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config_container[iZone]); + geometry_container[iZone]->Check_BoundElem_Orientation(config_container[iZone]); + } + + /*--- Create the edge structure ---*/ + + if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); + geometry_container[iZone]->SetVertex(config_container[iZone]); + + if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { + + /*--- Create the dual control volume structures ---*/ + + if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; + geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); + geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); + + } + /*--- Create the point-to-point MPI communication structures. ---*/ + + geometry_container[iZone]->PreprocessP2PComms(geometry_container[iZone], config_container[iZone]); + + /*--- Allocate the mesh output ---*/ + + output[iZone] = new CMeshOutput(config_container[iZone], geometry_container[iZone]->GetnDim()); + + /*--- Preprocess the volume output ---*/ + + output[iZone]->PreprocessVolumeOutput(config_container[iZone]); + + /*--- Preprocess history --- */ + + output[iZone]->PreprocessHistoryOutput(config_container[iZone], false); + + } + + + /*--- Surface grid deformation using design variables ---*/ + + for (iZone = 0; iZone < nZone; iZone++){ + + if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { + + /*--- Definition of the Class for grid movement ---*/ + grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone], config_container[iZone]); + + /*--- Save original coordinates to be reused in convexity checking procedure ---*/ + auto OriginalCoordinates = geometry_container[iZone]->nodes->GetCoord(); + + /*--- First check for volumetric grid deformation/transformations ---*/ + + if (config_container[iZone]->GetDesign_Variable(0) == SCALE_GRID) { + + if (rank == MASTER_NODE) + cout << endl << "--------------------- Volumetric grid scaling (ZONE " << iZone <<") ------------------" << endl; + grid_movement[iZone]->SetVolume_Scaling(geometry_container[iZone], config_container[iZone], false); + + } else if (config_container[iZone]->GetDesign_Variable(0) == TRANSLATE_GRID) { + + if (rank == MASTER_NODE) + cout << endl << "------------------- Volumetric grid translation (ZONE " << iZone <<") ----------------" << endl; + grid_movement[iZone]->SetVolume_Translation(geometry_container[iZone], config_container[iZone], false); + + } else if (config_container[iZone]->GetDesign_Variable(0) == ROTATE_GRID) { + + if (rank == MASTER_NODE) + cout << endl << "--------------------- Volumetric grid rotation (ZONE " << iZone <<") -----------------" << endl; + grid_movement[iZone]->SetVolume_Rotation(geometry_container[iZone], config_container[iZone], false); + + } else { + + /*--- If no volume-type deformations are requested, then this is a + surface-based deformation or FFD set up. ---*/ + + if (rank == MASTER_NODE) + cout << endl << "--------------------- Surface grid deformation (ZONE " << iZone <<") -----------------" << endl; + + /*--- Definition and initialization of the surface deformation class ---*/ + + surface_movement[iZone] = new CSurfaceMovement(); + + /*--- Copy coordinates to the surface structure ---*/ + + surface_movement[iZone]->CopyBoundary(geometry_container[iZone], config_container[iZone]); + + /*--- Surface grid deformation ---*/ + + if (rank == MASTER_NODE) cout << "Performing the deformation of the surface grid." << endl; + auto TotalDeformation = surface_movement[iZone]->SetSurface_Deformation(geometry_container[iZone], config_container[iZone]); + + if (config_container[iZone]->GetDesign_Variable(0) != FFD_SETTING) { + + if (rank == MASTER_NODE) + cout << endl << "------------------- Volumetric grid deformation (ZONE " << iZone <<") ----------------" << endl; + + if (rank == MASTER_NODE) + cout << "Performing the deformation of the volumetric grid." << endl; + grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone], config_container[iZone], false); + + /*--- Get parameters for convexity check ---*/ + bool ConvexityCheck; + unsigned short ConvexityCheck_MaxIter, ConvexityCheck_MaxDepth; + + tie(ConvexityCheck, ConvexityCheck_MaxIter, ConvexityCheck_MaxDepth) = config_container[iZone]->GetConvexityCheck(); + + /*--- Recursively change deformations if there are nonconvex elements. ---*/ + + if (ConvexityCheck && geometry_container[iZone]->GetnNonconvexElements() > 0) { + if (rank == MASTER_NODE) { + cout << "Nonconvex elements present after deformation. " << endl; + cout << "Recursively lowering deformation magnitude." << endl; + } + + /*--- Load initial deformation values ---*/ + auto InitialDeformation = TotalDeformation; + + unsigned short ConvexityCheckIter, RecursionDepth = 0; + su2double DeformationFactor = 1.0, DeformationDifference = 1.0; + for (ConvexityCheckIter = 1; ConvexityCheckIter <= ConvexityCheck_MaxIter; ConvexityCheckIter++) { + + /*--- Recursively change deformation magnitude: + decrease if there are nonconvex elements, increase otherwise ---*/ + DeformationDifference /= 2.0; + + if (geometry_container[iZone]->GetnNonconvexElements() > 0) { + DeformationFactor -= DeformationDifference; + } else { + RecursionDepth += 1; + + if (RecursionDepth == ConvexityCheck_MaxDepth) { + if (rank == MASTER_NODE) { + cout << "Maximum recursion depth reached." << endl; + cout << "Remaining amount of original deformation: "; + cout << DeformationFactor*100.0 << " percent. " << endl; + } + break; + } + + DeformationFactor += DeformationDifference; + } + + /*--- Load mesh to start every iteration with an undeformed grid ---*/ + for (auto iPoint = 0ul; iPoint < OriginalCoordinates.rows(); iPoint++) { + for (auto iDim = 0ul; iDim < OriginalCoordinates.cols(); iDim++) { + geometry_container[iZone]->nodes->SetCoord(iPoint, iDim, OriginalCoordinates(iPoint,iDim)); + } + } + + /*--- Set deformation magnitude as percentage of initial deformation ---*/ + for (auto iDV = 0u; iDV < config->GetnDV(); iDV++) { + for (auto iDV_Value = 0u; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++) { + config_container[iZone]->SetDV_Value(iDV, iDV_Value, InitialDeformation[iDV][iDV_Value]*DeformationFactor); + } + } + + /*--- Surface grid deformation ---*/ + if (rank == MASTER_NODE) cout << "Performing the deformation of the surface grid." << endl; + + TotalDeformation = surface_movement[iZone]->SetSurface_Deformation(geometry_container[iZone], config_container[iZone]); + + if (rank == MASTER_NODE) + cout << endl << "------------------- Volumetric grid deformation (ZONE " << iZone <<") ----------------" << endl; + + if (rank == MASTER_NODE) + cout << "Performing the deformation of the volumetric grid." << endl; + grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone], config_container[iZone], false); + + if (rank == MASTER_NODE) { + cout << "Number of nonconvex elements for iteration " << ConvexityCheckIter << ": "; + cout << geometry_container[iZone]->GetnNonconvexElements() << endl; + cout << "Remaining amount of original deformation: "; + cout << DeformationFactor*100.0 << " percent. " << endl; + } + + } + + } + + } + + } + + } + + } + + /*--- Computational grid preprocesing ---*/ + + if (rank == MASTER_NODE) cout << endl << "----------------------- Write deformed grid files -----------------------" << endl; + + /*--- Output deformed grid for visualization, if requested (surface and volumetric), in parallel + requires to move all the data to the master node---*/ + + for (iZone = 0; iZone < nZone; iZone++){ + + /*--- Compute Mesh Quality if requested. Necessary geometry preprocessing re-done beforehand. ---*/ + + if (config_container[iZone]->GetWrt_MeshQuality() && !config->GetStructuralProblem()) { + + if (rank == MASTER_NODE) cout << "Recompute geometry properties necessary to evaluate mesh quality statistics.\n"; + + geometry_container[iZone]->SetPoint_Connectivity(); + geometry_container[iZone]->SetBoundVolume(); + geometry_container[iZone]->SetEdges(); + geometry_container[iZone]->SetVertex(config_container[iZone]); + geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); + geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); + + if (rank == MASTER_NODE) cout << "Computing mesh quality statistics for the dual control volumes.\n"; + geometry_container[iZone]->ComputeMeshQualityStatistics(config_container[iZone]); + }// Mesh Quality Output + + /*--- Load the data --- */ + + output[iZone]->Load_Data(geometry_container[iZone], config_container[iZone], nullptr); + + output[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], MESH, config->GetMesh_Out_FileName()); + + /*--- Set the file names for the visualization files ---*/ + + output[iZone]->SetVolume_Filename("volume_deformed"); + output[iZone]->SetSurface_Filename("surface_deformed"); + + for (unsigned short iFile = 0; iFile < config_container[iZone]->GetnVolumeOutputFiles(); iFile++){ + auto FileFormat = config_container[iZone]->GetVolumeOutputFiles(); + if (FileFormat[iFile] != RESTART_ASCII && FileFormat[iFile] != RESTART_BINARY) + output[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], FileFormat[iFile]); + } + } + + + if ((config_container[ZONE_0]->GetDesign_Variable(0) != NO_DEFORMATION) && + (config_container[ZONE_0]->GetDesign_Variable(0) != SCALE_GRID) && + (config_container[ZONE_0]->GetDesign_Variable(0) != TRANSLATE_GRID) && + (config_container[ZONE_0]->GetDesign_Variable(0) != ROTATE_GRID)) { + + /*--- Write the the free-form deformation boxes after deformation. ---*/ + + if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; + + surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); + + } + + delete config; + config = nullptr; + if (rank == MASTER_NODE) + cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; + + if (geometry_container != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (geometry_container[iZone] != nullptr) { + delete geometry_container[iZone]; + } + } + delete [] geometry_container; + } + if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; + + if (surface_movement != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (surface_movement[iZone] != nullptr) { + delete surface_movement[iZone]; + } + } + delete [] surface_movement; + } + if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; + + if (grid_movement != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (grid_movement[iZone] != nullptr) { + delete grid_movement[iZone]; + } + } + delete [] grid_movement; + } + if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; + + if (config_container != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (config_container[iZone] != nullptr) { + delete config_container[iZone]; + } + } + delete [] config_container; + } + if (output != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (output[iZone] != nullptr) { + delete output[iZone]; + } + } + delete [] output; + } + if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; + + if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; + + /*--- Synchronization point after a single solver iteration. Compute the + wall clock time required. ---*/ + + StopTime = SU2_MPI::Wtime(); + + /*--- Compute/print the total time for performance benchmarking. ---*/ + + UsedTime = StopTime-StartTime; + if (rank == MASTER_NODE) { + cout << "\nCompleted in " << fixed << UsedTime << " seconds on "<< size; + if (size == 1) cout << " core." << endl; else cout << " cores." << endl; + } + + /*--- Exit the solver cleanly ---*/ + + if (rank == MASTER_NODE) + cout << endl << "------------------------- Exit Success (SU2_DEF) ------------------------" << endl << endl; + } diff --git a/SU2_PY/pySU2/Makefile.am b/SU2_PY/pySU2/Makefile.am index 29c7ef1833b..631400db6bd 100644 --- a/SU2_PY/pySU2/Makefile.am +++ b/SU2_PY/pySU2/Makefile.am @@ -6,8 +6,8 @@ # \version 7.1.1 "Blackbird" # # SU2 Project Website: https://su2code.github.io -# -# The SU2 Project is maintained by the SU2 Foundation +# +# The SU2 Project is maintained by the SU2 Foundation # (http://su2foundation.org) # # Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) @@ -16,7 +16,7 @@ # 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 @@ -61,15 +61,15 @@ PY_LIB = ${PYTHON_LIBS} \ -L${PYTHON_EXEC_PREFIX}/lib \ -L/usr/lib \ -L/usr/lib/x86_64-linux-gnu - + SWIG_INCLUDE = ${PY_INCLUDE} SUBDIR_EXEC = ${bindir} -all: - ${MAKE} real; - +all: + ${MAKE} real; + # List the dependencies real: ${SWIG_SO_REAL} @@ -104,11 +104,11 @@ pySU2_LD_FLAGS = ${SU2SOLVER_LIB} @su2_externals_LIBS@ ${PY_LIB} # Set the command line flags to use for compilation pySU2_CC_FLAGS = ${CPPFLAGS} ${EXTRA_CC_FLAGS} @su2_externals_INCLUDES@ ${pySU2_INCLUDE} -SO_LINK_FLAGS= -fPIC -shared +SO_LINK_FLAGS= -fPIC -shared # Default rule for creating the _wrap.cxx file from the .i file ${SWIG_WRAP_REAL}.cxx: ${SU2SOLVER_LIB} ${SWIG_SRC} - ${SWIG} ${CPPFLAGS} -Wall ${SWIG_INCLUDE} -outdir ./ -o ${SWIG_WRAP_REAL}.cxx -c++ -python ${SWIG_SRC} + ${SWIG} ${CPPFLAGS} -Wall ${SWIG_INCLUDE} -outdir ./ -o ${SWIG_WRAP_REAL}.cxx -c++ -python ${SWIG_SRC} #Default rule for compiling the .o files ${SWIG_WRAP_REAL}.o: ${SWIG_WRAP_REAL}.cxx @@ -122,7 +122,7 @@ ${SWIG_SO_REAL}: ${SWIG_WRAP_REAL}.o .SECONDARY: -clean: +clean: rm -f ${CURRENT_DIR}/*.cxx rm -f ${CURRENT_DIR}/*.${SO_EXT} rm -f ${CURRENT_DIR}/*.o @@ -132,4 +132,3 @@ clean: install: all ${INSTALL} ${PYLIB} ${bindir} ${INSTALL} ${SOLIB} ${bindir} - diff --git a/SU2_PY/pySU2/pySU2.i b/SU2_PY/pySU2/pySU2.i index e783ac8b48b..c042919a506 100644 --- a/SU2_PY/pySU2/pySU2.i +++ b/SU2_PY/pySU2/pySU2.i @@ -7,8 +7,8 @@ # \version 7.1.1 "Blackbird" # # SU2 Project Website: https://su2code.github.io -# -# The SU2 Project is maintained by the SU2 Foundation +# +# The SU2 Project is maintained by the SU2 Foundation # (http://su2foundation.org) # # Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) @@ -17,7 +17,7 @@ # 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 @@ -42,7 +42,8 @@ threads="1" #include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CDiscAdjSinglezoneDriver.hpp" - +#include "../../SU2_DEF/include/drivers/CDeformationDriver.hpp" + %} // ----------- USED MODULES ------------ @@ -91,3 +92,4 @@ const unsigned int ZONE_1 = 1; /*!< \brief Definition of the first grid domain. %include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CDiscAdjSinglezoneDriver.hpp" +%include "../../SU2_DEF/include/drivers/CDeformationDriver.hpp" diff --git a/SU2_PY/pySU2/pySU2ad.i b/SU2_PY/pySU2/pySU2ad.i index aaf37844c90..910202a138e 100644 --- a/SU2_PY/pySU2/pySU2ad.i +++ b/SU2_PY/pySU2/pySU2ad.i @@ -7,8 +7,8 @@ # \version 7.1.1 "Blackbird" # # SU2 Project Website: https://su2code.github.io -# -# The SU2 Project is maintained by the SU2 Foundation +# +# The SU2 Project is maintained by the SU2 Foundation # (http://su2foundation.org) # # Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) @@ -17,7 +17,7 @@ # 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 @@ -42,6 +42,7 @@ threads="1" #include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CDiscAdjSinglezoneDriver.hpp" +#include "../../SU2_DEF/include/drivers/CDeformationDriver.hpp" %} @@ -91,3 +92,4 @@ const unsigned int ZONE_1 = 1; /*!< \brief Definition of the first grid domain. %include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CDiscAdjSinglezoneDriver.hpp" +%include "../../SU2_DEF/include/drivers/CDeformationDriver.hpp" From 2643405946420bf47459c7961fafa2c4c80eb08b Mon Sep 17 00:00:00 2001 From: aa-g Date: Fri, 21 May 2021 18:48:51 +0200 Subject: [PATCH 002/598] Implement RunSolver() --- .../include/drivers/CDeformationDriver.hpp | 22 ++++-- SU2_DEF/src/drivers/CDeformationDriver.cpp | 36 ++++----- SU2_DEF/src/meson.build | 73 +++++++++++-------- SU2_PY/pySU2/meson.build | 2 +- SU2_PY/pySU2/pySU2ad.i | 2 - 5 files changed, 79 insertions(+), 56 deletions(-) diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index afd9a5abb8d..e2fd22f748f 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -27,7 +27,8 @@ */ #pragma once -#include "../../../SU2_CFD/include/drivers/CDriver.hpp" +#include "../../../Common/include/parallelization/mpi_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" /*! * \class CDeformationDriver @@ -35,13 +36,11 @@ * \author R. Sanchez * \version 7.1.1 "Blackbird" */ -class CDeformationDriver : public CDriver { +class CDeformationDriver { protected: - - unsigned long TimeIter; + char config_file_name[MAX_STRING_SIZE]; public: - /*! * \brief Constructor of the class. * \param[in] confFile - Configuration file name. @@ -53,11 +52,22 @@ class CDeformationDriver : public CDriver { /*! * \brief Destructor of the class. */ - ~CDeformationDriver(void) override; + ~CDeformationDriver(void); /*! * \brief [Overload] Launch the computation for single-zone problems. */ void RunSolver(); +protected: + /*! + * \brief Init_Containers + */ + void SetContainers_Null(); + + /*! + * \brief Read in the config and mesh files. + */ + void Input_Preprocessing(CConfig **&config, CConfig *&driver_config); + }; diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 0aa20dff8a8..529085f87e6 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -12,7 +12,7 @@ * Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) * * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public + * 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. * @@ -28,18 +28,25 @@ #include "../../include/drivers/CDeformationDriver.hpp" #include "../../../Common/include/geometry/CPhysicalGeometry.hpp" +#include "../../../Common/include/grid_movement/CSurfaceMovement.hpp" +#include "../../../Common/include/grid_movement/CVolumetricMovement.hpp" #include "../../../SU2_CFD/include/output/COutput.hpp" #include "../../../SU2_CFD/include/output/CMeshOutput.hpp" using namespace std; -CDeformationDriver::CDeformationDriver(char* confFile, - SU2_Comm MPICommunicator) : CDriver(confFile, - 1, - MPICommunicator, - false) { +CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) { - /*--- Initialize the counter for TimeIter ---*/ - TimeIter = 0; + /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ + #ifdef HAVE_MPI + #if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE) + SU2_MPI::Init_AMPI(); + #endif + #endif + + SU2_MPI::SetComm(MPICommunicator); + + /*--- Copy the config filename ---*/ + strcpy(config_file_name, confFile); } CDeformationDriver::~CDeformationDriver(void) { @@ -48,15 +55,12 @@ CDeformationDriver::~CDeformationDriver(void) { void CDeformationDriver::RunSolver() { - - unsigned short iZone, nZone = SINGLE_ZONE; + unsigned short iZone, nZone = SINGLE_ZONE; su2double StartTime = 0.0, StopTime = 0.0, UsedTime = 0.0; - char config_file_name[MAX_STRING_SIZE]; - int rank, size; string str; - rank = SU2_MPI::GetRank(); - size = SU2_MPI::GetSize(); + int rank = SU2_MPI::GetRank(); + int size = SU2_MPI::GetSize(); /*--- Pointer to different structures that will be used throughout the entire code ---*/ @@ -79,7 +83,7 @@ void CDeformationDriver::RunSolver() { /*--- Definition of the containers per zones ---*/ - config_container = new CConfig*[nZone]; + config_container = new CConfig*[nZone]; geometry_container = new CGeometry*[nZone]; surface_movement = new CSurfaceMovement*[nZone]; grid_movement = new CVolumetricMovement*[nZone]; @@ -215,10 +219,8 @@ void CDeformationDriver::RunSolver() { /*--- Preprocess history --- */ output[iZone]->PreprocessHistoryOutput(config_container[iZone], false); - } - /*--- Surface grid deformation using design variables ---*/ for (iZone = 0; iZone < nZone; iZone++){ diff --git a/SU2_DEF/src/meson.build b/SU2_DEF/src/meson.build index d18ed7a46b0..a6681c5c88d 100644 --- a/SU2_DEF/src/meson.build +++ b/SU2_DEF/src/meson.build @@ -1,38 +1,51 @@ -su2_def_src = ['SU2_DEF.cpp'] +su2_def_include = include_directories('./') +su2_def_src = files([ + 'SU2_DEF.cpp', + 'drivers/CDeformationDriver.cpp' +]) if get_option('enable-normal') - su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', - 'solvers/CBaselineSolver.cpp', - 'CMarkerProfileReaderFVM.cpp', - 'output/COutput.cpp', - 'output/tools/CWindowingTools.cpp', - 'output/CMeshOutput.cpp', - 'output/output_structure_legacy.cpp', - 'variables/CBaselineVariable.cpp', - 'variables/CVariable.cpp', - 'output/filewriter/CParallelDataSorter.cpp', - 'output/filewriter/CFVMDataSorter.cpp', - 'output/filewriter/CFEMDataSorter.cpp', - 'output/filewriter/CSurfaceFEMDataSorter.cpp', - 'output/filewriter/CSurfaceFVMDataSorter.cpp', - 'output/filewriter/CParallelFileWriter.cpp', - 'output/filewriter/CParaviewFileWriter.cpp', - 'output/filewriter/CParaviewBinaryFileWriter.cpp', - 'output/filewriter/CTecplotFileWriter.cpp', - 'output/filewriter/CTecplotBinaryFileWriter.cpp', - 'output/filewriter/CCSVFileWriter.cpp', - 'output/filewriter/CSTLFileWriter.cpp', - 'output/filewriter/CSU2FileWriter.cpp', - 'output/filewriter/CSU2BinaryFileWriter.cpp', - 'output/filewriter/CParaviewXMLFileWriter.cpp', - 'output/filewriter/CParaviewVTMFileWriter.cpp', - 'output/filewriter/CSU2MeshFileWriter.cpp', - 'limiters/CLimiterDetails.cpp']) +su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', + 'solvers/CBaselineSolver.cpp', + 'CMarkerProfileReaderFVM.cpp', + 'output/COutput.cpp', + 'output/tools/CWindowingTools.cpp', + 'output/CMeshOutput.cpp', + 'output/output_structure_legacy.cpp', + 'variables/CBaselineVariable.cpp', + 'variables/CVariable.cpp', + 'output/filewriter/CParallelDataSorter.cpp', + 'output/filewriter/CFVMDataSorter.cpp', + 'output/filewriter/CFEMDataSorter.cpp', + 'output/filewriter/CSurfaceFEMDataSorter.cpp', + 'output/filewriter/CSurfaceFVMDataSorter.cpp', + 'output/filewriter/CParallelFileWriter.cpp', + 'output/filewriter/CParaviewFileWriter.cpp', + 'output/filewriter/CParaviewBinaryFileWriter.cpp', + 'output/filewriter/CTecplotFileWriter.cpp', + 'output/filewriter/CTecplotBinaryFileWriter.cpp', + 'output/filewriter/CCSVFileWriter.cpp', + 'output/filewriter/CSTLFileWriter.cpp', + 'output/filewriter/CSU2FileWriter.cpp', + 'output/filewriter/CSU2BinaryFileWriter.cpp', + 'output/filewriter/CParaviewXMLFileWriter.cpp', + 'output/filewriter/CParaviewVTMFileWriter.cpp', + 'output/filewriter/CSU2MeshFileWriter.cpp', + 'limiters/CLimiterDetails.cpp']) + + su2_def_lib = static_library('SU2core_DEF', + su2_def_src, + install : false, + dependencies : [su2_deps, common_dep], + cpp_args: [default_warning_flags, su2_cpp_args]) + + su2_def_dep = declare_dependency(link_with: su2_def_lib, + include_directories: su2_def_include) su2_def = executable('SU2_DEF', - su2_def_src, + su2_def_src, install: true, - dependencies: [su2_deps, common_dep], + dependencies: [su2_deps, common_dep], objects : su2_cfd_obj, cpp_args :[default_warning_flags, su2_cpp_args]) endif diff --git a/SU2_PY/pySU2/meson.build b/SU2_PY/pySU2/meson.build index 1404f7fe10a..1aab2e53b50 100644 --- a/SU2_PY/pySU2/meson.build +++ b/SU2_PY/pySU2/meson.build @@ -28,7 +28,7 @@ if get_option('enable-normal') '_pysu2', cpp_source, dependencies: [wrapper_deps, common_dep, su2_deps], - objects: su2_cfd_lib.extract_all_objects(), + objects: [su2_cfd_lib.extract_all_objects(), su2_def_lib.extract_objects('drivers/CDeformationDriver.cpp')], install: true, include_directories : mpi4py_include, cpp_args : [default_warning_flags,su2_cpp_args], diff --git a/SU2_PY/pySU2/pySU2ad.i b/SU2_PY/pySU2/pySU2ad.i index 910202a138e..4409fd93fcb 100644 --- a/SU2_PY/pySU2/pySU2ad.i +++ b/SU2_PY/pySU2/pySU2ad.i @@ -42,7 +42,6 @@ threads="1" #include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CDiscAdjSinglezoneDriver.hpp" -#include "../../SU2_DEF/include/drivers/CDeformationDriver.hpp" %} @@ -92,4 +91,3 @@ const unsigned int ZONE_1 = 1; /*!< \brief Definition of the first grid domain. %include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CDiscAdjSinglezoneDriver.hpp" -%include "../../SU2_DEF/include/drivers/CDeformationDriver.hpp" From 907b5bfd4fae3f6db7ec141f9de9c3f002bd220f Mon Sep 17 00:00:00 2001 From: aa-g Date: Tue, 25 May 2021 19:06:39 +0200 Subject: [PATCH 003/598] Clean up CDeformationDriver implementation. Refactor some pre-processing operations in constructor to Geometrical_Preprocessing() and Output_Preprocessing(). Refactor SU2_DEF main function to use the new CDeformationDriver class. --- SU2_DEF/include/SU2_DEF.hpp | 7 +- .../include/drivers/CDeformationDriver.hpp | 53 +- SU2_DEF/src/SU2_DEF.cpp | 456 +----------------- SU2_DEF/src/drivers/CDeformationDriver.cpp | 265 +++++----- 4 files changed, 200 insertions(+), 581 deletions(-) diff --git a/SU2_DEF/include/SU2_DEF.hpp b/SU2_DEF/include/SU2_DEF.hpp index 462599f36df..505e72a73d0 100644 --- a/SU2_DEF/include/SU2_DEF.hpp +++ b/SU2_DEF/include/SU2_DEF.hpp @@ -32,14 +32,11 @@ #include "../../Common/include/parallelization/mpi_structure.hpp" #include "../../Common/include/parallelization/omp_structure.hpp" +#include "drivers/CDeformationDriver.hpp" + #include #include #include #include -#include "../../SU2_CFD/include/solvers/CSolver.hpp" -#include "../../SU2_CFD/include/output/CMeshOutput.hpp" -#include "../../Common/include/geometry/CPhysicalGeometry.hpp" -#include "../../Common/include/CConfig.hpp" - using namespace std; diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index e2fd22f748f..b76a2919976 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -27,7 +27,12 @@ */ #pragma once + #include "../../../Common/include/parallelization/mpi_structure.hpp" + +#include "../../../Common/include/grid_movement/CSurfaceMovement.hpp" +#include "../../../Common/include/grid_movement/CVolumetricMovement.hpp" +#include "../../../SU2_CFD/include/output/COutput.hpp" #include "../../../Common/include/geometry/CGeometry.hpp" /*! @@ -39,6 +44,21 @@ class CDeformationDriver { protected: char config_file_name[MAX_STRING_SIZE]; + int rank, + size; + su2double StartTime, /*!< \brief Start point of the timer for performance benchmarking.*/ + StopTime, /*!< \brief Stop point of the timer for performance benchmarking.*/ + UsedTimePreproc, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking preprocessing phase.*/ + UsedTimeCompute, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking compute phase.*/ + UsedTime; /*!< \brief Elapsed time between Start and Stop point of the timer.*/ + unsigned short iZone, nZone = SINGLE_ZONE; + CConfig *driver_config; /*!< \brief Definition of the driver configuration. */ + CConfig **config_container; /*!< \brief Definition of the particular problem. */ + CGeometry **geometry_container; /*!< \brief Geometrical definition of the problem. */ + CSurfaceMovement **surface_movement; /*!< \brief Surface movement classes of the problem. */ + CVolumetricMovement **grid_movement; /*!< \brief Volume grid movement classes of the problem. */ + COutput **output_container; /*!< \brief Pointer to the COutput class. */ + /*!< \brief FFD FFDBoxes of the problem. */ public: /*! @@ -57,17 +77,32 @@ class CDeformationDriver { /*! * \brief [Overload] Launch the computation for single-zone problems. */ - void RunSolver(); + void Run(); + + /*! + * \brief Deallocation routine + */ + void Postprocessing(); protected: - /*! - * \brief Init_Containers - */ - void SetContainers_Null(); + /*! + * \brief Init_Containers + */ + void SetContainers_Null(); - /*! - * \brief Read in the config and mesh files. - */ - void Input_Preprocessing(CConfig **&config, CConfig *&driver_config); + /*! + * \brief Read in the config and mesh files. + */ + void Input_Preprocessing(); + + /*! + * \brief Construction of the edge-based data structure. + */ + void Geometrical_Preprocessing(CConfig *config, CGeometry *&geometry); + + /*! + * \brief Preprocess the output container. + */ + void Output_Preprocessing(CConfig *config, CGeometry *geometry, COutput *&output); }; diff --git a/SU2_DEF/src/SU2_DEF.cpp b/SU2_DEF/src/SU2_DEF.cpp index adb078ae4a1..ea0ce32bcb2 100644 --- a/SU2_DEF/src/SU2_DEF.cpp +++ b/SU2_DEF/src/SU2_DEF.cpp @@ -27,15 +27,16 @@ #include "../include/SU2_DEF.hpp" + using namespace std; int main(int argc, char *argv[]) { - unsigned short iZone, nZone = SINGLE_ZONE; - su2double StartTime = 0.0, StopTime = 0.0, UsedTime = 0.0; char config_file_name[MAX_STRING_SIZE]; - int rank, size; - string str; + + /*--- Create a pointer to the main SU2_DEF Driver ---*/ + + CDeformationDriver* driver = nullptr; /*--- MPI initialization ---*/ @@ -45,20 +46,7 @@ int main(int argc, char *argv[]) { #else SU2_MPI::Init(&argc, &argv); #endif - SU2_MPI::Comm MPICommunicator = SU2_MPI::GetComm(); - - rank = SU2_MPI::GetRank(); - size = SU2_MPI::GetSize(); - - /*--- Pointer to different structures that will be used throughout - the entire code ---*/ - - CConfig **config_container = nullptr; - CGeometry **geometry_container = nullptr; - CSurfaceMovement **surface_movement = nullptr; - CVolumetricMovement **grid_movement = nullptr; - COutput **output = nullptr; - CConfig *driver_config = nullptr; + SU2_MPI::Comm comm = SU2_MPI::GetComm(); /*--- Load in the number of zones and spatial dimensions in the mesh file (if no config file is specified, default.cfg is used) ---*/ @@ -66,436 +54,18 @@ int main(int argc, char *argv[]) { if (argc == 2) { strcpy(config_file_name, argv[1]); } else { strcpy(config_file_name, "default.cfg"); } - /*--- Read the name and format of the input mesh file to get from the mesh - file the number of zones and dimensions from the numerical grid (required - for variables allocation) ---*/ - - CConfig *config = nullptr; - config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); - - nZone = config->GetnZone(); - - /*--- Definition of the containers per zones ---*/ - - config_container = new CConfig*[nZone]; - geometry_container = new CGeometry*[nZone]; - surface_movement = new CSurfaceMovement*[nZone]; - grid_movement = new CVolumetricMovement*[nZone]; - output = new COutput*[nZone]; - - driver_config = nullptr; - - for (iZone = 0; iZone < nZone; iZone++) { - config_container[iZone] = nullptr; - geometry_container[iZone] = nullptr; - surface_movement[iZone] = nullptr; - grid_movement[iZone] = nullptr; - output[iZone] = nullptr; - } - - /*--- Initialize the configuration of the driver ---*/ - driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF, false); - - /*--- Initialize a char to store the zone filename ---*/ - char zone_file_name[MAX_STRING_SIZE]; - - /*--- Loop over all zones to initialize the various classes. In most - cases, nZone is equal to one. This represents the solution of a partial - differential equation on a single block, unstructured mesh. ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Definition of the configuration option class for all zones. In this - constructor, the input configuration file is parsed and all options are - read and stored. ---*/ - - if (driver_config->GetnConfigFiles() > 0){ - strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); - config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); - } - else{ - config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); - } - config_container[iZone]->SetMPICommunicator(MPICommunicator); - } - - /*--- Set the multizone part of the problem. ---*/ - if (driver_config->GetMultizone_Problem()){ - for (iZone = 0; iZone < nZone; iZone++) { - /*--- Set the interface markers for multizone ---*/ - config_container[iZone]->SetMultizone(driver_config, config_container); - } - } - - for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ - - CGeometry *geometry_aux = nullptr; - - /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ - - geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); - - /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - - geometry_aux->SetColorGrid_Parallel(config_container[iZone]); - - /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - - geometry_container[iZone] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); - - /*--- Deallocate the memory of geometry_aux ---*/ - - delete geometry_aux; - - /*--- Add the Send/Receive boundaries ---*/ - - geometry_container[iZone]->SetSendReceive(config_container[iZone]); - - /*--- Add the Send/Receive boundaries ---*/ - - geometry_container[iZone]->SetBoundaries(config_container[iZone]); - - } - - /*--- Set up a timer for performance benchmarking (preprocessing time is included) ---*/ - - StartTime = SU2_MPI::Wtime(); - - for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Computational grid preprocesing ---*/ - - if (rank == MASTER_NODE) cout << endl << "----------------------- Preprocessing computations ----------------------" << endl; - - /*--- Compute elements surrounding points, points surrounding points ---*/ - - if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); - - /*--- Check the orientation before computing geometrical quantities ---*/ - - geometry_container[iZone]->SetBoundVolume(); - if (config_container[iZone]->GetReorientElements()) { - if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config_container[iZone]); - geometry_container[iZone]->Check_BoundElem_Orientation(config_container[iZone]); - } - - /*--- Create the edge structure ---*/ - - if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); - geometry_container[iZone]->SetVertex(config_container[iZone]); - - if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { - - /*--- Create the dual control volume structures ---*/ - - if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; - geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); - geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); - - } - /*--- Create the point-to-point MPI communication structures. ---*/ - - geometry_container[iZone]->PreprocessP2PComms(geometry_container[iZone], config_container[iZone]); - - /*--- Allocate the mesh output ---*/ - - output[iZone] = new CMeshOutput(config_container[iZone], geometry_container[iZone]->GetnDim()); - - /*--- Preprocess the volume output ---*/ - - output[iZone]->PreprocessVolumeOutput(config_container[iZone]); - - /*--- Preprocess history --- */ - - output[iZone]->PreprocessHistoryOutput(config_container[iZone], false); - - } - - - /*--- Surface grid deformation using design variables ---*/ - - for (iZone = 0; iZone < nZone; iZone++){ - - if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { - - /*--- Definition of the Class for grid movement ---*/ - grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone], config_container[iZone]); - - /*--- Save original coordinates to be reused in convexity checking procedure ---*/ - auto OriginalCoordinates = geometry_container[iZone]->nodes->GetCoord(); - - /*--- First check for volumetric grid deformation/transformations ---*/ - - if (config_container[iZone]->GetDesign_Variable(0) == SCALE_GRID) { - - if (rank == MASTER_NODE) - cout << endl << "--------------------- Volumetric grid scaling (ZONE " << iZone <<") ------------------" << endl; - grid_movement[iZone]->SetVolume_Scaling(geometry_container[iZone], config_container[iZone], false); - - } else if (config_container[iZone]->GetDesign_Variable(0) == TRANSLATE_GRID) { - - if (rank == MASTER_NODE) - cout << endl << "------------------- Volumetric grid translation (ZONE " << iZone <<") ----------------" << endl; - grid_movement[iZone]->SetVolume_Translation(geometry_container[iZone], config_container[iZone], false); - - } else if (config_container[iZone]->GetDesign_Variable(0) == ROTATE_GRID) { - - if (rank == MASTER_NODE) - cout << endl << "--------------------- Volumetric grid rotation (ZONE " << iZone <<") -----------------" << endl; - grid_movement[iZone]->SetVolume_Rotation(geometry_container[iZone], config_container[iZone], false); - - } else { - - /*--- If no volume-type deformations are requested, then this is a - surface-based deformation or FFD set up. ---*/ - - if (rank == MASTER_NODE) - cout << endl << "--------------------- Surface grid deformation (ZONE " << iZone <<") -----------------" << endl; - - /*--- Definition and initialization of the surface deformation class ---*/ - - surface_movement[iZone] = new CSurfaceMovement(); - - /*--- Copy coordinates to the surface structure ---*/ - - surface_movement[iZone]->CopyBoundary(geometry_container[iZone], config_container[iZone]); - - /*--- Surface grid deformation ---*/ - - if (rank == MASTER_NODE) cout << "Performing the deformation of the surface grid." << endl; - auto TotalDeformation = surface_movement[iZone]->SetSurface_Deformation(geometry_container[iZone], config_container[iZone]); - - if (config_container[iZone]->GetDesign_Variable(0) != FFD_SETTING) { - - if (rank == MASTER_NODE) - cout << endl << "------------------- Volumetric grid deformation (ZONE " << iZone <<") ----------------" << endl; - - if (rank == MASTER_NODE) - cout << "Performing the deformation of the volumetric grid." << endl; - grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone], config_container[iZone], false); - - /*--- Get parameters for convexity check ---*/ - bool ConvexityCheck; - unsigned short ConvexityCheck_MaxIter, ConvexityCheck_MaxDepth; - - tie(ConvexityCheck, ConvexityCheck_MaxIter, ConvexityCheck_MaxDepth) = config_container[iZone]->GetConvexityCheck(); - - /*--- Recursively change deformations if there are nonconvex elements. ---*/ - - if (ConvexityCheck && geometry_container[iZone]->GetnNonconvexElements() > 0) { - if (rank == MASTER_NODE) { - cout << "Nonconvex elements present after deformation. " << endl; - cout << "Recursively lowering deformation magnitude." << endl; - } - - /*--- Load initial deformation values ---*/ - auto InitialDeformation = TotalDeformation; - - unsigned short ConvexityCheckIter, RecursionDepth = 0; - su2double DeformationFactor = 1.0, DeformationDifference = 1.0; - for (ConvexityCheckIter = 1; ConvexityCheckIter <= ConvexityCheck_MaxIter; ConvexityCheckIter++) { - - /*--- Recursively change deformation magnitude: - decrease if there are nonconvex elements, increase otherwise ---*/ - DeformationDifference /= 2.0; - - if (geometry_container[iZone]->GetnNonconvexElements() > 0) { - DeformationFactor -= DeformationDifference; - } else { - RecursionDepth += 1; - - if (RecursionDepth == ConvexityCheck_MaxDepth) { - if (rank == MASTER_NODE) { - cout << "Maximum recursion depth reached." << endl; - cout << "Remaining amount of original deformation: "; - cout << DeformationFactor*100.0 << " percent. " << endl; - } - break; - } - - DeformationFactor += DeformationDifference; - } - - /*--- Load mesh to start every iteration with an undeformed grid ---*/ - for (auto iPoint = 0ul; iPoint < OriginalCoordinates.rows(); iPoint++) { - for (auto iDim = 0ul; iDim < OriginalCoordinates.cols(); iDim++) { - geometry_container[iZone]->nodes->SetCoord(iPoint, iDim, OriginalCoordinates(iPoint,iDim)); - } - } - - /*--- Set deformation magnitude as percentage of initial deformation ---*/ - for (auto iDV = 0u; iDV < config->GetnDV(); iDV++) { - for (auto iDV_Value = 0u; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++) { - config_container[iZone]->SetDV_Value(iDV, iDV_Value, InitialDeformation[iDV][iDV_Value]*DeformationFactor); - } - } - - /*--- Surface grid deformation ---*/ - if (rank == MASTER_NODE) cout << "Performing the deformation of the surface grid." << endl; - - TotalDeformation = surface_movement[iZone]->SetSurface_Deformation(geometry_container[iZone], config_container[iZone]); - - if (rank == MASTER_NODE) - cout << endl << "------------------- Volumetric grid deformation (ZONE " << iZone <<") ----------------" << endl; - - if (rank == MASTER_NODE) - cout << "Performing the deformation of the volumetric grid." << endl; - grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone], config_container[iZone], false); - - if (rank == MASTER_NODE) { - cout << "Number of nonconvex elements for iteration " << ConvexityCheckIter << ": "; - cout << geometry_container[iZone]->GetnNonconvexElements() << endl; - cout << "Remaining amount of original deformation: "; - cout << DeformationFactor*100.0 << " percent. " << endl; - } - - } - - } - - } - - } - - } - - } - - /*--- Computational grid preprocesing ---*/ - - if (rank == MASTER_NODE) cout << endl << "----------------------- Write deformed grid files -----------------------" << endl; - - /*--- Output deformed grid for visualization, if requested (surface and volumetric), in parallel - requires to move all the data to the master node---*/ - - for (iZone = 0; iZone < nZone; iZone++){ - - /*--- Compute Mesh Quality if requested. Necessary geometry preprocessing re-done beforehand. ---*/ - - if (config_container[iZone]->GetWrt_MeshQuality() && !config->GetStructuralProblem()) { - - if (rank == MASTER_NODE) cout << "Recompute geometry properties necessary to evaluate mesh quality statistics.\n"; - - geometry_container[iZone]->SetPoint_Connectivity(); - geometry_container[iZone]->SetBoundVolume(); - geometry_container[iZone]->SetEdges(); - geometry_container[iZone]->SetVertex(config_container[iZone]); - geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); - geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); - - if (rank == MASTER_NODE) cout << "Computing mesh quality statistics for the dual control volumes.\n"; - geometry_container[iZone]->ComputeMeshQualityStatistics(config_container[iZone]); - }// Mesh Quality Output - - /*--- Load the data --- */ - - output[iZone]->Load_Data(geometry_container[iZone], config_container[iZone], nullptr); - - output[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], MESH, config->GetMesh_Out_FileName()); - - /*--- Set the file names for the visualization files ---*/ - - output[iZone]->SetVolume_Filename("volume_deformed"); - output[iZone]->SetSurface_Filename("surface_deformed"); - - for (unsigned short iFile = 0; iFile < config_container[iZone]->GetnVolumeOutputFiles(); iFile++){ - auto FileFormat = config_container[iZone]->GetVolumeOutputFiles(); - if (FileFormat[iFile] != RESTART_ASCII && FileFormat[iFile] != RESTART_BINARY) - output[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], FileFormat[iFile]); - } - } - - - if ((config_container[ZONE_0]->GetDesign_Variable(0) != NO_DEFORMATION) && - (config_container[ZONE_0]->GetDesign_Variable(0) != SCALE_GRID) && - (config_container[ZONE_0]->GetDesign_Variable(0) != TRANSLATE_GRID) && - (config_container[ZONE_0]->GetDesign_Variable(0) != ROTATE_GRID)) { - - /*--- Write the the free-form deformation boxes after deformation. ---*/ - - if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; - - surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); - - } - - delete config; - config = nullptr; - if (rank == MASTER_NODE) - cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; - - if (geometry_container != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (geometry_container[iZone] != nullptr) { - delete geometry_container[iZone]; - } - } - delete [] geometry_container; - } - if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; - - if (surface_movement != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (surface_movement[iZone] != nullptr) { - delete surface_movement[iZone]; - } - } - delete [] surface_movement; - } - if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; - - if (grid_movement != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (grid_movement[iZone] != nullptr) { - delete grid_movement[iZone]; - } - } - delete [] grid_movement; - } - if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; - - if (config_container != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (config_container[iZone] != nullptr) { - delete config_container[iZone]; - } - } - delete [] config_container; - } - if (output != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (output[iZone] != nullptr) { - delete output[iZone]; - } - } - delete [] output; - } - if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; - - if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; - - /*--- Synchronization point after a single solver iteration. Compute the - wall clock time required. ---*/ + /*--- Initialize the mesh deformation driver ---*/ + driver = new CDeformationDriver(config_file_name, comm); - StopTime = SU2_MPI::Wtime(); + /*--- Launch the main external loop of the solver. ---*/ - /*--- Compute/print the total time for performance benchmarking. ---*/ + driver->Run(); - UsedTime = StopTime-StartTime; - if (rank == MASTER_NODE) { - cout << "\nCompleted in " << fixed << UsedTime << " seconds on "<< size; - if (size == 1) cout << " core." << endl; else cout << " cores." << endl; - } + /*--- Postprocess all the containers, close history file, exit SU2. ---*/ - /*--- Exit the solver cleanly ---*/ + driver->Postprocessing(); - if (rank == MASTER_NODE) - cout << endl << "------------------------- Exit Success (SU2_DEF) ------------------------" << endl << endl; + delete driver; /*--- Finalize MPI parallelization ---*/ SU2_MPI::Finalize(); diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 529085f87e6..9ceb6b65fc5 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -28,9 +28,6 @@ #include "../../include/drivers/CDeformationDriver.hpp" #include "../../../Common/include/geometry/CPhysicalGeometry.hpp" -#include "../../../Common/include/grid_movement/CSurfaceMovement.hpp" -#include "../../../Common/include/grid_movement/CVolumetricMovement.hpp" -#include "../../../SU2_CFD/include/output/COutput.hpp" #include "../../../SU2_CFD/include/output/CMeshOutput.hpp" using namespace std; @@ -43,183 +40,202 @@ CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) #endif #endif - SU2_MPI::SetComm(MPICommunicator); + SU2_MPI::SetComm(MPICommunicator); + + rank = SU2_MPI::GetRank(); + size = SU2_MPI::GetSize(); /*--- Copy the config filename ---*/ strcpy(config_file_name, confFile); -} -CDeformationDriver::~CDeformationDriver(void) { + /*--- Initialize the configuration of the driver ---*/ + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF, false); -} + nZone = driver_config->GetnZone(); + + /*--- Initialize containers --- */ + + SetContainers_Null(); + + /*--- Preprocessing of the config files. ---*/ -void CDeformationDriver::RunSolver() { + Input_Preprocessing(); - unsigned short iZone, nZone = SINGLE_ZONE; - su2double StartTime = 0.0, StopTime = 0.0, UsedTime = 0.0; - string str; + /*--- Set up a timer for performance benchmarking ---*/ - int rank = SU2_MPI::GetRank(); - int size = SU2_MPI::GetSize(); + StartTime = SU2_MPI::Wtime(); - /*--- Pointer to different structures that will be used throughout - the entire code ---*/ + for (iZone = 0; iZone < nZone; iZone++) { - CConfig **config_container = nullptr; - CGeometry **geometry_container = nullptr; - CSurfaceMovement **surface_movement = nullptr; - CVolumetricMovement **grid_movement = nullptr; - COutput **output = nullptr; - CConfig *driver_config = nullptr; + /*--- Preprocessing of the geometry for all zones. ---*/ - /*--- Read the name and format of the input mesh file to get from the mesh - file the number of zones and dimensions from the numerical grid (required - for variables allocation) ---*/ + Geometrical_Preprocessing(config_container[iZone], geometry_container[iZone]); - CConfig *config = nullptr; - config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); + /*--- Preprocessing of the output for all zones. ---*/ - nZone = config->GetnZone(); + Output_Preprocessing(config_container[iZone], geometry_container[iZone], output_container[iZone]); - /*--- Definition of the containers per zones ---*/ + } + + /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ + + StopTime = SU2_MPI::Wtime(); + + /*--- Compute/print the total time for performance benchmarking. ---*/ + + UsedTime = StopTime-StartTime; + UsedTimePreproc = UsedTime; + UsedTimeCompute = 0.0; + +} +CDeformationDriver::~CDeformationDriver(void) { + +} + +void CDeformationDriver::SetContainers_Null() { + + /*--- Create pointers to all of the classes that may be used throughout + the SU2_DEF code. In general, the pointers are instantiated down a + hierarchy over all zones as described in the comments below. ---*/ config_container = new CConfig*[nZone]; geometry_container = new CGeometry*[nZone]; surface_movement = new CSurfaceMovement*[nZone]; grid_movement = new CVolumetricMovement*[nZone]; - output = new COutput*[nZone]; - - driver_config = nullptr; + output_container = new COutput*[nZone]; for (iZone = 0; iZone < nZone; iZone++) { - config_container[iZone] = nullptr; - geometry_container[iZone] = nullptr; - surface_movement[iZone] = nullptr; - grid_movement[iZone] = nullptr; - output[iZone] = nullptr; + config_container[iZone] = nullptr; + geometry_container[iZone] = nullptr; + surface_movement[iZone] = nullptr; + grid_movement[iZone] = nullptr; + output_container[iZone] = nullptr; } +} - /*--- Initialize the configuration of the driver ---*/ - driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF, false); +void CDeformationDriver::Input_Preprocessing() { /*--- Initialize a char to store the zone filename ---*/ char zone_file_name[MAX_STRING_SIZE]; /*--- Loop over all zones to initialize the various classes. In most - cases, nZone is equal to one. This represents the solution of a partial - differential equation on a single block, unstructured mesh. ---*/ + cases, nZone is equal to one. This represents the solution of a partial + differential equation on a single block, unstructured mesh. ---*/ for (iZone = 0; iZone < nZone; iZone++) { - /*--- Definition of the configuration option class for all zones. In this - constructor, the input configuration file is parsed and all options are - read and stored. ---*/ + /*--- Definition of the configuration option class for all zones. In this + constructor, the input configuration file is parsed and all options are + read and stored. ---*/ - if (driver_config->GetnConfigFiles() > 0){ - strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); - config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); - } - else{ - config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); - } - config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); + if (driver_config->GetnConfigFiles() > 0){ + strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); + config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); + } else { + config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); + } + + config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); } - /*--- Set the multizone part of the problem. ---*/ + /*--- Set the multizone part of the problem. ---*/ if (driver_config->GetMultizone_Problem()){ - for (iZone = 0; iZone < nZone; iZone++) { - /*--- Set the interface markers for multizone ---*/ - config_container[iZone]->SetMultizone(driver_config, config_container); - } + for (iZone = 0; iZone < nZone; iZone++) { + /*--- Set the interface markers for multizone ---*/ + config_container[iZone]->SetMultizone(driver_config, config_container); + } } +} - for (iZone = 0; iZone < nZone; iZone++) { +void CDeformationDriver::Geometrical_Preprocessing(CConfig *config, CGeometry *&geometry) { - /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ + /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ - CGeometry *geometry_aux = nullptr; + CGeometry *geometry_aux = nullptr; - /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ + /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ - geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); + geometry_aux = new CPhysicalGeometry(config, iZone, nZone); - /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ + /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - geometry_aux->SetColorGrid_Parallel(config_container[iZone]); + geometry_aux->SetColorGrid_Parallel(config); - /*--- Build the grid data structures using the ParMETIS coloring. ---*/ + /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - geometry_container[iZone] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); + geometry = new CPhysicalGeometry(geometry_aux, config); - /*--- Deallocate the memory of geometry_aux ---*/ + /*--- Deallocate the memory of geometry_aux ---*/ - delete geometry_aux; + delete geometry_aux; - /*--- Add the Send/Receive boundaries ---*/ + /*--- Add the Send/Receive boundaries ---*/ - geometry_container[iZone]->SetSendReceive(config_container[iZone]); + geometry->SetSendReceive(config); - /*--- Add the Send/Receive boundaries ---*/ + /*--- Add the Send/Receive boundaries ---*/ - geometry_container[iZone]->SetBoundaries(config_container[iZone]); + geometry->SetBoundaries(config); - } + /*--- Computational grid preprocesing ---*/ - /*--- Set up a timer for performance benchmarking (preprocessing time is included) ---*/ + if (rank == MASTER_NODE) cout << endl << "----------------------- Preprocessing computations ----------------------" << endl; - StartTime = SU2_MPI::Wtime(); + /*--- Compute elements surrounding points, points surrounding points ---*/ - for (iZone = 0; iZone < nZone; iZone++) { + if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); - /*--- Computational grid preprocesing ---*/ + /*--- Check the orientation before computing geometrical quantities ---*/ - if (rank == MASTER_NODE) cout << endl << "----------------------- Preprocessing computations ----------------------" << endl; + geometry->SetBoundVolume(); + if (config->GetReorientElements()) { + if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config); + geometry->Check_BoundElem_Orientation(config); + } - /*--- Compute elements surrounding points, points surrounding points ---*/ + /*--- Create the edge structure ---*/ - if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); + if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); + geometry->SetVertex(config); - /*--- Check the orientation before computing geometrical quantities ---*/ + if (config->GetDesign_Variable(0) != NO_DEFORMATION) { - geometry_container[iZone]->SetBoundVolume(); - if (config_container[iZone]->GetReorientElements()) { - if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config_container[iZone]); - geometry_container[iZone]->Check_BoundElem_Orientation(config_container[iZone]); - } + /*--- Create the dual control volume structures ---*/ - /*--- Create the edge structure ---*/ + if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; + geometry->SetControlVolume(config, ALLOCATE); + geometry->SetBoundControlVolume(config, ALLOCATE); + } - if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); - geometry_container[iZone]->SetVertex(config_container[iZone]); + /*--- Create the point-to-point MPI communication structures. ---*/ - if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { + geometry->PreprocessP2PComms(geometry, config); - /*--- Create the dual control volume structures ---*/ +} - if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; - geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); - geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); +void CDeformationDriver::Output_Preprocessing(CConfig *config, CGeometry *geometry, COutput *&output) { - } - /*--- Create the point-to-point MPI communication structures. ---*/ + /*--- Allocate the mesh output ---*/ - geometry_container[iZone]->PreprocessP2PComms(geometry_container[iZone], config_container[iZone]); + output = new CMeshOutput(config, geometry->GetnDim()); - /*--- Allocate the mesh output ---*/ + /*--- Preprocess the volume output ---*/ - output[iZone] = new CMeshOutput(config_container[iZone], geometry_container[iZone]->GetnDim()); + output->PreprocessVolumeOutput(config); - /*--- Preprocess the volume output ---*/ + /*--- Preprocess history --- */ - output[iZone]->PreprocessVolumeOutput(config_container[iZone]); + output->PreprocessHistoryOutput(config, false); +} - /*--- Preprocess history --- */ +void CDeformationDriver::Run() { - output[iZone]->PreprocessHistoryOutput(config_container[iZone], false); - } + /* --- Start measuring computation time ---*/ + + StartTime = SU2_MPI::Wtime(); /*--- Surface grid deformation using design variables ---*/ @@ -333,8 +349,8 @@ void CDeformationDriver::RunSolver() { } /*--- Set deformation magnitude as percentage of initial deformation ---*/ - for (auto iDV = 0u; iDV < config->GetnDV(); iDV++) { - for (auto iDV_Value = 0u; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++) { + for (auto iDV = 0u; iDV < driver_config->GetnDV(); iDV++) { + for (auto iDV_Value = 0u; iDV_Value < driver_config->GetnDV_Value(iDV); iDV_Value++) { config_container[iZone]->SetDV_Value(iDV, iDV_Value, InitialDeformation[iDV][iDV_Value]*DeformationFactor); } } @@ -381,7 +397,7 @@ void CDeformationDriver::RunSolver() { /*--- Compute Mesh Quality if requested. Necessary geometry preprocessing re-done beforehand. ---*/ - if (config_container[iZone]->GetWrt_MeshQuality() && !config->GetStructuralProblem()) { + if (config_container[iZone]->GetWrt_MeshQuality() && !driver_config->GetStructuralProblem()) { if (rank == MASTER_NODE) cout << "Recompute geometry properties necessary to evaluate mesh quality statistics.\n"; @@ -398,19 +414,19 @@ void CDeformationDriver::RunSolver() { /*--- Load the data --- */ - output[iZone]->Load_Data(geometry_container[iZone], config_container[iZone], nullptr); + output_container[iZone]->Load_Data(geometry_container[iZone], config_container[iZone], nullptr); - output[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], MESH, config->GetMesh_Out_FileName()); + output_container[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], MESH, driver_config->GetMesh_Out_FileName()); /*--- Set the file names for the visualization files ---*/ - output[iZone]->SetVolume_Filename("volume_deformed"); - output[iZone]->SetSurface_Filename("surface_deformed"); + output_container[iZone]->SetVolume_Filename("volume_deformed"); + output_container[iZone]->SetSurface_Filename("surface_deformed"); for (unsigned short iFile = 0; iFile < config_container[iZone]->GetnVolumeOutputFiles(); iFile++){ auto FileFormat = config_container[iZone]->GetVolumeOutputFiles(); if (FileFormat[iFile] != RESTART_ASCII && FileFormat[iFile] != RESTART_BINARY) - output[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], FileFormat[iFile]); + output_container[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], FileFormat[iFile]); } } @@ -427,12 +443,15 @@ void CDeformationDriver::RunSolver() { surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); } +} - delete config; - config = nullptr; +void CDeformationDriver::Postprocessing() { if (rank == MASTER_NODE) cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; + delete driver_config; + driver_config = nullptr; + if (geometry_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { if (geometry_container[iZone] != nullptr) { @@ -471,13 +490,13 @@ void CDeformationDriver::RunSolver() { } delete [] config_container; } - if (output != nullptr) { + if (output_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (output[iZone] != nullptr) { - delete output[iZone]; + if (output_container[iZone] != nullptr) { + delete output_container[iZone]; } } - delete [] output; + delete [] output_container; } if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; @@ -488,11 +507,9 @@ void CDeformationDriver::RunSolver() { StopTime = SU2_MPI::Wtime(); - /*--- Compute/print the total time for performance benchmarking. ---*/ - - UsedTime = StopTime-StartTime; + UsedTimeCompute = StopTime-StartTime; if (rank == MASTER_NODE) { - cout << "\nCompleted in " << fixed << UsedTime << " seconds on "<< size; + cout << "\nCompleted in " << fixed << UsedTimeCompute << " seconds on "<< size; if (size == 1) cout << " core." << endl; else cout << " cores." << endl; } From b9838977be491aa8b529b69b6d7839f5db980a83 Mon Sep 17 00:00:00 2001 From: aa-g Date: Wed, 26 May 2021 01:17:28 +0200 Subject: [PATCH 004/598] Minor fixes in CDeformationDriver --- .../include/drivers/CDeformationDriver.hpp | 11 ++---- SU2_DEF/src/drivers/CDeformationDriver.cpp | 38 ++++++++++--------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index b76a2919976..905cdf106c6 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -1,7 +1,6 @@ /*! * \file CDeformationDriver.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. + * \brief Headers of the main subroutines for driving the mesh deformation. * \author T. Economon, H. Kline, R. Sanchez * \version 7.1.1 "Blackbird" * @@ -37,8 +36,8 @@ /*! * \class CDeformationDriver - * \brief Class for driving single-zone solvers. - * \author R. Sanchez + * \brief Class for driving mesh deformation solvers. + * \author A. Gastaldi, H. Patel * \version 7.1.1 "Blackbird" */ class CDeformationDriver { @@ -58,7 +57,6 @@ class CDeformationDriver { CSurfaceMovement **surface_movement; /*!< \brief Surface movement classes of the problem. */ CVolumetricMovement **grid_movement; /*!< \brief Volume grid movement classes of the problem. */ COutput **output_container; /*!< \brief Pointer to the COutput class. */ - /*!< \brief FFD FFDBoxes of the problem. */ public: /*! @@ -66,8 +64,7 @@ class CDeformationDriver { * \param[in] confFile - Configuration file name. * \param[in] MPICommunicator - MPI communicator for SU2. */ - CDeformationDriver(char* confFile, - SU2_Comm MPICommunicator); + CDeformationDriver(char* confFile, SU2_Comm MPICommunicator); /*! * \brief Destructor of the class. diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 9ceb6b65fc5..eb4524c6376 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -1,7 +1,7 @@ /*! - * \file SU2_DEF.cpp - * \brief Main file of Mesh Deformation Code (SU2_DEF). - * \author F. Palacios, T. Economon + * \file CDeformationDriver.hpp + * \brief Main subroutines for driving the mesh deformation. + * \author T. Economon, H. Kline, R. Sanchez * \version 7.1.1 "Blackbird" * * SU2 Project Website: https://su2code.github.io @@ -27,8 +27,10 @@ #include "../../include/drivers/CDeformationDriver.hpp" + #include "../../../Common/include/geometry/CPhysicalGeometry.hpp" #include "../../../SU2_CFD/include/output/CMeshOutput.hpp" + using namespace std; CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) { @@ -49,9 +51,10 @@ CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) strcpy(config_file_name, confFile); /*--- Initialize the configuration of the driver ---*/ - driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF, false); + driver_config = nullptr; + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); - nZone = driver_config->GetnZone(); + nZone = driver_config->GetnZone(); /*--- Initialize containers --- */ @@ -430,7 +433,6 @@ void CDeformationDriver::Run() { } } - if ((config_container[ZONE_0]->GetDesign_Variable(0) != NO_DEFORMATION) && (config_container[ZONE_0]->GetDesign_Variable(0) != SCALE_GRID) && (config_container[ZONE_0]->GetDesign_Variable(0) != TRANSLATE_GRID) && @@ -443,6 +445,17 @@ void CDeformationDriver::Run() { surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); } + + /*--- Synchronization point after a single solver iteration. Compute the + wall clock time required. ---*/ + + StopTime = SU2_MPI::Wtime(); + + UsedTimeCompute = StopTime-StartTime; + if (rank == MASTER_NODE) { + cout << "\nCompleted in " << fixed << UsedTimeCompute << " seconds on "<< size; + if (size == 1) cout << " core." << endl; else cout << " cores." << endl; + } } void CDeformationDriver::Postprocessing() { @@ -502,19 +515,8 @@ void CDeformationDriver::Postprocessing() { if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; - /*--- Synchronization point after a single solver iteration. Compute the - wall clock time required. ---*/ - - StopTime = SU2_MPI::Wtime(); - - UsedTimeCompute = StopTime-StartTime; - if (rank == MASTER_NODE) { - cout << "\nCompleted in " << fixed << UsedTimeCompute << " seconds on "<< size; - if (size == 1) cout << " core." << endl; else cout << " cores." << endl; - } - /*--- Exit the solver cleanly ---*/ if (rank == MASTER_NODE) cout << endl << "------------------------- Exit Success (SU2_DEF) ------------------------" << endl << endl; - } +} From 6facf5b1fe5b49b9f97430ee1f46f3ed978d4cd4 Mon Sep 17 00:00:00 2001 From: aa-g Date: Tue, 1 Jun 2021 21:36:01 +0200 Subject: [PATCH 005/598] Add CDiscAdjDeformationDriver --- .../include/drivers/CDeformationDriver.hpp | 4 +- .../drivers/CDiscAdjDeformationDriver.hpp | 155 +++ SU2_DEF/src/drivers/CDeformationDriver.cpp | 61 +- .../src/drivers/CDiscAdjDeformationDriver.cpp | 945 ++++++++++++++++++ SU2_DEF/src/meson.build | 44 +- SU2_DOT/src/meson.build | 9 +- SU2_PY/pySU2/meson.build | 10 +- SU2_PY/pySU2/pySU2ad.i | 2 + 8 files changed, 1192 insertions(+), 38 deletions(-) create mode 100644 SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp create mode 100644 SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index 905cdf106c6..8a424ff32fd 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -95,11 +95,11 @@ class CDeformationDriver { /*! * \brief Construction of the edge-based data structure. */ - void Geometrical_Preprocessing(CConfig *config, CGeometry *&geometry); + void Geometrical_Preprocessing(); /*! * \brief Preprocess the output container. */ - void Output_Preprocessing(CConfig *config, CGeometry *geometry, COutput *&output); + void Output_Preprocessing(); }; diff --git a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp new file mode 100644 index 00000000000..f3635ab694b --- /dev/null +++ b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp @@ -0,0 +1,155 @@ +/*! +* \file CDiscAdjDeformationDriver.cpp +* \brief Main subroutines for driving the projection of sensitivities. + * \author T. Economon, H. Kline, R. Sanchez + * \version 7.1.1 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#define ENABLE_MAPS +#include "../../../Common/include/CConfig.hpp" +#undef ENABLE_MAPS + +#include "../../../Common/include/parallelization/mpi_structure.hpp" + +#include "../../../Common/include/geometry/CGeometry.hpp" +#include "../../../Common/include/fem/fem_geometry_structure.hpp" +#include "../../../Common/include/grid_movement/CSurfaceMovement.hpp" +#include "../../../Common/include/grid_movement/CVolumetricMovement.hpp" +#include "../../../SU2_CFD/include/output/COutput.hpp" +#include "../../../SU2_CFD/include/output/CBaselineOutput.hpp" +#include "../../../SU2_CFD/include/solvers/CBaselineSolver.hpp" + +/*! + * \class CDiscAdjDeformationDriver + * \brief Class for driving sensitivity DiscAdjDeformations. + * \author A. Gastaldi, H. Patel + * \version 7.1.1 "Blackbird" + */ +class CDiscAdjDeformationDriver { +protected: + char config_file_name[MAX_STRING_SIZE]; + int rank, + size; + unsigned short iZone, nZone = SINGLE_ZONE; + unsigned short iInst; + unsigned short* nInst; + su2double StartTime, /*!< \brief Start point of the timer for performance benchmarking.*/ + StopTime, /*!< \brief Stop point of the timer for performance benchmarking.*/ + UsedTimePreproc, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking preprocessing phase.*/ + UsedTimeCompute, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking compute phase.*/ + UsedTime; /*!< \brief Elapsed time between Start and Stop point of the timer.*/ + su2double** Gradient; + ofstream Gradient_file; + CConfig *driver_config; /*!< \brief Definition of the driver configuration. */ + CConfig **config_container; /*!< \brief Definition of the particular problem. */ + CGeometry ***geometry_container; /*!< \brief Geometrical definition of the problem. */ + CSurfaceMovement **surface_movement; + CVolumetricMovement **grid_movement; + COutput **output_container; /*!< \brief Pointer to the COutput class. */ + +public: + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CDiscAdjDeformationDriver(char* confFile, SU2_Comm MPICommunicator); + + /*! + * \brief Destructor of the class. + */ + ~CDiscAdjDeformationDriver(void); + + /*! + * \brief [Overload] Launch the computation for single-zone problems. + */ + void Run(); + + /*! + * \brief Deallocation routine + */ + void Postprocessing(); + +protected: + /*! + * \brief Init_Containers + */ + void SetContainers_Null(); + + /*! + * \brief Read in the config and mesh files. + */ + void Input_Preprocessing(); + + /*! + * \brief Construction of the edge-based data structure. + */ + void Geometrical_Preprocessing(); + + /*! + * \brief Preprocess the output container. + */ + void Output_Preprocessing(); + + /*! + * \brief DiscAdjDeformation of the surface sensitivity using finite differences (FD). + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement class of the problem. + * \param[in] Gradient_file - Output file to store the gradient data. + */ + + void SetDiscAdjDeformation_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double **Gradient); + + /*! + * \brief DiscAdjDeformation of the surface sensitivity using algorithmic differentiation (AD). + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement class of the problem. + * \param[in] Gradient_file - Output file to store the gradient data. + */ + + void SetDiscAdjDeformation_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double **Gradient); + + /*! + * \brief Prints the gradient information to a file. + * \param[in] Gradient - The gradient data. + * \param[in] config - Definition of the particular problem. + * \param[in] Gradient_file - Output file to store the gradient data. + */ + + void OutputGradient(su2double** Gradient, CConfig* config, ofstream& Gradient_file); + + /*! + * \brief Write the sensitivity (including mesh sensitivity) computed with the discrete adjoint method + * on the surface and in the volume to a file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] val_nZone - Number of Zones. + */ + + void SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone); + +}; diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index eb4524c6376..b12d24154a9 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -68,17 +68,13 @@ CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) StartTime = SU2_MPI::Wtime(); - for (iZone = 0; iZone < nZone; iZone++) { + /*--- Preprocessing of the geometry for all zones. ---*/ - /*--- Preprocessing of the geometry for all zones. ---*/ + Geometrical_Preprocessing(); - Geometrical_Preprocessing(config_container[iZone], geometry_container[iZone]); + /*--- Preprocessing of the output for all zones. ---*/ - /*--- Preprocessing of the output for all zones. ---*/ - - Output_Preprocessing(config_container[iZone], geometry_container[iZone], output_container[iZone]); - - } + Output_Preprocessing(); /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ @@ -150,7 +146,9 @@ void CDeformationDriver::Input_Preprocessing() { } } -void CDeformationDriver::Geometrical_Preprocessing(CConfig *config, CGeometry *&geometry) { +void CDeformationDriver::Geometrical_Preprocessing() { + + for (iZone = 0; iZone < nZone; iZone++) { /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ @@ -158,15 +156,15 @@ void CDeformationDriver::Geometrical_Preprocessing(CConfig *config, CGeometry *& /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ - geometry_aux = new CPhysicalGeometry(config, iZone, nZone); + geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - geometry_aux->SetColorGrid_Parallel(config); + geometry_aux->SetColorGrid_Parallel(config_container[iZone]); /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - geometry = new CPhysicalGeometry(geometry_aux, config); + geometry_container[iZone] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); /*--- Deallocate the memory of geometry_aux ---*/ @@ -174,11 +172,11 @@ void CDeformationDriver::Geometrical_Preprocessing(CConfig *config, CGeometry *& /*--- Add the Send/Receive boundaries ---*/ - geometry->SetSendReceive(config); + geometry_container[iZone]->SetSendReceive(config_container[iZone]); /*--- Add the Send/Receive boundaries ---*/ - geometry->SetBoundaries(config); + geometry_container[iZone]->SetBoundaries(config_container[iZone]); /*--- Computational grid preprocesing ---*/ @@ -187,51 +185,56 @@ void CDeformationDriver::Geometrical_Preprocessing(CConfig *config, CGeometry *& /*--- Compute elements surrounding points, points surrounding points ---*/ if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); + geometry_container[iZone]->SetPoint_Connectivity(); /*--- Check the orientation before computing geometrical quantities ---*/ - geometry->SetBoundVolume(); - if (config->GetReorientElements()) { + geometry_container[iZone]->SetBoundVolume(); + if (config_container[iZone]->GetReorientElements()) { if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config); - geometry->Check_BoundElem_Orientation(config); + geometry_container[iZone]->Check_IntElem_Orientation(config_container[iZone]); + geometry_container[iZone]->Check_BoundElem_Orientation(config_container[iZone]); } /*--- Create the edge structure ---*/ if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); - geometry->SetVertex(config); + geometry_container[iZone]->SetEdges(); + geometry_container[iZone]->SetVertex(config_container[iZone]); - if (config->GetDesign_Variable(0) != NO_DEFORMATION) { + if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { /*--- Create the dual control volume structures ---*/ if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; - geometry->SetControlVolume(config, ALLOCATE); - geometry->SetBoundControlVolume(config, ALLOCATE); + geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); + geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); } /*--- Create the point-to-point MPI communication structures. ---*/ - geometry->PreprocessP2PComms(geometry, config); + geometry_container[iZone]->PreprocessP2PComms(geometry_container[iZone], config_container[iZone]); + } } -void CDeformationDriver::Output_Preprocessing(CConfig *config, CGeometry *geometry, COutput *&output) { +void CDeformationDriver::Output_Preprocessing() { + + for (iZone = 0; iZone < nZone; iZone++) { /*--- Allocate the mesh output ---*/ - output = new CMeshOutput(config, geometry->GetnDim()); + output_container[iZone] = new CMeshOutput(config_container[iZone], geometry_container[iZone]->GetnDim()); /*--- Preprocess the volume output ---*/ - output->PreprocessVolumeOutput(config); + output_container[iZone]->PreprocessVolumeOutput(config_container[iZone]); /*--- Preprocess history --- */ - output->PreprocessHistoryOutput(config, false); + output_container[iZone]->PreprocessHistoryOutput(config_container[iZone], false); + + } } void CDeformationDriver::Run() { diff --git a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp new file mode 100644 index 00000000000..923901fee8b --- /dev/null +++ b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp @@ -0,0 +1,945 @@ +/*! + * \file CDiscAdjDeformationDriver.cpp + * \brief Main subroutines for driving the projection of sensitivities. + * \author T. Economon, H. Kline, R. Sanchez + * \version 7.1.1 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../include/drivers/CDiscAdjDeformationDriver.hpp" + +#include "../../../Common/include/geometry/CPhysicalGeometry.hpp" + +using namespace std; + +CDiscAdjDeformationDriver::CDiscAdjDeformationDriver(char* confFile, SU2_Comm MPICommunicator) { + + /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ + #ifdef HAVE_MPI + #if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE) + SU2_MPI::Init_AMPI(); + #endif + #endif + + SU2_MPI::SetComm(MPICommunicator); + + rank = SU2_MPI::GetRank(); + size = SU2_MPI::GetSize(); + + /*--- Copy the config filename ---*/ + strcpy(config_file_name, confFile); + + /*--- Read the name and format of the input mesh file to get from the mesh + file the number of zones and dimensions from the numerical grid (required + for variables allocation) ---*/ + + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DOT); + + nZone = driver_config->GetnZone(); + + /*--- Initialize containers --- */ + + SetContainers_Null(); + + /*--- Preprocessing of the config files. ---*/ + + Input_Preprocessing(); + + /*--- Set up a timer for performance benchmarking ---*/ + + StartTime = SU2_MPI::Wtime(); + + /*--- Preprocessing of the geometry for all zones. ---*/ + + Geometrical_Preprocessing(); + + /*--- Preprocessing of the outputs for all zones. ---*/ + + Output_Preprocessing(); + + /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ + + StopTime = SU2_MPI::Wtime(); + + /*--- Compute/print the total time for performance benchmarking. ---*/ + + UsedTime = StopTime-StartTime; + UsedTimePreproc = UsedTime; + UsedTimeCompute = 0.0; + +} + +CDiscAdjDeformationDriver::~CDiscAdjDeformationDriver(void) { + +} + +void CDiscAdjDeformationDriver::SetContainers_Null() { + + /*--- Definition of the containers per zones ---*/ + + config_container = new CConfig*[nZone] (); + geometry_container = new CGeometry**[nZone] (); + surface_movement = new CSurfaceMovement*[nZone] (); + grid_movement = new CVolumetricMovement*[nZone] (); + + nInst = new unsigned short[nZone]; + for (iZone = 0; iZone < nZone; iZone++) { + nInst[iZone] = 1; + } +} + +void CDiscAdjDeformationDriver::Input_Preprocessing() { + + // TODO Check that config is for Discrete Adjoint ! + + /*--- Initialize a char to store the zone filename ---*/ + char zone_file_name[MAX_STRING_SIZE]; + + /*--- Loop over all zones to initialize the various classes. In most + cases, nZone is equal to one. This represents the solution of a partial + differential equation on a single block, unstructured mesh. ---*/ + + for (iZone = 0; iZone < nZone; iZone++) { + + /*--- Definition of the configuration option class for all zones. In this + constructor, the input configuration file is parsed and all options are + read and stored. ---*/ + + if (driver_config->GetnConfigFiles() > 0){ + strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); + config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DOT, iZone, nZone, true); + } else { + config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DOT, iZone, nZone, true); + } + + config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); + } + + /*--- Set the multizone part of the problem. ---*/ + if (driver_config->GetMultizone_Problem()){ + for (iZone = 0; iZone < nZone; iZone++) { + /*--- Set the interface markers for multizone ---*/ + config_container[iZone]->SetMultizone(driver_config, config_container); + } + } +} + +void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { + + /*--- Loop over all zones to initialize the various classes. In most + cases, nZone is equal to one. This represents the solution of a partial + differential equation on a single block, unstructured mesh. ---*/ + + for (iZone = 0; iZone < nZone; iZone++) { + + /*--- Determine whether or not the FEM solver is used, which decides the + type of geometry classes that are instantiated. ---*/ + const bool fem_solver = config_container[iZone]->GetFEMSolver(); + + /*--- Read the number of instances for each zone ---*/ + + nInst[iZone] = config_container[iZone]->GetnTimeInstances(); + + geometry_container[iZone] = new CGeometry*[nInst[iZone]]; + + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + + /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ + + CGeometry *geometry_aux = nullptr; + + /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ + + geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); + + /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ + + if ( fem_solver ) geometry_aux->SetColorFEMGrid_Parallel(config_container[iZone]); + else geometry_aux->SetColorGrid_Parallel(config_container[iZone]); + + /*--- Build the grid data structures using the ParMETIS coloring. ---*/ + + if( fem_solver ) { + switch( config_container[iZone]->GetKind_FEM_Flow() ) { + case DG: { + geometry_container[iZone][iInst] = new CMeshFEM_DG(geometry_aux, config_container[iZone]); + break; + } + } + } + else { + geometry_container[iZone][iInst] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); + } + + /*--- Deallocate the memory of geometry_aux ---*/ + + delete geometry_aux; + + /*--- Add the Send/Receive boundaries ---*/ + + geometry_container[iZone][iInst]->SetSendReceive(config_container[iZone]); + + /*--- Add the Send/Receive boundaries ---*/ + + geometry_container[iZone][iInst]->SetBoundaries(config_container[iZone]); + + /*--- Create the vertex structure (required for MPI) ---*/ + + if (rank == MASTER_NODE) cout << "Identify vertices." << endl; + geometry_container[iZone][iInst]->SetVertex(config_container[iZone]); + + /*--- Store the global to local mapping after preprocessing. ---*/ + + if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; + geometry_container[iZone][iInst]->SetGlobal_to_Local_Point(); + + /* Test for a fem solver, because some more work must be done. */ + + if (fem_solver) { + + /*--- Carry out a dynamic cast to CMeshFEM_DG, such that it is not needed to + define all virtual functions in the base class CGeometry. ---*/ + CMeshFEM_DG *DGMesh = dynamic_cast(geometry_container[iZone][iInst]); + + /*--- Determine the standard elements for the volume elements. ---*/ + if (rank == MASTER_NODE) cout << "Creating standard volume elements." << endl; + DGMesh->CreateStandardVolumeElements(config_container[iZone]); + + /*--- Create the face information needed to compute the contour integral + for the elements in the Discontinuous Galerkin formulation. ---*/ + if (rank == MASTER_NODE) cout << "Creating face information." << endl; + DGMesh->CreateFaces(config_container[iZone]); + } + } + + if (rank == MASTER_NODE) + cout << "\n----------------------- Preprocessing computations ----------------------" << endl; + + /*--- Compute elements surrounding points, points surrounding points ---*/ + + if (rank == MASTER_NODE) cout << "Setting local point connectivity." << endl; + geometry_container[iZone][INST_0]->SetPoint_Connectivity(); + + /*--- Check the orientation before computing geometrical quantities ---*/ + + geometry_container[iZone][INST_0]->SetBoundVolume(); + if (config_container[iZone]->GetReorientElements()) { + if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the elements." << endl; + geometry_container[iZone][INST_0]->Check_IntElem_Orientation(config_container[iZone]); + geometry_container[iZone][INST_0]->Check_BoundElem_Orientation(config_container[iZone]); + } + + /*--- Create the edge structure ---*/ + + if (rank == MASTER_NODE) cout << "Identify edges and vertices." << endl; + geometry_container[iZone][INST_0]->SetEdges(); geometry_container[iZone][INST_0]->SetVertex(config_container[iZone]); + + /*--- Create the dual control volume structures ---*/ + + if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; + geometry_container[iZone][INST_0]->SetBoundControlVolume(config_container[ZONE_0], ALLOCATE); + + /*--- Store the global to local mapping after preprocessing. ---*/ + + if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; + geometry_container[iZone][INST_0]->SetGlobal_to_Local_Point(); + + /*--- Create the point-to-point MPI communication structures. ---*/ + + geometry_container[iZone][INST_0]->PreprocessP2PComms(geometry_container[iZone][INST_0], config_container[iZone]); + + } +} + +void CDiscAdjDeformationDriver::Output_Preprocessing() { + +} + +void CDiscAdjDeformationDriver::Run() { + + for (iZone = 0; iZone < nZone; iZone++) { + if (rank == MASTER_NODE) cout << "Reading volume sensitivities at each node from file." << endl; + grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone][INST_0], config_container[iZone]); + + /*--- Read in sensitivities from file. ---*/ + if (config_container[ZONE_0]->GetSensitivity_Format() == UNORDERED_ASCII) + geometry_container[iZone][INST_0]->ReadUnorderedSensitivity(config_container[iZone]); + else + geometry_container[iZone][INST_0]->SetSensitivity(config_container[iZone]); + + if (rank == MASTER_NODE) cout << "\n---------------------- Mesh sensitivity computation ---------------------" << endl; + grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone][INST_0], config_container[iZone], false, true); + } + + if (rank == MASTER_NODE) cout << "\n------------------------ Mesh sensitivity Output ------------------------" << endl; + SetSensitivity_Files(geometry_container, config_container, nZone); + + /*--- Initialize structure to store the gradient ---*/ + Gradient = new su2double*[config_container[ZONE_0]->GetnDV()]; + + for (auto iDV = 0u; iDV < config_container[ZONE_0]->GetnDV(); iDV++) { + /*--- Initialize to zero ---*/ + Gradient[iDV] = new su2double[config_container[ZONE_0]->GetnDV_Value(iDV)](); + } + + Gradient_file.precision(driver_config->OptionIsSet("OUTPUT_PRECISION") ? driver_config->GetOutput_Precision() : 6); + + /*--- For multizone computations the gradient contributions are summed up and written into one file. ---*/ + for (iZone = 0; iZone < nZone; iZone++){ + if ((config_container[iZone]->GetDesign_Variable(0) != NONE) && + (config_container[iZone]->GetDesign_Variable(0) != SURFACE_FILE)) { + + if (rank == MASTER_NODE) + cout << "\n---------- Start gradient evaluation using sensitivity information ----------" << endl; + + /*--- Definition of the Class for surface deformation ---*/ + + surface_movement[iZone] = new CSurfaceMovement(); + + /*--- Copy coordinates to the surface structure ---*/ + + surface_movement[iZone]->CopyBoundary(geometry_container[iZone][INST_0], config_container[iZone]); + + /*--- If AD mode is enabled we can use it to compute the projection, + * otherwise we use finite differences. ---*/ + + if (config_container[iZone]->GetAD_Mode()) + SetDiscAdjDeformation_AD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); + else + SetDiscAdjDeformation_FD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); + + } + } // for iZone + + /*--- Write the gradient to a file ---*/ + + if (rank == MASTER_NODE) + Gradient_file.open(config_container[ZONE_0]->GetObjFunc_Grad_FileName().c_str(), ios::out); + + /*--- Print gradients to screen and writes to file ---*/ + + OutputGradient(Gradient, config_container[ZONE_0], Gradient_file); + +} + +void CDiscAdjDeformationDriver::Postprocessing() { + + for (auto iDV = 0u; iDV < config_container[ZONE_0]->GetnDV(); iDV++){ + delete [] Gradient[iDV]; + } + delete [] Gradient; + + delete driver_config; + driver_config = nullptr; + + if (rank == MASTER_NODE) + cout << "\n------------------------- Solver Postprocessing -------------------------" << endl; + + if (geometry_container != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (geometry_container[iZone] != nullptr) { + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + if (geometry_container[iZone][iInst] != nullptr) { + delete geometry_container[iZone][iInst]; + } + } + delete geometry_container[iZone]; + } + } + delete [] geometry_container; + } + if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; + + if (surface_movement != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (surface_movement[iZone] != nullptr) { + delete surface_movement[iZone]; + } + } + delete [] surface_movement; + } + if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; + + if (grid_movement != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (grid_movement[iZone] != nullptr) { + delete grid_movement[iZone]; + } + } + delete [] grid_movement; + } + if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; + + if (config_container != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (config_container[iZone] != nullptr) { + delete config_container[iZone]; + } + } + delete [] config_container; + } + if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; + +} + +void CDiscAdjDeformationDriver::SetDiscAdjDeformation_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ + + unsigned short iDV, nDV, iFFDBox, nDV_Value, iMarker, iDim; + unsigned long iVertex, iPoint; + su2double delta_eps, my_Gradient, localGradient, *Normal, dS, *VarCoord, Sensitivity, + dalpha[3], deps[3], dalpha_deps; + bool *UpdatePoint, MoveSurface, Local_MoveSurface; + CFreeFormDefBox **FFDBox; + + int rank = SU2_MPI::GetRank(); + + nDV = config->GetnDV(); + + /*--- Boolean controlling points to be updated ---*/ + + UpdatePoint = new bool[geometry->GetnPoint()]; + + /*--- Definition of the FFD deformation class ---*/ + + unsigned short nFFDBox = MAX_NUMBER_FFD; + FFDBox = new CFreeFormDefBox*[nFFDBox]; + for (iFFDBox = 0; iFFDBox < MAX_NUMBER_FFD; iFFDBox++) FFDBox[iFFDBox] = nullptr; + + for (iDV = 0; iDV < nDV; iDV++){ + nDV_Value = config->GetnDV_Value(iDV); + if (nDV_Value != 1){ + SU2_MPI::Error("The DiscAdjDeformation using finite differences currently only supports a fixed direction of movement for FFD points.", CURRENT_FUNCTION); + } + } + + /*--- Continuous adjoint gradient computation ---*/ + + if (rank == MASTER_NODE) + cout << "Evaluate functional gradient using Finite Differences." << endl; + + for (iDV = 0; iDV < nDV; iDV++) { + + MoveSurface = true; + Local_MoveSurface = true; + + /*--- Free Form deformation based ---*/ + + if ((config->GetDesign_Variable(iDV) == FFD_CONTROL_POINT_2D) || + (config->GetDesign_Variable(iDV) == FFD_CAMBER_2D) || + (config->GetDesign_Variable(iDV) == FFD_THICKNESS_2D) || + (config->GetDesign_Variable(iDV) == FFD_TWIST_2D) || + (config->GetDesign_Variable(iDV) == FFD_CONTROL_POINT) || + (config->GetDesign_Variable(iDV) == FFD_NACELLE) || + (config->GetDesign_Variable(iDV) == FFD_GULL) || + (config->GetDesign_Variable(iDV) == FFD_TWIST) || + (config->GetDesign_Variable(iDV) == FFD_ROTATION) || + (config->GetDesign_Variable(iDV) == FFD_CAMBER) || + (config->GetDesign_Variable(iDV) == FFD_THICKNESS) || + (config->GetDesign_Variable(iDV) == FFD_ANGLE_OF_ATTACK)) { + + /*--- Read the FFD information in the first iteration ---*/ + + if (iDV == 0) { + + if (rank == MASTER_NODE) + cout << "Read the FFD information from mesh file." << endl; + + /*--- Read the FFD information from the grid file ---*/ + + surface_movement->ReadFFDInfo(geometry, config, FFDBox, config->GetMesh_FileName()); + + /*--- If the FFDBox was not defined in the input file ---*/ + if (!surface_movement->GetFFDBoxDefinition()) { + SU2_MPI::Error("The input grid doesn't have the entire FFD information!", CURRENT_FUNCTION); + } + + for (iFFDBox = 0; iFFDBox < surface_movement->GetnFFDBox(); iFFDBox++) { + + if (rank == MASTER_NODE) cout << "Checking FFD box dimension." << endl; + surface_movement->CheckFFDDimension(geometry, config, FFDBox[iFFDBox], iFFDBox); + + if (rank == MASTER_NODE) cout << "Check the FFD box intersections with the solid surfaces." << endl; + surface_movement->CheckFFDIntersections(geometry, config, FFDBox[iFFDBox], iFFDBox); + + } + + if (rank == MASTER_NODE) + cout <<"-------------------------------------------------------------------------" << endl; + + } + + if (rank == MASTER_NODE) { + cout << endl << "Design variable number "<< iDV <<"." << endl; + cout << "Performing 3D deformation of the surface." << endl; + } + + /*--- Apply the control point change ---*/ + + MoveSurface = false; + + for (iFFDBox = 0; iFFDBox < surface_movement->GetnFFDBox(); iFFDBox++) { + + /*--- Reset FFD box ---*/ + + switch (config->GetDesign_Variable(iDV) ) { + case FFD_CONTROL_POINT_2D : Local_MoveSurface = surface_movement->SetFFDCPChange_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_CAMBER_2D : Local_MoveSurface = surface_movement->SetFFDCamber_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_THICKNESS_2D : Local_MoveSurface = surface_movement->SetFFDThickness_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_TWIST_2D : Local_MoveSurface = surface_movement->SetFFDTwist_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_CONTROL_POINT : Local_MoveSurface = surface_movement->SetFFDCPChange(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_NACELLE : Local_MoveSurface = surface_movement->SetFFDNacelle(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_GULL : Local_MoveSurface = surface_movement->SetFFDGull(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_TWIST : Local_MoveSurface = surface_movement->SetFFDTwist(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_ROTATION : Local_MoveSurface = surface_movement->SetFFDRotation(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_CAMBER : Local_MoveSurface = surface_movement->SetFFDCamber(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_THICKNESS : Local_MoveSurface = surface_movement->SetFFDThickness(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_CONTROL_SURFACE : Local_MoveSurface = surface_movement->SetFFDControl_Surface(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_ANGLE_OF_ATTACK : Gradient[iDV][0] = config->GetAoA_Sens(); break; + } + + /*--- Recompute cartesian coordinates using the new control points position ---*/ + + if (Local_MoveSurface) { + MoveSurface = true; + surface_movement->SetCartesianCoord(geometry, config, FFDBox[iFFDBox], iFFDBox, true); + } + + } + + } + + /*--- Hicks Henne design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == HICKS_HENNE) { + surface_movement->SetHicksHenne(geometry, config, iDV, true); + } + + /*--- Surface bump design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == SURFACE_BUMP) { + surface_movement->SetSurface_Bump(geometry, config, iDV, true); + } + + /*--- Kulfan (CST) design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == CST) { + surface_movement->SetCST(geometry, config, iDV, true); + } + + /*--- Displacement design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == TRANSLATION) { + surface_movement->SetTranslation(geometry, config, iDV, true); + } + + /*--- Angle of Attack design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == ANGLE_OF_ATTACK) { + Gradient[iDV][0] = config->GetAoA_Sens(); + } + + /*--- Scale design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == SCALE) { + surface_movement->SetScale(geometry, config, iDV, true); + } + + /*--- Rotation design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == ROTATION) { + surface_movement->SetRotation(geometry, config, iDV, true); + } + + /*--- NACA_4Digits design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == NACA_4DIGITS) { + surface_movement->SetNACA_4Digits(geometry, config); + } + + /*--- Parabolic design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == PARABOLIC) { + surface_movement->SetParabolic(geometry, config); + } + + /*--- Design variable not implement ---*/ + + else { + if (rank == MASTER_NODE) + cout << "Design Variable not implement yet" << endl; + } + + /*--- Load the delta change in the design variable (finite difference step). ---*/ + + if ((config->GetDesign_Variable(iDV) != ANGLE_OF_ATTACK) && + (config->GetDesign_Variable(iDV) != FFD_ANGLE_OF_ATTACK)) { + + /*--- If the Angle of attack is not involved, reset the value of the gradient ---*/ + + my_Gradient = 0.0; Gradient[iDV][0] = 0.0; + + if (MoveSurface) { + + delta_eps = config->GetDV_Value(iDV); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + UpdatePoint[iPoint] = true; + + 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 ((iPoint < geometry->GetnPointDomain()) && UpdatePoint[iPoint]) { + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + Sensitivity = geometry->vertex[iMarker][iVertex]->GetAuxVar(); + + dS = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { + dS += Normal[iDim]*Normal[iDim]; + deps[iDim] = VarCoord[iDim] / delta_eps; + } + dS = sqrt(dS); + + dalpha_deps = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { + dalpha[iDim] = Normal[iDim] / dS; + dalpha_deps -= dalpha[iDim]*deps[iDim]; + } + + my_Gradient += Sensitivity*dalpha_deps; + UpdatePoint[iPoint] = false; + } + } + } + } + } + + SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + Gradient[iDV][0] += localGradient; + } + } + + /*--- Delete memory for parameterization. ---*/ + + if (FFDBox != nullptr) { + for (iFFDBox = 0; iFFDBox < MAX_NUMBER_FFD; iFFDBox++) { + if (FFDBox[iFFDBox] != nullptr) { + delete FFDBox[iFFDBox]; + } + } + delete [] FFDBox; + } + + delete [] UpdatePoint; + +} + + +void CDiscAdjDeformationDriver::SetDiscAdjDeformation_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ + + su2double DV_Value, *VarCoord, Sensitivity, my_Gradient, localGradient, *Normal, Area = 0.0; + unsigned short iDV_Value = 0, iMarker, nMarker, iDim, nDim, iDV, nDV, nDV_Value; + unsigned long iVertex, nVertex, iPoint; + + int rank = SU2_MPI::GetRank(); + + nMarker = config->GetnMarker_All(); + nDim = geometry->GetnDim(); + nDV = config->GetnDV(); + + VarCoord = nullptr; + + /*--- Discrete adjoint gradient computation ---*/ + + if (rank == MASTER_NODE) + cout << endl << "Evaluate functional gradient using Algorithmic Differentiation (ZONE " << config->GetiZone() << ")." << endl; + + /*--- Start recording of operations ---*/ + + AD::StartRecording(); + + /*--- Register design variables as input and set them to zero + * (since we want to have the derivative at alpha = 0, i.e. for the current design) ---*/ + + + + for (iDV = 0; iDV < nDV; iDV++){ + + nDV_Value = config->GetnDV_Value(iDV); + + for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ + + /*--- Initilization with su2double resets the index ---*/ + + DV_Value = 0.0; + + AD::RegisterInput(DV_Value); + + config->SetDV_Value(iDV, iDV_Value, DV_Value); + } + } + + /*--- Call the surface deformation routine ---*/ + + surface_movement->SetSurface_Deformation(geometry, config); + + /*--- Stop the recording --- */ + + AD::StopRecording(); + + /*--- Create a structure to identify points that have been already visited. + * We need that to make sure to set the sensitivity of surface points only once + * (Markers share points, so we would visit them more than once in the loop over the markers below) ---*/ + + bool* visited = new bool[geometry->GetnPoint()]; + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++){ + visited[iPoint] = false; + } + + /*--- Initialize the derivatives of the output of the surface deformation routine + * with the discrete adjoints from the CFD solution ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_DV(iMarker) == YES) { + nVertex = geometry->nVertex[iMarker]; + for (iVertex = 0; iVertex vertex[iMarker][iVertex]->GetNode(); + if (!visited[iPoint]){ + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + 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++){ + if (config->GetDiscrete_Adjoint()){ + Sensitivity = geometry->GetSensitivity(iPoint, iDim); + } else { + Sensitivity = -Normal[iDim]*geometry->vertex[iMarker][iVertex]->GetAuxVar()/Area; + } + SU2_TYPE::SetDerivative(VarCoord[iDim], SU2_TYPE::GetValue(Sensitivity)); + } + visited[iPoint] = true; + } + } + } + } + + delete [] visited; + + /*--- Compute derivatives and extract gradient ---*/ + + AD::ComputeAdjoint(); + + for (iDV = 0; iDV < nDV; iDV++){ + nDV_Value = config->GetnDV_Value(iDV); + + for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ + DV_Value = config->GetDV_Value(iDV, iDV_Value); + my_Gradient = SU2_TYPE::GetDerivative(DV_Value); + SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + + /*--- Angle of Attack design variable (this is different, + the value comes form the input file) ---*/ + + if ((config->GetDesign_Variable(iDV) == ANGLE_OF_ATTACK) || + (config->GetDesign_Variable(iDV) == FFD_ANGLE_OF_ATTACK)) { + Gradient[iDV][iDV_Value] = config->GetAoA_Sens(); + } + + Gradient[iDV][iDV_Value] += localGradient; + } + } + + AD::Reset(); + +} + +void CDiscAdjDeformationDriver::OutputGradient(su2double** Gradient, CConfig* config, ofstream& Gradient_file){ + + unsigned short nDV, iDV, iDV_Value, nDV_Value; + + int rank = SU2_MPI::GetRank(); + + nDV = config->GetnDV(); + + /*--- Loop through all design variables and their gradients ---*/ + + for (iDV = 0; iDV < nDV; iDV++){ + nDV_Value = config->GetnDV_Value(iDV); + if (rank == MASTER_NODE){ + + /*--- Print the kind of design variable on screen ---*/ + + cout << endl << "Design variable ("; + for (std::map::const_iterator it = Param_Map.begin(); it != Param_Map.end(); ++it ){ + if (it->second == config->GetDesign_Variable(iDV)){ + cout << it->first << ") number "<< iDV << "." << endl; + } + } + + /*--- Print the kind of objective function to screen ---*/ + + for (std::map::const_iterator it = Objective_Map.begin(); it != Objective_Map.end(); ++it ){ + if (it->second == config->GetKind_ObjFunc()){ + cout << it->first << " gradient : "; + if (iDV == 0) Gradient_file << it->first << " gradient " << endl; + } + } + + /*--- Print the gradient to file and screen ---*/ + + for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ + cout << Gradient[iDV][iDV_Value]; + if (iDV_Value != nDV_Value-1 ){ + cout << ", "; + } + Gradient_file << Gradient[iDV][iDV_Value] << endl; + } + cout << endl; + cout <<"-------------------------------------------------------------------------" << endl; + } + } +} + + +void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone) { + + unsigned short iMarker,iDim, nDim, nMarker, nVar; + unsigned long iVertex, iPoint, nPoint, nVertex; + su2double *Normal, Prod, Sens = 0.0, SensDim, Area; + + unsigned short iZone; + + CSolver *solver = nullptr; + COutput *output = nullptr; + + for (iZone = 0; iZone < val_nZone; iZone++) { + + nPoint = geometry[iZone][INST_0]->GetnPoint(); + nDim = geometry[iZone][INST_0]->GetnDim(); + nMarker = config[iZone]->GetnMarker_All(); + nVar = nDim + 1; + + /*--- We create a baseline solver to easily merge the sensitivity information ---*/ + + vector fieldnames; + fieldnames.push_back("\"Point\""); + fieldnames.push_back("\"x\""); + fieldnames.push_back("\"y\""); + if (nDim == 3) { + fieldnames.push_back("\"z\""); + } + fieldnames.push_back("\"Sensitivity_x\""); + fieldnames.push_back("\"Sensitivity_y\""); + if (nDim == 3) { + fieldnames.push_back("\"Sensitivity_z\""); + } + fieldnames.push_back("\"Surface_Sensitivity\""); + + solver = new CBaselineSolver(geometry[iZone][INST_0], config[iZone], nVar+nDim, fieldnames); + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) { + solver->GetNodes()->SetSolution(iPoint, iDim, geometry[iZone][INST_0]->nodes->GetCoord(iPoint, iDim)); + solver->GetNodes()->SetSolution(iPoint, iDim+nDim, geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim)); + } + } + + /*--- Compute the sensitivity in normal direction ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if(config[iZone]->GetSolid_Wall(iMarker) || (config[iZone]->GetMarker_All_DV(iMarker) == YES )) { + + nVertex = geometry[iZone][INST_0]->GetnVertex(iMarker); + + for (iVertex = 0; iVertex < nVertex; iVertex++) { + iPoint = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNormal(); + Prod = 0.0; + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + + /*--- Retrieve the gradient calculated with discrete adjoint method ---*/ + + SensDim = geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim); + + /*--- Calculate scalar product for DiscAdjDeformation onto the normal vector ---*/ + + Prod += Normal[iDim]*SensDim; + + Area += Normal[iDim]*Normal[iDim]; + } + + Area = sqrt(Area); + + /*--- DiscAdjDeformation of the gradient onto the normal vector of the surface ---*/ + + Sens = Prod/Area; + + solver->GetNodes()->SetSolution(iPoint, 2*nDim, Sens); + + } + } + } + + output = new CBaselineOutput(config[iZone], nDim, solver); + output->PreprocessVolumeOutput(config[iZone]); + output->PreprocessHistoryOutput(config[iZone], false); + + /*--- Load the data --- */ + + output->Load_Data(geometry[iZone][INST_0], config[iZone], &solver); + + /*--- Set the surface filename ---*/ + + output->SetSurface_Filename(config[iZone]->GetSurfSens_FileName()); + + /*--- Set the volume filename ---*/ + + output->SetVolume_Filename(config[iZone]->GetVolSens_FileName()); + + /*--- Write to file ---*/ + + for (unsigned short iFile = 0; iFile < config[iZone]->GetnVolumeOutputFiles(); iFile++){ + auto FileFormat = config[iZone]->GetVolumeOutputFiles(); + if (FileFormat[iFile] != RESTART_ASCII && + FileFormat[iFile] != RESTART_BINARY && + FileFormat[iFile] != CSV) + output->WriteToFile(config[iZone], geometry[iZone][INST_0], FileFormat[iFile]); + } + + /*--- Free memory ---*/ + + delete output; + delete solver; + + } + +} diff --git a/SU2_DEF/src/meson.build b/SU2_DEF/src/meson.build index a6681c5c88d..0f19687b7bc 100644 --- a/SU2_DEF/src/meson.build +++ b/SU2_DEF/src/meson.build @@ -1,7 +1,8 @@ su2_def_include = include_directories('./') su2_def_src = files([ 'SU2_DEF.cpp', - 'drivers/CDeformationDriver.cpp' + 'drivers/CDeformationDriver.cpp', + 'drivers/CDiscAdjDeformationDriver.cpp' ]) if get_option('enable-normal') @@ -12,6 +13,7 @@ su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', 'output/tools/CWindowingTools.cpp', 'output/CMeshOutput.cpp', 'output/output_structure_legacy.cpp', + 'output/CBaselineOutput.cpp', 'variables/CBaselineVariable.cpp', 'variables/CVariable.cpp', 'output/filewriter/CParallelDataSorter.cpp', @@ -49,3 +51,43 @@ su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', objects : su2_cfd_obj, cpp_args :[default_warning_flags, su2_cpp_args]) endif + +if get_option('enable-autodiff') +su2_cfd_obj_ad = su2_cfd_lib_ad.extract_objects(['solvers/CSolver.cpp', + 'solvers/CBaselineSolver.cpp', + 'CMarkerProfileReaderFVM.cpp', + 'output/COutput.cpp', + 'output/tools/CWindowingTools.cpp', + 'output/output_structure_legacy.cpp', + 'output/CBaselineOutput.cpp', + 'output/filewriter/CParallelDataSorter.cpp', + 'output/filewriter/CParallelFileWriter.cpp', + 'output/filewriter/CFEMDataSorter.cpp', + 'output/filewriter/CSurfaceFEMDataSorter.cpp', + 'output/filewriter/CFVMDataSorter.cpp', + 'output/filewriter/CSurfaceFVMDataSorter.cpp', + 'output/filewriter/CCSVFileWriter.cpp', + 'output/filewriter/CSTLFileWriter.cpp', + 'output/filewriter/CTecplotFileWriter.cpp', + 'output/filewriter/CTecplotBinaryFileWriter.cpp', + 'output/filewriter/CParaviewFileWriter.cpp', + 'output/filewriter/CParaviewBinaryFileWriter.cpp', + 'output/filewriter/CSU2FileWriter.cpp', + 'output/filewriter/CSU2BinaryFileWriter.cpp', + 'output/filewriter/CSU2MeshFileWriter.cpp', + 'output/filewriter/CParaviewXMLFileWriter.cpp', + 'output/filewriter/CParaviewVTMFileWriter.cpp', + 'variables/CBaselineVariable.cpp', + 'variables/CVariable.cpp', + 'limiters/CLimiterDetails.cpp']) + + su2_def_lib_ad = static_library('SU2core_DEF_AD', + su2_def_src, + install : false, + dependencies : [su2_deps, codi_dep, commonAD_dep], + cpp_args: [default_warning_flags, su2_cpp_args, codi_rev_args]) + + su2_def_dep_ad = declare_dependency(link_with: su2_def_lib_ad, + include_directories: su2_def_include) + +endif diff --git a/SU2_DOT/src/meson.build b/SU2_DOT/src/meson.build index 4b01f4f3547..8fd80741329 100644 --- a/SU2_DOT/src/meson.build +++ b/SU2_DOT/src/meson.build @@ -1,4 +1,4 @@ -su2_dot_src = ['SU2_DOT.cpp'] +su2_dot_src = 'SU2_DOT.cpp' if get_option('enable-normal') su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', @@ -28,10 +28,11 @@ if get_option('enable-normal') 'variables/CBaselineVariable.cpp', 'variables/CVariable.cpp', 'limiters/CLimiterDetails.cpp']) + su2_dot = executable('SU2_DOT', - su2_dot_src, + su2_dot_src, install: true, - dependencies: [su2_deps, common_dep], + dependencies: [su2_deps, common_dep], objects : su2_cfd_obj, cpp_args :[default_warning_flags, su2_cpp_args]) @@ -69,7 +70,7 @@ if get_option('enable-autodiff') su2_dot_ad = executable('SU2_DOT_AD', su2_dot_src, install: true, - dependencies: [su2_deps, codi_dep, commonAD_dep], + dependencies: [su2_deps, codi_dep, commonAD_dep], objects : su2_cfd_obj_ad, cpp_args : [default_warning_flags, su2_cpp_args, codi_rev_args]) diff --git a/SU2_PY/pySU2/meson.build b/SU2_PY/pySU2/meson.build index 1aab2e53b50..59b6a063347 100644 --- a/SU2_PY/pySU2/meson.build +++ b/SU2_PY/pySU2/meson.build @@ -28,7 +28,10 @@ if get_option('enable-normal') '_pysu2', cpp_source, dependencies: [wrapper_deps, common_dep, su2_deps], - objects: [su2_cfd_lib.extract_all_objects(), su2_def_lib.extract_objects('drivers/CDeformationDriver.cpp')], + objects: [ + su2_cfd_lib.extract_all_objects(), + su2_def_lib.extract_objects('drivers/CDeformationDriver.cpp') + ], install: true, include_directories : mpi4py_include, cpp_args : [default_warning_flags,su2_cpp_args], @@ -44,7 +47,10 @@ if get_option('enable-autodiff') '_pysu2ad', cpp_source, dependencies: [wrapper_deps, commonAD_dep, su2_deps, codi_dep], - objects: su2_cfd_lib_ad.extract_all_objects(), + objects: [ + su2_cfd_lib_ad.extract_all_objects(), + su2_def_lib_ad.extract_objects('drivers/CDiscAdjDeformationDriver.cpp') + ], install: true, include_directories : mpi4py_include, cpp_args : [default_warning_flags, su2_cpp_args, codi_rev_args], diff --git a/SU2_PY/pySU2/pySU2ad.i b/SU2_PY/pySU2/pySU2ad.i index 4409fd93fcb..ff7eaf6cb51 100644 --- a/SU2_PY/pySU2/pySU2ad.i +++ b/SU2_PY/pySU2/pySU2ad.i @@ -42,6 +42,7 @@ threads="1" #include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CDiscAdjSinglezoneDriver.hpp" +#include "../../SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp" %} @@ -91,3 +92,4 @@ const unsigned int ZONE_1 = 1; /*!< \brief Definition of the first grid domain. %include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CDiscAdjSinglezoneDriver.hpp" +%include "../../SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp" From bb2c03044cf60e4106eb7041f5152477052b2a71 Mon Sep 17 00:00:00 2001 From: aa-g Date: Tue, 22 Jun 2021 19:34:31 +0200 Subject: [PATCH 006/598] Integrate CMeshSolver for mesh deformation based on linear elasticity solver --- .../geometry/primal_grid/CPrimalGrid.hpp | 1 + SU2_CFD/include/solvers/CMeshSolver.hpp | 15 +- SU2_CFD/include/solvers/CSolver.hpp | 12 +- SU2_CFD/src/iteration/CIteration.cpp | 2 +- SU2_CFD/src/solvers/CMeshSolver.cpp | 58 ++++++- .../include/drivers/CDeformationDriver.hpp | 30 +++- SU2_DEF/src/drivers/CDeformationDriver.cpp | 152 ++++++++++++++---- SU2_DEF/src/meson.build | 10 ++ 8 files changed, 245 insertions(+), 35 deletions(-) diff --git a/Common/include/geometry/primal_grid/CPrimalGrid.hpp b/Common/include/geometry/primal_grid/CPrimalGrid.hpp index 5697b6fbf07..e5b7f19ca50 100644 --- a/Common/include/geometry/primal_grid/CPrimalGrid.hpp +++ b/Common/include/geometry/primal_grid/CPrimalGrid.hpp @@ -32,6 +32,7 @@ #include #include +#include #include #include "../../CConfig.hpp" diff --git a/SU2_CFD/include/solvers/CMeshSolver.hpp b/SU2_CFD/include/solvers/CMeshSolver.hpp index 5a4a6d927f0..2b8cdb04b9e 100644 --- a/SU2_CFD/include/solvers/CMeshSolver.hpp +++ b/SU2_CFD/include/solvers/CMeshSolver.hpp @@ -129,6 +129,7 @@ class CMeshSolver final : public CFEASolver { /*! * \brief Grid deformation using the linear elasticity equations. * \param[in] geometry - Geometrical definition of the problem. + * \param[in] numerics - Numerics used in the solution. * \param[in] config - Definition of the particular problem. */ void DeformMesh(CGeometry **geometry, @@ -136,12 +137,20 @@ class CMeshSolver final : public CFEASolver { CConfig *config) override; /*! - * \brief Set the stiffness of the mesh. + * \brief Grid deformation using the linear elasticity equations (no multigrid). * \param[in] geometry - Geometrical definition of the problem. + * \param[in] numerics - Numerics used in the solution. + * \param[in] config - Definition of the particular problem. + */ + void DeformMesh(CGeometry *geometry, + CNumerics **numerics, + CConfig *config) override; + /*! + * \brief Set the stiffness of the mesh. + * \param[in] numerics - Numerics used in the solution. * \param[in] config - Definition of the particular problem. */ - void SetMesh_Stiffness(CGeometry **geometry, - CNumerics **numerics, + void SetMesh_Stiffness(CNumerics **numerics, CConfig *config) override; /*! diff --git a/SU2_CFD/include/solvers/CSolver.hpp b/SU2_CFD/include/solvers/CSolver.hpp index ad1889ce9f4..8263a8ae064 100644 --- a/SU2_CFD/include/solvers/CSolver.hpp +++ b/SU2_CFD/include/solvers/CSolver.hpp @@ -4205,8 +4205,16 @@ class CSolver { * \param[in] config - Definition of the particular problem. * \param[in] referenceCoord - Determine if the mesh is deformed from the reference or from the current coordinates. */ - inline virtual void SetMesh_Stiffness(CGeometry **geometry, - CNumerics **numerics, + inline virtual void DeformMesh(CGeometry *geometry, + CNumerics **numerics, + CConfig *config) { } + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] referenceCoord - Determine if the mesh is deformed from the reference or from the current coordinates. + */ + inline virtual void SetMesh_Stiffness(CNumerics **numerics, CConfig *config) { } /*! diff --git a/SU2_CFD/src/iteration/CIteration.cpp b/SU2_CFD/src/iteration/CIteration.cpp index 3fbe23c695c..fe27147992a 100644 --- a/SU2_CFD/src/iteration/CIteration.cpp +++ b/SU2_CFD/src/iteration/CIteration.cpp @@ -163,7 +163,7 @@ void CIteration::SetMesh_Deformation(CGeometry** geometry, CSolver** solver, CNu /*--- Set the stiffness of each element mesh into the mesh numerics ---*/ - solver[MESH_SOL]->SetMesh_Stiffness(geometry, numerics[MESH_SOL], config); + solver[MESH_SOL]->SetMesh_Stiffness(numerics[MESH_SOL], config); /*--- Deform the volume grid around the new boundary locations ---*/ diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index 06af9b8408c..ab0446da994 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -420,7 +420,7 @@ void CMeshSolver::SetWallDistance(CGeometry *geometry, CConfig *config) { END_SU2_OMP_PARALLEL } -void CMeshSolver::SetMesh_Stiffness(CGeometry **geometry, CNumerics **numerics, CConfig *config){ +void CMeshSolver::SetMesh_Stiffness(CNumerics **numerics, CConfig *config){ if (stiffness_set) return; @@ -542,6 +542,62 @@ void CMeshSolver::DeformMesh(CGeometry **geometry, CNumerics **numerics, CConfig } +void CMeshSolver::DeformMesh(CGeometry *geometry, CNumerics **numerics, CConfig *config){ + + if (multizone) nodes->Set_BGSSolution_k(); + + /*--- Capture a few MPI dependencies for AD. ---*/ + geometry->InitiateComms(geometry, config, COORDINATES); + geometry->CompleteComms(geometry, config, COORDINATES); + + InitiateComms(geometry, config, SOLUTION); + CompleteComms(geometry, config, SOLUTION); + + InitiateComms(geometry, config, MESH_DISPLACEMENTS); + CompleteComms(geometry, config, MESH_DISPLACEMENTS); + + /*--- Compute the stiffness matrix, no point recording because we clear the residual. ---*/ + + const bool wasActive = AD::BeginPassive(); + + Compute_StiffMatrix(geometry, numerics, config); + + AD::EndPassive(wasActive); + + /*--- Clear residual (loses AD info), we do not want an incremental solution. ---*/ + SU2_OMP_PARALLEL { + LinSysRes.SetValZero(); + if (time_domain && config->GetFSI_Simulation()) LinSysSol.SetValZero(); + } + END_SU2_OMP_PARALLEL + + /*--- Impose boundary conditions (all of them are ESSENTIAL BC's - displacements). ---*/ + SetBoundaryDisplacements(geometry, config, false); + + /*--- Solve the linear system. ---*/ + Solve_System(geometry, config); + + SU2_OMP_PARALLEL { + + /*--- Update the grid coordinates and cell volumes using the solution + of the linear system (usol contains the x, y, z displacements). ---*/ + UpdateGridCoord(geometry, config); + + /*--- Update the dual grid. ---*/ + UpdateDualGrid(geometry, config); + + /*--- Check for failed deformation (negative volumes). ---*/ + SetMinMaxVolume(geometry, config, true); + + /*--- The Grid Velocity is only computed if the problem is time domain ---*/ + if (time_domain && !config->GetFSI_Simulation()) + ComputeGridVelocity(geometry, config); + + } + END_SU2_OMP_PARALLEL + +} + void CMeshSolver::UpdateGridCoord(CGeometry *geometry, CConfig *config){ /*--- Update the grid coordinates using the solution of the linear system ---*/ diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index 8a424ff32fd..2601f378ad8 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -1,4 +1,4 @@ -/*! + /*! * \file CDeformationDriver.hpp * \brief Headers of the main subroutines for driving the mesh deformation. * \author T. Economon, H. Kline, R. Sanchez @@ -32,6 +32,7 @@ #include "../../../Common/include/grid_movement/CSurfaceMovement.hpp" #include "../../../Common/include/grid_movement/CVolumetricMovement.hpp" #include "../../../SU2_CFD/include/output/COutput.hpp" +#include "../../../SU2_CFD/include/numerics/CNumerics.hpp" #include "../../../Common/include/geometry/CGeometry.hpp" /*! @@ -56,6 +57,8 @@ class CDeformationDriver { CGeometry **geometry_container; /*!< \brief Geometrical definition of the problem. */ CSurfaceMovement **surface_movement; /*!< \brief Surface movement classes of the problem. */ CVolumetricMovement **grid_movement; /*!< \brief Volume grid movement classes of the problem. */ + CSolver **solver_container; + CNumerics ***numerics_container; COutput **output_container; /*!< \brief Pointer to the COutput class. */ public: @@ -76,6 +79,11 @@ class CDeformationDriver { */ void Run(); + /*! + * \brief Output the mesh. + */ + void Output(); + /*! * \brief Deallocation routine */ @@ -102,4 +110,24 @@ class CDeformationDriver { */ void Output_Preprocessing(); + /*! + * \brief Preprocess the mesh solver container. + */ + void Solver_Preprocessing(); + + /*! + * \brief Preprocess the numerics container. + */ + void Numerics_Preprocessing(); + + /*! + * \brief Mesh deformation based on linear elasticity solver (CMeshSolver). + */ + void Update(); + + /*! + * \brief Mesh deformation based on legacy implementation. + */ + void Update_Legacy(); + }; diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index b12d24154a9..b330c7fc343 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -29,7 +29,9 @@ #include "../../include/drivers/CDeformationDriver.hpp" #include "../../../Common/include/geometry/CPhysicalGeometry.hpp" +#include "../../../SU2_CFD/include/solvers/CMeshSolver.hpp" #include "../../../SU2_CFD/include/output/CMeshOutput.hpp" +#include "../../../SU2_CFD/include/numerics/elasticity/CFEALinearElasticity.hpp" using namespace std; @@ -76,6 +78,18 @@ CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) Output_Preprocessing(); + if (driver_config->GetDeform_Mesh()){ + + /*--- Preprocessing of the mesh solver for all zones. ---*/ + + Solver_Preprocessing(); + + /*--- Preprocessing of the mesh solver for all zones. ---*/ + + Numerics_Preprocessing(); + + } + /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ StopTime = SU2_MPI::Wtime(); @@ -98,17 +112,22 @@ void CDeformationDriver::SetContainers_Null() { the SU2_DEF code. In general, the pointers are instantiated down a hierarchy over all zones as described in the comments below. ---*/ config_container = new CConfig*[nZone]; + output_container = new COutput*[nZone]; geometry_container = new CGeometry*[nZone]; surface_movement = new CSurfaceMovement*[nZone]; grid_movement = new CVolumetricMovement*[nZone]; - output_container = new COutput*[nZone]; + + solver_container = new CSolver*[nZone]; + numerics_container = new CNumerics**[nZone]; for (iZone = 0; iZone < nZone; iZone++) { config_container[iZone] = nullptr; + output_container[iZone] = nullptr; geometry_container[iZone] = nullptr; surface_movement[iZone] = nullptr; grid_movement[iZone] = nullptr; - output_container[iZone] = nullptr; + solver_container[iZone] = nullptr; + numerics_container[iZone] = nullptr; } } @@ -137,10 +156,13 @@ void CDeformationDriver::Input_Preprocessing() { config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); } - /*--- Set the multizone part of the problem. ---*/ + /*--- Set the multizone part of the problem. ---*/ + if (driver_config->GetMultizone_Problem()){ for (iZone = 0; iZone < nZone; iZone++) { + /*--- Set the interface markers for multizone ---*/ + config_container[iZone]->SetMultizone(driver_config, config_container); } } @@ -237,6 +259,30 @@ void CDeformationDriver::Output_Preprocessing() { } } +void CDeformationDriver::Solver_Preprocessing() { + + for (iZone = 0; iZone < nZone; iZone++) { + solver_container[iZone] = new CMeshSolver(geometry_container[iZone], config_container[iZone]); + } + +} + +void CDeformationDriver::Numerics_Preprocessing() { + + for (iZone = 0; iZone < nZone; iZone++) { + numerics_container[iZone] = new CNumerics* [omp_get_num_threads() * MAX_TERMS](); + + for (int thread = 0; thread < omp_get_max_threads(); ++thread) { + const int iTerm = FEA_TERM + thread * MAX_TERMS; + const int nDim = geometry_container[iZone]->GetnDim(); + + numerics_container[iZone][iTerm] = new CFEAMeshElasticity(nDim, nDim, geometry_container[iZone]->GetnElem(), config_container[iZone]); + } + + } + +} + void CDeformationDriver::Run() { /* --- Start measuring computation time ---*/ @@ -245,6 +291,47 @@ void CDeformationDriver::Run() { /*--- Surface grid deformation using design variables ---*/ + if (driver_config->GetDeform_Mesh()) { + Update(); + } + else { + Update_Legacy(); + } + + /*--- Synchronization point after a single solver iteration. Compute the + wall clock time required. ---*/ + + StopTime = SU2_MPI::Wtime(); + + UsedTimeCompute = StopTime-StartTime; + if (rank == MASTER_NODE) { + cout << "\nCompleted in " << fixed << UsedTimeCompute << " seconds on "<< size; + + if (size == 1) cout << " core." << endl; else cout << " cores." << endl; + } + + /*--- Output the deformed mesh ---*/ + Output(); + +} + +void CDeformationDriver::Update() { + + for (iZone = 0; iZone < nZone; iZone++){ + + /*--- Set the stiffness of each element mesh into the mesh numerics ---*/ + + solver_container[iZone]->SetMesh_Stiffness(numerics_container[iZone], config_container[iZone]); + + /*--- Deform the volume grid around the new boundary locations ---*/ + + solver_container[iZone]->DeformMesh(geometry_container[iZone], numerics_container[iZone], config_container[iZone]); + + } +} + +void CDeformationDriver::Update_Legacy() { + for (iZone = 0; iZone < nZone; iZone++){ if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { @@ -392,12 +479,14 @@ void CDeformationDriver::Run() { } - /*--- Computational grid preprocesing ---*/ +} - if (rank == MASTER_NODE) cout << endl << "----------------------- Write deformed grid files -----------------------" << endl; +void CDeformationDriver::Output() { /*--- Output deformed grid for visualization, if requested (surface and volumetric), in parallel - requires to move all the data to the master node---*/ + requires to move all the data to the master node---*/ + + if (rank == MASTER_NODE) cout << endl << "----------------------- Write deformed grid files -----------------------" << endl; for (iZone = 0; iZone < nZone; iZone++){ @@ -427,7 +516,7 @@ void CDeformationDriver::Run() { /*--- Set the file names for the visualization files ---*/ output_container[iZone]->SetVolume_Filename("volume_deformed"); - output_container[iZone]->SetSurface_Filename("surface_deformed"); + output_container[iZone]->SetSurface_Filename("surfac e_deformed"); for (unsigned short iFile = 0; iFile < config_container[iZone]->GetnVolumeOutputFiles(); iFile++){ auto FileFormat = config_container[iZone]->GetVolumeOutputFiles(); @@ -436,38 +525,47 @@ void CDeformationDriver::Run() { } } - if ((config_container[ZONE_0]->GetDesign_Variable(0) != NO_DEFORMATION) && - (config_container[ZONE_0]->GetDesign_Variable(0) != SCALE_GRID) && - (config_container[ZONE_0]->GetDesign_Variable(0) != TRANSLATE_GRID) && - (config_container[ZONE_0]->GetDesign_Variable(0) != ROTATE_GRID)) { - - /*--- Write the the free-form deformation boxes after deformation. ---*/ - - if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; - - surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); + if (!driver_config->GetDeform_Mesh()) { + if ((config_container[ZONE_0]->GetDesign_Variable(0) != NO_DEFORMATION) && + (config_container[ZONE_0]->GetDesign_Variable(0) != SCALE_GRID) && + (config_container[ZONE_0]->GetDesign_Variable(0) != TRANSLATE_GRID) && + (config_container[ZONE_0]->GetDesign_Variable(0) != ROTATE_GRID)) { - } + /*--- Write the the free-form deformation boxes after deformation. ---*/ - /*--- Synchronization point after a single solver iteration. Compute the - wall clock time required. ---*/ + if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; - StopTime = SU2_MPI::Wtime(); + surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); - UsedTimeCompute = StopTime-StartTime; - if (rank == MASTER_NODE) { - cout << "\nCompleted in " << fixed << UsedTimeCompute << " seconds on "<< size; - if (size == 1) cout << " core." << endl; else cout << " cores." << endl; } + } } void CDeformationDriver::Postprocessing() { + if (rank == MASTER_NODE) cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; delete driver_config; driver_config = nullptr; + for (iZone = 0; iZone < nZone; iZone++) { + if (numerics_container[iZone] != nullptr) { + for (unsigned int iTerm = 0; iTerm < MAX_TERMS*omp_get_max_threads(); iTerm++) { + delete numerics_container[iZone][iTerm]; + } + delete [] numerics_container[iZone]; + } + } + delete [] numerics_container; + if (rank == MASTER_NODE) cout << "Deleted CNumerics container." << endl; + + for (iZone = 0; iZone < nZone; iZone++) { + delete solver_container[iZone]; + } + delete [] solver_container; + if (rank == MASTER_NODE) cout << "Deleted CSolver container." << endl; + if (geometry_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { if (geometry_container[iZone] != nullptr) { @@ -506,6 +604,8 @@ void CDeformationDriver::Postprocessing() { } delete [] config_container; } + if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; + if (output_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { if (output_container[iZone] != nullptr) { @@ -514,8 +614,6 @@ void CDeformationDriver::Postprocessing() { } delete [] output_container; } - if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; - if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; /*--- Exit the solver cleanly ---*/ diff --git a/SU2_DEF/src/meson.build b/SU2_DEF/src/meson.build index 0f19687b7bc..ecd2c2faf86 100644 --- a/SU2_DEF/src/meson.build +++ b/SU2_DEF/src/meson.build @@ -8,6 +8,11 @@ if get_option('enable-normal') su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', 'solvers/CBaselineSolver.cpp', + 'solvers/CMeshSolver.cpp', + 'solvers/CFEASolver.cpp', + 'numerics/CNumerics.cpp', + 'numerics/elasticity/CFEAElasticity.cpp', + 'numerics/elasticity/CFEALinearElasticity.cpp', 'CMarkerProfileReaderFVM.cpp', 'output/COutput.cpp', 'output/tools/CWindowingTools.cpp', @@ -16,6 +21,11 @@ su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', 'output/CBaselineOutput.cpp', 'variables/CBaselineVariable.cpp', 'variables/CVariable.cpp', + 'variables/CFEAVariable.cpp', + 'variables/CFEABoundVariable.cpp', + 'variables/CMeshElement.cpp', + 'variables/CMeshVariable.cpp', + 'variables/CMeshBoundVariable.cpp', 'output/filewriter/CParallelDataSorter.cpp', 'output/filewriter/CFVMDataSorter.cpp', 'output/filewriter/CFEMDataSorter.cpp', From c44014888000d625489c28fd0e04dec85b518a86 Mon Sep 17 00:00:00 2001 From: aa-g Date: Tue, 22 Jun 2021 20:53:48 +0200 Subject: [PATCH 007/598] Fix merge 29e45213f1c5c27db241da16665bebad41d20d4f --- SU2_CFD/src/solvers/CMeshSolver.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index f51bda27186..b3605563473 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -586,16 +586,17 @@ void CMeshSolver::DeformMesh(CGeometry *geometry, CNumerics **numerics, CConfig of the linear system (usol contains the x, y, z displacements). ---*/ UpdateGridCoord(geometry, config); - /*--- Update the dual grid. ---*/ - UpdateDualGrid(geometry, config); + /*--- Update the dual grid (without multigrid). ---*/ + geometry->InitiateComms(geometry, config, COORDINATES); + geometry->CompleteComms(geometry, config, COORDINATES); + + geometry->SetControlVolume(config, UPDATE); + geometry->SetBoundControlVolume(config, UPDATE); + geometry->SetMaxLength(config); /*--- Check for failed deformation (negative volumes). ---*/ SetMinMaxVolume(geometry, config, true); - /*--- The Grid Velocity is only computed if the problem is time domain ---*/ - if (time_domain && !config->GetFSI_Simulation()) - ComputeGridVelocity(geometry, config); - } END_SU2_OMP_PARALLEL From 169be9a4067cebc7495485069a72e21ce1930087 Mon Sep 17 00:00:00 2001 From: aa-g Date: Wed, 23 Jun 2021 00:43:00 +0200 Subject: [PATCH 008/598] Add marker- and vertex-data getters and setters (+ minor fixes) --- .../include/drivers/CDeformationDriver.hpp | 83 ++++++++ SU2_DEF/src/SU2_DEF.cpp | 1 + SU2_DEF/src/drivers/CDeformationDriver.cpp | 193 +++++++++++++++++- 3 files changed, 276 insertions(+), 1 deletion(-) diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index 2601f378ad8..cfb92560262 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -89,6 +89,89 @@ class CDeformationDriver { */ void Postprocessing(); + /*! + * \brief Get all the deformable boundary marker tags. + * \return List of deformable boundary markers tags. + */ + vector GetAllDeformMeshMarkersTag() const; + + /*! + * \brief Get all the boundary markers tags with their associated indices. + * \return List of boundary markers tags with their indices. + */ + map GetAllBoundaryMarkers() const; + + /*! + * \brief Get all the boundary markers tags with their associated types. + * \return List of boundary markers tags with their types. + */ + map GetAllBoundaryMarkersType() const; + + /*! + * \brief Get the number of vertices (halo nodes included) from a specified marker. + * \param[in] iMarker - Marker identifier. + * \return Number of vertices. + */ + unsigned long GetNumberVertices(unsigned short iMarker) const; + + /*! + * \brief Get the number of halo vertices from a specified marker. + * \param[in] iMarker - Marker identifier. + * \return Number of vertices. + */ + unsigned long GetNumberHaloVertices(unsigned short iMarker) const; + + /*! + * \brief Check if a vertex is physical or not (halo node) on a specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return True if the specified vertex is a halo node. + */ + bool IsAHaloNode(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get the global index of a vertex on a specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Vertex global index. + */ + unsigned long GetVertexGlobalIndex(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get undeformed coordinates from the mesh solver. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return x,y,z coordinates of the vertex. + */ + vector GetInitialMeshCoord(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get the unit normal (vector) at a vertex on a specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Unit normal (vector) at the vertex. + */ + vector GetVertexNormal(unsigned short iMarker, unsigned long iVertex, bool unitNormal = false) const; + + inline vector GetVertexUnitNormal(unsigned short iMarker, unsigned long iVertex) const { + return GetVertexNormal(iMarker, iVertex, true); + } + + /*! + * \brief Set the mesh displacement for the elasticity mesh solver. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \param[in] DispX - Value of the mesh displacement in the direction X. + * \param[in] DispY - Value of the mesh displacement in the direction Y. + * \param[in] DispZ - Value of the mesh displacement in the direction Z. + */ + void SetMeshDisplacement(unsigned short iMarker, unsigned long iVertex, passivedouble DispX, passivedouble DispY, passivedouble DispZ); + + /*! + * \brief Communicate the boundary mesh displacements in a python call + */ + void CommunicateMeshDisplacement(void); + protected: /*! * \brief Init_Containers diff --git a/SU2_DEF/src/SU2_DEF.cpp b/SU2_DEF/src/SU2_DEF.cpp index ea0ce32bcb2..f383f2f7746 100644 --- a/SU2_DEF/src/SU2_DEF.cpp +++ b/SU2_DEF/src/SU2_DEF.cpp @@ -55,6 +55,7 @@ int main(int argc, char *argv[]) { else { strcpy(config_file_name, "default.cfg"); } /*--- Initialize the mesh deformation driver ---*/ + driver = new CDeformationDriver(config_file_name, comm); /*--- Launch the main external loop of the solver. ---*/ diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index b330c7fc343..3f8d5ce71ac 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -29,6 +29,7 @@ #include "../../include/drivers/CDeformationDriver.hpp" #include "../../../Common/include/geometry/CPhysicalGeometry.hpp" +#include "../../../Common/include/toolboxes/geometry_toolbox.hpp" #include "../../../SU2_CFD/include/solvers/CMeshSolver.hpp" #include "../../../SU2_CFD/include/output/CMeshOutput.hpp" #include "../../../SU2_CFD/include/numerics/elasticity/CFEALinearElasticity.hpp" @@ -516,7 +517,7 @@ void CDeformationDriver::Output() { /*--- Set the file names for the visualization files ---*/ output_container[iZone]->SetVolume_Filename("volume_deformed"); - output_container[iZone]->SetSurface_Filename("surfac e_deformed"); + output_container[iZone]->SetSurface_Filename("surface_deformed"); for (unsigned short iFile = 0; iFile < config_container[iZone]->GetnVolumeOutputFiles(); iFile++){ auto FileFormat = config_container[iZone]->GetVolumeOutputFiles(); @@ -621,3 +622,193 @@ void CDeformationDriver::Postprocessing() { if (rank == MASTER_NODE) cout << endl << "------------------------- Exit Success (SU2_DEF) ------------------------" << endl << endl; } + +vector CDeformationDriver::GetAllDeformMeshMarkersTag() const { + + vector interfaceBoundariesTagList; + unsigned short iMarker, nBoundariesMarker; + string Marker_Tag; + + nBoundariesMarker = config_container[ZONE_0]->GetnMarker_Deform_Mesh(); + interfaceBoundariesTagList.resize(nBoundariesMarker); + + for(iMarker=0; iMarker < nBoundariesMarker; iMarker++){ + Marker_Tag = config_container[ZONE_0]->GetMarker_Deform_Mesh_TagBound(iMarker); + interfaceBoundariesTagList[iMarker] = Marker_Tag; + } + + return interfaceBoundariesTagList; +} + +map CDeformationDriver::GetAllBoundaryMarkers() const { + + map allBoundariesMap; + unsigned short iMarker, nBoundaryMarkers; + string Marker_Tag; + + nBoundaryMarkers = config_container[ZONE_0]->GetnMarker_All(); + + for(iMarker=0; iMarker < nBoundaryMarkers; iMarker++){ + Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); + allBoundariesMap[Marker_Tag] = iMarker; + } + + return allBoundariesMap; +} + +map CDeformationDriver::GetAllBoundaryMarkersType() const { + + map allBoundariesTypeMap; + unsigned short iMarker, KindBC; + string Marker_Tag, Marker_Type; + + for(iMarker=0; iMarker < config_container[ZONE_0]->GetnMarker_All(); iMarker++){ + Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); + KindBC = config_container[ZONE_0]->GetMarker_All_KindBC(iMarker); + switch(KindBC){ + case EULER_WALL: + Marker_Type = "EULER_WALL"; + break; + case FAR_FIELD: + Marker_Type = "FARFIELD"; + break; + case ISOTHERMAL: + Marker_Type = "ISOTHERMAL"; + break; + case HEAT_FLUX: + Marker_Type = "HEATFLUX"; + break; + case INLET_FLOW: + Marker_Type = "INLET_FLOW"; + break; + case OUTLET_FLOW: + Marker_Type = "OUTLET_FLOW"; + break; + case SYMMETRY_PLANE: + Marker_Type = "SYMMETRY"; + break; + case SEND_RECEIVE: + Marker_Type = "SEND_RECEIVE"; + break; + default: + Marker_Type = "UNKNOWN_TYPE"; + } + allBoundariesTypeMap[Marker_Tag] = Marker_Type; + } + + return allBoundariesTypeMap; +} + +unsigned long CDeformationDriver::GetNumberVertices(unsigned short iMarker) const { + + return geometry_container[ZONE_0]->nVertex[iMarker]; + +} + +unsigned long CDeformationDriver::GetNumberHaloVertices(unsigned short iMarker) const { + + unsigned long nHaloVertices, iVertex, iPoint; + + nHaloVertices = 0; + for(iVertex = 0; iVertex < geometry_container[ZONE_0]->nVertex[iMarker]; iVertex++){ + iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); + if(!(geometry_container[ZONE_0]->nodes->GetDomain(iPoint))) nHaloVertices += 1; + } + + return nHaloVertices; + +} + +unsigned long CDeformationDriver::GetVertexGlobalIndex(unsigned short iMarker, unsigned long iVertex) const { + + unsigned long iPoint, GlobalIndex; + + iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); + GlobalIndex = geometry_container[ZONE_0]->nodes->GetGlobalIndex(iPoint); + + return GlobalIndex; + +} + +bool CDeformationDriver::IsAHaloNode(unsigned short iMarker, unsigned long iVertex) const { + + unsigned long iPoint; + + iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); + if(geometry_container[ZONE_0]->nodes->GetDomain(iPoint)) return false; + else return true; + +} + +vector CDeformationDriver::GetInitialMeshCoord(unsigned short iMarker, unsigned long iVertex) const { + + vector coord(3,0.0); + vector coord_passive(3, 0.0); + + auto iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); + + for (auto iDim = 0 ; iDim < geometry_container[ZONE_0]->GetnDim(); iDim++){ + coord[iDim] = solver_container[ZONE_0]->GetNodes()->GetMesh_Coord(iPoint,iDim); + } + + coord_passive[0] = SU2_TYPE::GetValue(coord[0]); + coord_passive[1] = SU2_TYPE::GetValue(coord[1]); + coord_passive[2] = SU2_TYPE::GetValue(coord[2]); + + return coord_passive; +} + +vector CDeformationDriver::GetVertexNormal(unsigned short iMarker, unsigned long iVertex, bool unitNormal) const { + + int nDim = geometry_container[ZONE_0]->GetnDim(); + + su2double *Normal; + su2double Area; + vector ret_Normal(3, 0.0); + vector ret_Normal_passive(3, 0.0); + + Normal = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNormal(); + + if (!unitNormal) { + + ret_Normal_passive[0] = SU2_TYPE::GetValue(Normal[0]); + ret_Normal_passive[1] = SU2_TYPE::GetValue(Normal[1]); + if(nDim>2) ret_Normal_passive[2] = SU2_TYPE::GetValue(Normal[2]); + + return ret_Normal_passive; + } + + Area = GeometryToolbox::Norm(nDim, Normal); + + ret_Normal[0] = Normal[0]/Area; + ret_Normal[1] = Normal[1]/Area; + if(nDim>2) ret_Normal[2] = Normal[2]/Area; + + ret_Normal_passive[0] = SU2_TYPE::GetValue(ret_Normal[0]); + ret_Normal_passive[1] = SU2_TYPE::GetValue(ret_Normal[1]); + ret_Normal_passive[2] = SU2_TYPE::GetValue(ret_Normal[2]); + + return ret_Normal_passive; +} + +void CDeformationDriver::SetMeshDisplacement(unsigned short iMarker, unsigned long iVertex, passivedouble DispX, passivedouble DispY, passivedouble DispZ) { + + unsigned long iPoint; + su2double MeshDispl[3] = {0.0,0.0,0.0}; + + MeshDispl[0] = DispX; + MeshDispl[1] = DispY; + MeshDispl[2] = DispZ; + + iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); + + solver_container[ZONE_0]->GetNodes()->SetBound_Disp(iPoint, MeshDispl); + +} + +void CDeformationDriver::CommunicateMeshDisplacement(void) { + + solver_container[ZONE_0]->InitiateComms(geometry_container[ZONE_0], config_container[ZONE_0], MESH_DISPLACEMENTS); + solver_container[ZONE_0]->CompleteComms(geometry_container[ZONE_0], config_container[ZONE_0], MESH_DISPLACEMENTS); + +} From e818703eaa73ae9cc5bfe78bcf20a19b69b57aa7 Mon Sep 17 00:00:00 2001 From: patelha57 Date: Tue, 22 Jun 2021 17:20:16 -0400 Subject: [PATCH 009/598] Remove nullptr checks, update AD register input code, minor code fixes --- .../drivers/CDiscAdjDeformationDriver.hpp | 4 - SU2_DEF/src/drivers/CDeformationDriver.cpp | 96 +++++++++---------- .../src/drivers/CDiscAdjDeformationDriver.cpp | 30 ++---- 3 files changed, 50 insertions(+), 80 deletions(-) diff --git a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp index f3635ab694b..7901776a9f1 100644 --- a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp @@ -27,12 +27,8 @@ #pragma once -#define ENABLE_MAPS #include "../../../Common/include/CConfig.hpp" -#undef ENABLE_MAPS - #include "../../../Common/include/parallelization/mpi_structure.hpp" - #include "../../../Common/include/geometry/CGeometry.hpp" #include "../../../Common/include/fem/fem_geometry_structure.hpp" #include "../../../Common/include/grid_movement/CSurfaceMovement.hpp" diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 3f8d5ce71ac..8c8155dfaa5 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -173,70 +173,70 @@ void CDeformationDriver::Geometrical_Preprocessing() { for (iZone = 0; iZone < nZone; iZone++) { - /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ + /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ - CGeometry *geometry_aux = nullptr; + CGeometry *geometry_aux = nullptr; - /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ + /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ - geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); + geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); - /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ + /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - geometry_aux->SetColorGrid_Parallel(config_container[iZone]); + geometry_aux->SetColorGrid_Parallel(config_container[iZone]); - /*--- Build the grid data structures using the ParMETIS coloring. ---*/ + /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - geometry_container[iZone] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); + geometry_container[iZone] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); - /*--- Deallocate the memory of geometry_aux ---*/ + /*--- Deallocate the memory of geometry_aux ---*/ - delete geometry_aux; + delete geometry_aux; - /*--- Add the Send/Receive boundaries ---*/ + /*--- Add the Send/Receive boundaries ---*/ - geometry_container[iZone]->SetSendReceive(config_container[iZone]); + geometry_container[iZone]->SetSendReceive(config_container[iZone]); - /*--- Add the Send/Receive boundaries ---*/ + /*--- Add the Send/Receive boundaries ---*/ - geometry_container[iZone]->SetBoundaries(config_container[iZone]); + geometry_container[iZone]->SetBoundaries(config_container[iZone]); - /*--- Computational grid preprocesing ---*/ + /*--- Computational grid preprocesing ---*/ - if (rank == MASTER_NODE) cout << endl << "----------------------- Preprocessing computations ----------------------" << endl; + if (rank == MASTER_NODE) cout << endl << "----------------------- Preprocessing computations ----------------------" << endl; - /*--- Compute elements surrounding points, points surrounding points ---*/ + /*--- Compute elements surrounding points, points surrounding points ---*/ - if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); + if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); - /*--- Check the orientation before computing geometrical quantities ---*/ + /*--- Check the orientation before computing geometrical quantities ---*/ - geometry_container[iZone]->SetBoundVolume(); - if (config_container[iZone]->GetReorientElements()) { - if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config_container[iZone]); - geometry_container[iZone]->Check_BoundElem_Orientation(config_container[iZone]); - } + geometry_container[iZone]->SetBoundVolume(); + if (config_container[iZone]->GetReorientElements()) { + if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config_container[iZone]); + geometry_container[iZone]->Check_BoundElem_Orientation(config_container[iZone]); + } - /*--- Create the edge structure ---*/ + /*--- Create the edge structure ---*/ - if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); - geometry_container[iZone]->SetVertex(config_container[iZone]); + if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); + geometry_container[iZone]->SetVertex(config_container[iZone]); - if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { + if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { - /*--- Create the dual control volume structures ---*/ + /*--- Create the dual control volume structures ---*/ - if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; - geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); - geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); - } + if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; + geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); + geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); + } - /*--- Create the point-to-point MPI communication structures. ---*/ + /*--- Create the point-to-point MPI communication structures. ---*/ - geometry_container[iZone]->PreprocessP2PComms(geometry_container[iZone], config_container[iZone]); + geometry_container[iZone]->PreprocessP2PComms(geometry_container[iZone], config_container[iZone]); } } @@ -569,9 +569,7 @@ void CDeformationDriver::Postprocessing() { if (geometry_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (geometry_container[iZone] != nullptr) { - delete geometry_container[iZone]; - } + delete geometry_container[iZone]; } delete [] geometry_container; } @@ -579,9 +577,7 @@ void CDeformationDriver::Postprocessing() { if (surface_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (surface_movement[iZone] != nullptr) { - delete surface_movement[iZone]; - } + delete surface_movement[iZone]; } delete [] surface_movement; } @@ -589,9 +585,7 @@ void CDeformationDriver::Postprocessing() { if (grid_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (grid_movement[iZone] != nullptr) { - delete grid_movement[iZone]; - } + delete grid_movement[iZone]; } delete [] grid_movement; } @@ -599,9 +593,7 @@ void CDeformationDriver::Postprocessing() { if (config_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (config_container[iZone] != nullptr) { - delete config_container[iZone]; - } + delete config_container[iZone]; } delete [] config_container; } @@ -609,9 +601,7 @@ void CDeformationDriver::Postprocessing() { if (output_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (output_container[iZone] != nullptr) { - delete output_container[iZone]; - } + delete output_container[iZone]; } delete [] output_container; } diff --git a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp index 923901fee8b..f95c9f36455 100644 --- a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp @@ -358,9 +358,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { for (iZone = 0; iZone < nZone; iZone++) { if (geometry_container[iZone] != nullptr) { for (iInst = 0; iInst < nInst[iZone]; iInst++){ - if (geometry_container[iZone][iInst] != nullptr) { - delete geometry_container[iZone][iInst]; - } + delete geometry_container[iZone][iInst]; } delete geometry_container[iZone]; } @@ -371,9 +369,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { if (surface_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (surface_movement[iZone] != nullptr) { - delete surface_movement[iZone]; - } + delete surface_movement[iZone]; } delete [] surface_movement; } @@ -381,9 +377,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { if (grid_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (grid_movement[iZone] != nullptr) { - delete grid_movement[iZone]; - } + delete grid_movement[iZone]; } delete [] grid_movement; } @@ -391,9 +385,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { if (config_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - if (config_container[iZone] != nullptr) { - delete config_container[iZone]; - } + delete config_container[iZone]; } delete [] config_container; } @@ -683,21 +675,13 @@ void CDiscAdjDeformationDriver::SetDiscAdjDeformation_AD(CGeometry *geometry, CC /*--- Register design variables as input and set them to zero * (since we want to have the derivative at alpha = 0, i.e. for the current design) ---*/ - - for (iDV = 0; iDV < nDV; iDV++){ - nDV_Value = config->GetnDV_Value(iDV); - - for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ - - /*--- Initilization with su2double resets the index ---*/ - - DV_Value = 0.0; + for (iDV_Value = 0; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++){ - AD::RegisterInput(DV_Value); + config->SetDV_Value(iDV, iDV_Value, 0.0); - config->SetDV_Value(iDV, iDV_Value, DV_Value); + AD::RegisterInput(config->GetDV_Value(iDV, iDV_Value)); } } From 31c969e16507ae80d69105ea8c9190071d54a08d Mon Sep 17 00:00:00 2001 From: patelha57 Date: Tue, 22 Jun 2021 17:40:55 -0400 Subject: [PATCH 010/598] Simplify cfd and cfd_ad library links --- SU2_DEF/src/meson.build | 67 ++--------------------------------------- 1 file changed, 2 insertions(+), 65 deletions(-) diff --git a/SU2_DEF/src/meson.build b/SU2_DEF/src/meson.build index ecd2c2faf86..f7edd9f0a19 100644 --- a/SU2_DEF/src/meson.build +++ b/SU2_DEF/src/meson.build @@ -6,44 +6,7 @@ su2_def_src = files([ ]) if get_option('enable-normal') -su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', - 'solvers/CBaselineSolver.cpp', - 'solvers/CMeshSolver.cpp', - 'solvers/CFEASolver.cpp', - 'numerics/CNumerics.cpp', - 'numerics/elasticity/CFEAElasticity.cpp', - 'numerics/elasticity/CFEALinearElasticity.cpp', - 'CMarkerProfileReaderFVM.cpp', - 'output/COutput.cpp', - 'output/tools/CWindowingTools.cpp', - 'output/CMeshOutput.cpp', - 'output/output_structure_legacy.cpp', - 'output/CBaselineOutput.cpp', - 'variables/CBaselineVariable.cpp', - 'variables/CVariable.cpp', - 'variables/CFEAVariable.cpp', - 'variables/CFEABoundVariable.cpp', - 'variables/CMeshElement.cpp', - 'variables/CMeshVariable.cpp', - 'variables/CMeshBoundVariable.cpp', - 'output/filewriter/CParallelDataSorter.cpp', - 'output/filewriter/CFVMDataSorter.cpp', - 'output/filewriter/CFEMDataSorter.cpp', - 'output/filewriter/CSurfaceFEMDataSorter.cpp', - 'output/filewriter/CSurfaceFVMDataSorter.cpp', - 'output/filewriter/CParallelFileWriter.cpp', - 'output/filewriter/CParaviewFileWriter.cpp', - 'output/filewriter/CParaviewBinaryFileWriter.cpp', - 'output/filewriter/CTecplotFileWriter.cpp', - 'output/filewriter/CTecplotBinaryFileWriter.cpp', - 'output/filewriter/CCSVFileWriter.cpp', - 'output/filewriter/CSTLFileWriter.cpp', - 'output/filewriter/CSU2FileWriter.cpp', - 'output/filewriter/CSU2BinaryFileWriter.cpp', - 'output/filewriter/CParaviewXMLFileWriter.cpp', - 'output/filewriter/CParaviewVTMFileWriter.cpp', - 'output/filewriter/CSU2MeshFileWriter.cpp', - 'limiters/CLimiterDetails.cpp']) +su2_cfd_obj = su2_cfd_lib.extract_all_objects() su2_def_lib = static_library('SU2core_DEF', su2_def_src, @@ -63,33 +26,7 @@ su2_cfd_obj = su2_cfd_lib.extract_objects(['solvers/CSolver.cpp', endif if get_option('enable-autodiff') -su2_cfd_obj_ad = su2_cfd_lib_ad.extract_objects(['solvers/CSolver.cpp', - 'solvers/CBaselineSolver.cpp', - 'CMarkerProfileReaderFVM.cpp', - 'output/COutput.cpp', - 'output/tools/CWindowingTools.cpp', - 'output/output_structure_legacy.cpp', - 'output/CBaselineOutput.cpp', - 'output/filewriter/CParallelDataSorter.cpp', - 'output/filewriter/CParallelFileWriter.cpp', - 'output/filewriter/CFEMDataSorter.cpp', - 'output/filewriter/CSurfaceFEMDataSorter.cpp', - 'output/filewriter/CFVMDataSorter.cpp', - 'output/filewriter/CSurfaceFVMDataSorter.cpp', - 'output/filewriter/CCSVFileWriter.cpp', - 'output/filewriter/CSTLFileWriter.cpp', - 'output/filewriter/CTecplotFileWriter.cpp', - 'output/filewriter/CTecplotBinaryFileWriter.cpp', - 'output/filewriter/CParaviewFileWriter.cpp', - 'output/filewriter/CParaviewBinaryFileWriter.cpp', - 'output/filewriter/CSU2FileWriter.cpp', - 'output/filewriter/CSU2BinaryFileWriter.cpp', - 'output/filewriter/CSU2MeshFileWriter.cpp', - 'output/filewriter/CParaviewXMLFileWriter.cpp', - 'output/filewriter/CParaviewVTMFileWriter.cpp', - 'variables/CBaselineVariable.cpp', - 'variables/CVariable.cpp', - 'limiters/CLimiterDetails.cpp']) +su2_cfd_obj_ad = su2_cfd_lib_ad.extract_all_objects() su2_def_lib_ad = static_library('SU2core_DEF_AD', su2_def_src, From fd959313969af95c06b6057f003bcdd9869ed447 Mon Sep 17 00:00:00 2001 From: Harsh Patel <51417692+patelha57@users.noreply.github.com> Date: Mon, 28 Jun 2021 10:55:13 -0400 Subject: [PATCH 011/598] Remove redundant nullptr in CDeformationDriver Co-authored-by: Pedro Gomes <38071223+pcarruscag@users.noreply.github.com> --- SU2_DEF/src/drivers/CDeformationDriver.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 8c8155dfaa5..c95c45493be 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -54,7 +54,6 @@ CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) strcpy(config_file_name, confFile); /*--- Initialize the configuration of the driver ---*/ - driver_config = nullptr; driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); nZone = driver_config->GetnZone(); From 90dbc0da26f37b22be01723b9cc4e96e5ad10da4 Mon Sep 17 00:00:00 2001 From: aa-g Date: Tue, 25 Jan 2022 17:55:31 +0100 Subject: [PATCH 012/598] Merge develop --- externals/meson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/meson b/externals/meson index 41c650a040d..29ef4478df6 160000 --- a/externals/meson +++ b/externals/meson @@ -1 +1 @@ -Subproject commit 41c650a040d50e0912d268af7a903a9ce1456dfa +Subproject commit 29ef4478df6d3aaca40c7993f125b29409be1de2 From 1e2b91fe7c099a9587bf2df958d4702d83ce76ef Mon Sep 17 00:00:00 2001 From: patelha57 Date: Sun, 13 Feb 2022 23:34:48 -0800 Subject: [PATCH 013/598] Updates for PR1300 --- Common/include/drivers/CDriverBase.hpp | 343 ++++ Common/src/drivers/CDriverBase.cpp | 547 ++++++ Common/src/drivers/meson.build | 1 + Common/src/meson.build | 1 + SU2_CFD/include/drivers/CDriver.hpp | 1661 ++++++++--------- SU2_CFD/src/drivers/CDriver.cpp | 3 +- SU2_CFD/src/python_wrapper_structure.cpp | 197 -- .../include/drivers/CDeformationDriver.hpp | 115 +- .../drivers/CDiscAdjDeformationDriver.hpp | 225 +-- SU2_DEF/src/drivers/CDeformationDriver.cpp | 1092 +++++------ .../src/drivers/CDiscAdjDeformationDriver.cpp | 1395 +++++++------- SU2_DOT/include/SU2_DOT.hpp | 69 +- SU2_DOT/src/SU2_DOT.cpp | 1060 +---------- SU2_PY/pySU2/pySU2.i | 1 + SU2_PY/pySU2/pySU2ad.i | 1 + 15 files changed, 3035 insertions(+), 3676 deletions(-) create mode 100644 Common/include/drivers/CDriverBase.hpp create mode 100644 Common/src/drivers/CDriverBase.cpp create mode 100644 Common/src/drivers/meson.build diff --git a/Common/include/drivers/CDriverBase.hpp b/Common/include/drivers/CDriverBase.hpp new file mode 100644 index 00000000000..7291411e397 --- /dev/null +++ b/Common/include/drivers/CDriverBase.hpp @@ -0,0 +1,343 @@ +/*! + * \file CDriverBase.hpp + * \brief Base class template for all drivers. + * \author H. Patel, A. Gastaldi + * \version 7.3.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include "../CConfig.hpp" +#include "../../../SU2_CFD/include/numerics/CNumerics.hpp" +#include "../../../SU2_CFD/include/solvers/CSolver.hpp" +#include "../../../SU2_CFD/include/output/COutput.hpp" + +class CDriverBase { + +protected: + + int rank, /*!< \brief MPI Rank. */ + size; /*!< \brief MPI Size. */ + char* config_file_name; /*!< \brief Configuration file name of the problem.*/ + + su2double StartTime, /*!< \brief Start point of the timer for performance benchmarking.*/ + StopTime, /*!< \brief Stop point of the timer for performance benchmarking.*/ + UsedTimePreproc, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking preprocessing phase.*/ + UsedTimeCompute, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking compute phase.*/ + UsedTime; /*!< \brief Elapsed time between Start and Stop point of the timer.*/ + + unsigned long TimeIter; + + unsigned short iMesh, /*!< \brief Iterator on mesh levels.*/ + iZone, /*!< \brief Iterator on zones.*/ + nZone, /*!< \brief Total number of zones in the problem. */ + nDim, /*!< \brief Number of dimensions.*/ + iInst, /*!< \brief Iterator on instance levels.*/ + *nInst, /*!< \brief Total number of instances in the problem (per zone). */ + **interface_types; /*!< \brief Type of coupling between the distinct (physical) zones.*/ + + CConfig **config_container; /*!< \brief Definition of the particular problem. */ + CConfig *driver_config; /*!< \brief Definition of the driver configuration. */ + COutput **output_container; /*!< \brief Pointer to the COutput class. */ + COutput *driver_output; /*!< \brief Definition of the driver output. */ + CGeometry ****geometry_container; /*!< \brief Geometrical definition of the problem. */ + CSolver *****solver_container; /*!< \brief Container vector with all the solutions. */ + CNumerics ******numerics_container; /*!< \brief Description of the numerical method (the way in which the equations are solved). */ + CSurfaceMovement **surface_movement; /*!< \brief Surface movement classes of the problem. */ + CVolumetricMovement ***grid_movement; /*!< \brief Volume grid movement classes of the problem. */ + CFreeFormDefBox*** FFDBox; /*!< \brief FFD FFDBoxes of the problem. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] val_nZone - Total number of zones. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CDriverBase(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator); + + /*! + * \brief Destructor of the class. + */ + ~CDriverBase(void); + + /*! + * \brief A virtual member. + */ + virtual void Preprocessing() {}; + + /*! + * \brief A virtual member. + */ + virtual void Run() {}; + + /*! + * \brief A virtual member. + */ + virtual void Update() {}; + + /*! + * \brief A virtual member. + */ + virtual void Update_Legacy() {}; + + /*! + * \brief A virtual member. + */ + virtual void Output() {}; + + /*! + * \brief A virtual member. + */ + virtual void Postprocessing() {}; + + /*! + * \brief Get all the boundary markers tags with their associated indices. + * \return List of boundary markers tags with their indices. + */ + map GetBoundaryMarkerIndices() const; + + /*! + * \brief Get all the boundary markers tags with their associated types. + * \return List of boundary markers tags with their types. + */ + map GetBoundaryMarkerTypes() const; + + /*! + * \brief Get all the deformable boundary marker tags. + * \return List of deformable boundary markers tags. + */ + vector GetDeformableMarkerTags() const; + + /*! + * \brief Get the number of mesh dimensions. + * \return Number of dimensions. + */ + unsigned long GetNumberDimensions() const; + + /*! + * \brief Get the number of mesh elements. + * \return Number of elements. + */ + unsigned long GetNumberElements() const; + + /*! + * \brief Get the number of mesh elements from a specified marker. + * \param[in] iMarker - Marker identifier. + * \return Number of elements. + */ + unsigned long GetNumberElementsMarker(unsigned short iMarker) const; + + /*! + * \brief Get the number of mesh vertices. + * \return Number of vertices. + */ + unsigned long GetNumberVertices() const; + + /*! + * \brief Get the number of mesh vertices from a specified marker. + * \param[in] iMarker - Marker identifier. + * \return Number of vertices. + */ + unsigned long GetNumberVerticesMarker(unsigned short iMarker) const; + + /*! + * \brief Get the number of halo mesh vertices. + * \return Number of vertices. + */ + unsigned long GetNumberHaloVertices() const; + + /*! + * \brief Get the number of halo mesh vertices from a specified marker. + * \param[in] iMarker - Marker identifier. + * \return Number of vertices. + */ + unsigned long GetNumberHaloVerticesMarker(unsigned short iMarker) const; + + /*! + * \brief Get global IDs of mesh vertices. + * \return Global vertex IDs. + */ + vector GetVertexIDs() const; + + /*! + * \brief Get global IDs of mesh vertices. + * \param[in] iMarker - Marker identifier. + * \return Global vertex IDs. + */ + vector GetVertexIDsMarker(unsigned short iMarker) const; + + /*! + * \brief Get global IDs of mesh elements. + * \return Global element IDs. + */ + vector GetElementIDs() const; + + /*! + * \brief Get global IDs of mesh elements. + * \param[in] iMarker - Marker identifier. + * \return Global element IDs. + */ + vector GetElementIDsMarker(unsigned short iMarker) const; + + /*! + * \brief Get the connected point IDs of mesh elements. + * \return Element connectivities (nElem, nNode) + */ + vector> GetConnectivity() const; + + /*! + * \brief Get the connected point IDs of mesh elements on a specified marker. + * \param[in] iMarker - Marker identifier. + * \return Element connectivities (nBound, nNode). + */ + vector> GetConnectivityMarker(unsigned short iMarker) const; + + /*! + * \brief Get halo node stauts of mesh vertices. + * \return Point domain status. + */ + vector GetDomain() const; + + /*! + * \brief Get halo node stauts of mesh marker vertices. + * \param[in] iMarker - Marker identifier. + * \return Point domain status. + */ + vector GetDomainMarker(unsigned short iMarker) const; + + /*! + * \brief Get the coordinates of the mesh points. + * \return Point coordinates (nPoint*nDim). + */ + vector GetCoordinates() const; + + /*! + * \brief Get the coordinates of the mesh points on the specified marker. + * \param[in] iMarker - Marker identifier. + * \return Point coordinates (nVertex*nDim). + */ + vector GetCoordinatesMarker(unsigned short iMarker) const; + + /*! + * \brief Set the coordinates of the mesh points. + * \param[in] values - Point coordinates (nPoint*nDim). + */ + void SetCoordinates(vector values); + + /*! + * \brief Set the coordinates of the mesh points on the specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] values - Point coordinates (nVertex*nDim). + */ + void SetCoordinatesMarker(unsigned short iMarker, vector values); + + /*! + * \brief Get the vertex displacements on the specified marker. + * \param[in] iMarker - Marker identifier. + * \return Vertex displacements (nVertex*nDim). + */ + vector GetDisplacementsMarker(unsigned short iMarker) const; + + /*! + * \brief Set the vertex displacements on the specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] values - Vertex displacements (nVertex*nDim). + */ + void SetDisplacementsMarker(unsigned short iMarker, vector values); + + /*! + * \brief Get the vertex velocities on the specified marker. + * \param[in] iMarker - Marker identifier. + * \return Vertex velocities (nVertex*nDim). + */ + vector GetVelocitiesMarker(unsigned short iMarker) const; + + /*! + * \brief Set the vertex velocities on the specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] values - Vertex velocities (nVertex*nDim). + */ + void SetVelocitiesMarker(unsigned short iMarker, vector values); + + /*! + * \brief Get undeformed coordinates from mesh solver on the specified marker. + * \param[in] iMarker - Marker identifier. + * \return Initial point coordinates (nVertex*nDim). + */ + vector GetInitialCoordinatesMarker(unsigned short iMarker) const; + + /*! + * \brief Get the vertex normal vectors on the specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] UnitNormal - Boolean to indicate if unit normal vector should be returned. + * \return Normal vector at the vertex (nVertex*nDim). + */ + vector GetVertexNormalsMarker(unsigned short iMarker, bool UnitNormal = false) const; + + /*! + * \brief Communicate the boundary mesh displacements in a python call + */ + void CommunicateMeshDisplacements(void); + +protected: + + /*! + * \brief Initialize Containers + */ + void SetContainers_Null(); + + /*! + * \brief Read in the config and mesh files. + */ + void Input_Preprocessing(CConfig **&config, CConfig *&driver_config); + + /*! + * \brief Construction of the edge-based data structure and the multigrid structure. + */ + void Geometrical_Preprocessing(CConfig *config, CGeometry **&geometry, bool dummy); + + /*! + * \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(CConfig *config, CGeometry **geometry, CSolver ***&solver); + + /*! + * \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] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + */ + void Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSolver ***solver, CNumerics ****&numerics) const; + + /*! + * \brief Preprocess the output container. + */ + void Output_Preprocessing(CConfig **config, CConfig *driver_config, COutput **&output_container, COutput *&driver_output); + +}; diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp new file mode 100644 index 00000000000..094113173ec --- /dev/null +++ b/Common/src/drivers/CDriverBase.cpp @@ -0,0 +1,547 @@ +/*! + * \file CDriverBase.hpp + * \brief Base class template for all drivers. + * \author H. Patel, A. Gastaldi + * \version 7.3.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser/ General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../include/drivers/CDriverBase.hpp" + +#include "../../include/geometry/CPhysicalGeometry.hpp" +#include "../../include/toolboxes/geometry_toolbox.hpp" + +using namespace std; + +CDriverBase::CDriverBase(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator): + config_file_name(confFile), + StartTime(0.0), + StopTime(0.0), + UsedTime(0.0), + TimeIter(0), + nZone() +{ + +} + +CDriverBase::~CDriverBase(void) { + +} + +void CDriverBase::SetContainers_Null() { + + /*--- Create pointers to all of the classes that may be used by drivers. In general, the pointers are instantiated down a + hierarchy over all zones, multigrid levels, equation sets, and equation + terms as described in the comments below. ---*/ + + nInst = nullptr; + + config_container = nullptr; + output_container = nullptr; + geometry_container = nullptr; + solver_container = nullptr; + numerics_container = nullptr; + + surface_movement = nullptr; + grid_movement = nullptr; + FFDBox = nullptr; + + nInst = new unsigned short[nZone] (); + + config_container = new CConfig*[nZone] (); + output_container = new COutput*[nZone] (); + geometry_container = new CGeometry***[nZone] (); + solver_container = new CSolver****[nZone] (); + numerics_container = new CNumerics*****[nZone] (); + + surface_movement = new CSurfaceMovement*[nZone] (); + grid_movement = new CVolumetricMovement**[nZone] (); + FFDBox = new CFreeFormDefBox**[nZone] (); + + driver_config = nullptr; + driver_output = nullptr; + + for (iZone = 0; iZone < nZone; iZone++) { + nInst[iZone] = 1; + } +} + +map CDriverBase::GetBoundaryMarkerIndices() const { + CConfig* config = config_container[ZONE_0]; + + const auto nBoundaryMarkers = config->GetnMarker_All(); + map allBoundariesMap; + + for (auto iMarker = 0u; iMarker < nBoundaryMarkers; iMarker++) { + auto Marker_Tag = config->GetMarker_All_TagBound(iMarker); + allBoundariesMap[Marker_Tag] = iMarker; + } + + return allBoundariesMap; +} + +map CDriverBase::GetBoundaryMarkerTypes() const { + CConfig* config = config_container[ZONE_0]; + + map allBoundariesTypeMap; + string Marker_Type; + + for (auto iMarker = 0u; iMarker < config->GetnMarker_All(); iMarker++) { + auto Marker_Tag = config->GetMarker_All_TagBound(iMarker); + auto KindBC = config->GetMarker_All_KindBC(iMarker); + + switch(KindBC) { + case EULER_WALL: + Marker_Type = "EULER_WALL"; + break; + case FAR_FIELD: + Marker_Type = "FARFIELD"; + break; + case ISOTHERMAL: + Marker_Type = "ISOTHERMAL"; + break; + case HEAT_FLUX: + Marker_Type = "HEATFLUX"; + break; + case INLET_FLOW: + Marker_Type = "INLET_FLOW"; + break; + case OUTLET_FLOW: + Marker_Type = "OUTLET_FLOW"; + break; + case SYMMETRY_PLANE: + Marker_Type = "SYMMETRY"; + break; + case SEND_RECEIVE: + Marker_Type = "SEND_RECEIVE"; + break; + default: + Marker_Type = "UNKNOWN_TYPE"; + } + allBoundariesTypeMap[Marker_Tag] = Marker_Type; + } + + return allBoundariesTypeMap; +} + +vector CDriverBase::GetDeformableMarkerTags() const { + CConfig* config = config_container[ZONE_0]; + + const auto nBoundariesMarker = config->GetnMarker_Deform_Mesh(); + vector interfaceBoundariesTagList; + + interfaceBoundariesTagList.resize(nBoundariesMarker); + + for (auto iMarker = 0u; iMarker < nBoundariesMarker; iMarker++) { + auto Marker_Tag = config->GetMarker_Deform_Mesh_TagBound(iMarker); + interfaceBoundariesTagList[iMarker] = Marker_Tag; + } + + return interfaceBoundariesTagList; +} + +unsigned long CDriverBase::GetNumberDimensions() const { + return geometry_container[ZONE_0][INST_0][MESH_0]->GetnDim(); +} + +unsigned long CDriverBase::GetNumberElements() const { + return geometry_container[ZONE_0][INST_0][MESH_0]->GetnElem(); +} + +unsigned long CDriverBase::GetNumberElementsMarker(unsigned short iMarker) const { + return geometry_container[ZONE_0][INST_0][MESH_0]->GetnElem_Bound(iMarker); +} + +unsigned long CDriverBase::GetNumberVertices() const { + return geometry_container[ZONE_0][INST_0][MESH_0]->GetnPoint(); +} + +unsigned long CDriverBase::GetNumberVerticesMarker(unsigned short iMarker) const { + return geometry_container[ZONE_0][INST_0][MESH_0]->GetnVertex(iMarker); +} + +unsigned long CDriverBase::GetNumberHaloVertices() const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nPoint = geometry->GetnPoint(); + unsigned long nHaloVertices = 0; + + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + if (!(geometry->nodes->GetDomain(iPoint))) { + nHaloVertices += 1; + } + } + + return nHaloVertices; +} + +unsigned long CDriverBase::GetNumberHaloVerticesMarker(unsigned short iMarker) const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nVertex = geometry->GetnVertex(iMarker); + unsigned long nHaloVertices = 0; + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (!(geometry->nodes->GetDomain(iPoint))) { + nHaloVertices += 1; + } + } + + return nHaloVertices; +} + +vector CDriverBase::GetVertexIDs() const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nPoint = geometry->GetnPoint(); + vector values; + + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + values.push_back(geometry->nodes->GetGlobalIndex(iPoint)); + } + + return values; +} + +vector CDriverBase::GetVertexIDsMarker(unsigned short iMarker) const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nVertex = geometry->GetnVertex(iMarker); + vector values; + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + values.push_back(geometry->nodes->GetGlobalIndex(iPoint)); + } + + return values; +} + +vector CDriverBase::GetElementIDs() const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nElem = geometry->GetnElem(); + vector values; + + for (auto iElem = 0ul; iElem < nElem; iElem++) { + values.push_back(geometry->elem[iElem]->GetGlobalIndex()); + } + + return values; +} + +vector CDriverBase::GetElementIDsMarker(unsigned short iMarker) const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nBound = geometry->GetnElem_Bound(iMarker); + vector values; + + for (auto iBound = 0ul; iBound < nBound; iBound++) { + values.push_back(geometry->bound[iMarker][iBound]->GetGlobalIndex()); + } + + return values; +} + +vector> CDriverBase::GetConnectivity() const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nElem = geometry->GetnElem(); + vector> values(nElem); + + for (auto iElem = 0ul; iElem < nElem; iElem++) { + unsigned short nNode = geometry->elem[iElem]->GetnNodes(); + + for (auto iNode = 0u; iNode < nNode; iNode++) { + values[iElem].push_back(geometry->elem[iElem]->GetNode(iNode)); + } + } + + return values; +} + +vector> CDriverBase::GetConnectivityMarker(unsigned short iMarker) const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nBound = geometry->GetnElem_Bound(iMarker); + vector> values(nBound); + + for (auto iBound = 0ul; iBound < nBound; iBound++) { + unsigned short nNode = geometry->bound[iMarker][iBound]->GetnNodes(); + + for (auto iNode = 0u; iNode < nNode; iNode++) { + values[iBound].push_back(geometry->bound[iMarker][iBound]->GetNode(iNode)); + } + } + + return values; +} + +vector CDriverBase::GetDomain() const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nPoint = geometry->GetnPoint(); + vector values(nPoint); + + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + values.push_back(geometry->nodes->GetDomain(iPoint)); + } + + return values; +} + +vector CDriverBase::GetDomainMarker(unsigned short iMarker) const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nVertex = geometry->GetnVertex(iMarker); + vector values(nVertex); + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + values.push_back(geometry->nodes->GetDomain(iPoint)); + } + + return values; +} + +vector CDriverBase::GetCoordinates() const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nPoint = geometry->GetnPoint(); + vector values(nPoint*nDim, 0.0); + su2double value; + + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + for (auto iDim = 0u; iDim < nDim; iDim++) { + value = geometry->nodes->GetCoord(iPoint, iDim); + values[iPoint*nDim + iDim] = SU2_TYPE::GetValue(value); + } + } + + return values; +} + +vector CDriverBase::GetCoordinatesMarker(unsigned short iMarker) const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nVertex = geometry->GetnVertex(iMarker); + vector values(nVertex*nDim, 0.0); + su2double value; + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + value = geometry->nodes->GetCoord(iPoint, iDim); + values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(value); + } + } + + return values; +} + +void CDriverBase::SetCoordinates(vector values) { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nPoint = geometry->GetnPoint(); + if (values.size() != nPoint*nDim) { + SU2_MPI::Error("Size does not match nPoint * nDim!", CURRENT_FUNCTION); + } + + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + for (auto iDim = 0u; iDim < nDim; iDim++) { + geometry->nodes->SetCoord(iPoint, iDim, values[iPoint*nDim + iDim]); + } + } +} + +void CDriverBase::SetCoordinatesMarker(unsigned short iMarker, vector values) { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nVertex = geometry->GetnVertex(iMarker); + if (values.size() != nVertex*nDim) { + SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); + } + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + geometry->nodes->SetCoord(iPoint, iDim, values[iVertex*nDim + iDim]); + } + } +} + +vector CDriverBase::GetDisplacementsMarker(unsigned short iMarker) const { + CConfig* config = config_container[ZONE_0]; + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; + + if (!config->GetDeform_Mesh()) { + return {}; + } + + const auto nVertex = geometry->GetnVertex(iMarker); + vector values(nVertex*nDim, 0.0); + su2double value; + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + value = solver->GetNodes()->GetBound_Disp(iPoint, iDim); + values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(value); + } + } + + return values; +} + +void CDriverBase::SetDisplacementsMarker(unsigned short iMarker, vector values) { + CConfig* config = config_container[ZONE_0]; + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; + + if (!config->GetDeform_Mesh()) { + SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + } + + const auto nVertex = geometry->GetnVertex(iMarker); + if (values.size() != nVertex*nDim) { + SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); + } + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + solver->GetNodes()->SetBound_Disp(iPoint, iDim, values[iVertex*nDim + iDim]); + } + } +} + +vector CDriverBase::GetVelocitiesMarker(unsigned short iMarker) const { + CConfig* config = config_container[ZONE_0]; + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; + + if (!config->GetDeform_Mesh()) { + return {}; + } + + const auto nVertex = geometry->GetnVertex(iMarker); + vector values(nVertex*nDim, 0.0); + su2double value; + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + value = solver->GetNodes()->GetBound_Vel(iPoint, iDim); + values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(value); + } + } + + return values; +} + +void CDriverBase::SetVelocitiesMarker(unsigned short iMarker, vector values) { + CConfig* config = config_container[ZONE_0]; + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; + + if (!config->GetDeform_Mesh()) { + SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + } + + const auto nVertex = geometry->GetnVertex(iMarker); + if (values.size() != nVertex*nDim) { + SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); + } + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + solver->GetNodes()->SetBound_Vel(iPoint, iDim, values[iVertex*nDim + iDim]); + } + } +} + +vector CDriverBase::GetInitialCoordinatesMarker(unsigned short iMarker) const { + CConfig* config = config_container[ZONE_0]; + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; + + if (!config->GetDeform_Mesh()) { + return {}; + } + + const auto nVertex = geometry->GetnVertex(iMarker); + vector values(nVertex*nDim, 0.0); + su2double value; + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + value = solver->GetNodes()->GetMesh_Coord(iPoint, iDim); + values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(value); + } + } + + return values; +} + +vector CDriverBase::GetVertexNormalsMarker(unsigned short iMarker, bool UnitNormal) const { + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + const auto nVertex = geometry->GetnVertex(iMarker); + vector values(nVertex*nDim, 0.0); + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + auto Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + auto Area = GeometryToolbox::Norm(nDim, Normal); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + if (!UnitNormal) { + values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(Normal[iDim]); + } else { + values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(Normal[iDim]/Area); + } + } + } + + return values; +} + +void CDriverBase::CommunicateMeshDisplacements(void) { + CConfig* config = config_container[ZONE_0]; + CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; + + solver->InitiateComms(geometry, config, MESH_DISPLACEMENTS); + solver->CompleteComms(geometry, config, MESH_DISPLACEMENTS); +} diff --git a/Common/src/drivers/meson.build b/Common/src/drivers/meson.build new file mode 100644 index 00000000000..bcee2ba35cb --- /dev/null +++ b/Common/src/drivers/meson.build @@ -0,0 +1 @@ +common_src += files(['CDriverBase.cpp']) diff --git a/Common/src/meson.build b/Common/src/meson.build index b3e0726e70c..4902f8bf9ab 100644 --- a/Common/src/meson.build +++ b/Common/src/meson.build @@ -13,6 +13,7 @@ subdir('geometry/elements') subdir('geometry/dual_grid') subdir('geometry/primal_grid') subdir('geometry/meshreader') +subdir('drivers') subdir('interface_interpolation') subdir('fem') subdir('grid_movement') diff --git a/SU2_CFD/include/drivers/CDriver.hpp b/SU2_CFD/include/drivers/CDriver.hpp index 7f27dab3bbe..32843db8c50 100644 --- a/SU2_CFD/include/drivers/CDriver.hpp +++ b/SU2_CFD/include/drivers/CDriver.hpp @@ -1,4 +1,4 @@ -/*! +/*! * \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. @@ -35,6 +35,7 @@ #include "../interfaces/CInterface.hpp" #include "../../../Common/include/geometry/CGeometry.hpp" +#include "../../../Common/include/drivers/CDriverBase.hpp" using namespace std; @@ -48,739 +49,629 @@ class COutput; * \brief Parent class for driving an iteration of a single or multi-zone problem. * \author T. Economon */ -class CDriver { -protected: - int rank, /*!< \brief MPI Rank. */ - size; /*!< \brief MPI Size. */ - char* config_file_name; /*!< \brief Configuration file name of the problem.*/ - char runtime_file_name[MAX_STRING_SIZE]; - su2double StartTime, /*!< \brief Start point of the timer for performance benchmarking.*/ - StopTime, /*!< \brief Stop point of the timer for performance benchmarking.*/ - UsedTimePreproc, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking preprocessing phase.*/ - UsedTimeCompute, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking compute phase.*/ - UsedTimeOutput, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking output phase.*/ - UsedTime; /*!< \brief Elapsed time between Start and Stop point of the timer.*/ - su2double BandwidthSum = 0.0; /*!< \brief Aggregate value of the bandwidth for writing restarts (to be average later).*/ - unsigned long IterCount, /*!< \brief Iteration count stored for performance benchmarking.*/ - OutputCount; /*!< \brief Output count stored for performance benchmarking.*/ - unsigned long DOFsPerPoint; /*!< \brief Number of unknowns at each vertex, i.e., number of equations solved. */ - su2double Mpoints; /*!< \brief Total number of grid points in millions in the calculation (including ghost points).*/ - su2double MpointsDomain; /*!< \brief Total number of grid points in millions in the calculation (excluding ghost points).*/ - su2double MDOFs; /*!< \brief Total number of DOFs in millions in the calculation (including ghost points).*/ - su2double MDOFsDomain; /*!< \brief Total number of DOFs in millions in the calculation (excluding ghost points).*/ - unsigned long TimeIter; /*!< \brief External iteration.*/ - ofstream **ConvHist_file; /*!< \brief Convergence history file.*/ - ofstream FSIHist_file; /*!< \brief FSI convergence history file.*/ - unsigned short iMesh, /*!< \brief Iterator on mesh levels.*/ - iZone, /*!< \brief Iterator on zones.*/ - nZone, /*!< \brief Total number of zones in the problem. */ - nDim, /*!< \brief Number of dimensions.*/ - iInst, /*!< \brief Iterator on instance levels.*/ - *nInst, /*!< \brief Total number of instances in the problem (per zone). */ - **interface_types; /*!< \brief Type of coupling between the distinct (physical) zones.*/ - bool StopCalc, /*!< \brief Stop computation flag.*/ - mixingplane, /*!< \brief mixing-plane simulation flag.*/ - fsi, /*!< \brief FSI simulation flag.*/ - fem_solver; /*!< \brief FEM fluid solver simulation flag. */ - CIteration ***iteration_container; /*!< \brief Container vector with all the iteration methods. */ - COutput **output_container; /*!< \brief Pointer to the COutput class. */ - CIntegration ****integration_container; /*!< \brief Container vector with all the integration methods. */ - CGeometry ****geometry_container; /*!< \brief Geometrical definition of the problem. */ - CSolver *****solver_container; /*!< \brief Container vector with all the solutions. */ - CNumerics ******numerics_container; /*!< \brief Description of the numerical method (the way in which the equations are solved). */ - CConfig **config_container; /*!< \brief Definition of the particular problem. */ - CConfig *driver_config; /*!< \brief Definition of the driver configuration. */ - COutput *driver_output; /*!< \brief Definition of the driver output. */ - CSurfaceMovement **surface_movement; /*!< \brief Surface movement classes of the problem. */ - CVolumetricMovement ***grid_movement; /*!< \brief Volume grid movement classes of the problem. */ - CFreeFormDefBox*** FFDBox; /*!< \brief FFD FFDBoxes of the problem. */ - vector > > - interpolator_container; /*!< \brief Definition of the interpolation method between non-matching discretizations of the interface. */ - CInterface ***interface_container; /*!< \brief Definition of the interface of information and physics. */ - bool dry_run; /*!< \brief Flag if SU2_CFD was started as dry-run via "SU2_CFD -d .cfg" */ +class CDriver : public CDriverBase { + +protected: + + char runtime_file_name[MAX_STRING_SIZE]; + su2double UsedTimeOutput; /*!< \brief Elapsed time between Start and Stop point of the timer for tracking output phase.*/ + + su2double BandwidthSum = 0.0; /*!< \brief Aggregate value of the bandwidth for writing restarts (to be average later).*/ + unsigned long IterCount, /*!< \brief Iteration count stored for performance benchmarking.*/ + OutputCount; /*!< \brief Output count stored for performance benchmarking.*/ + unsigned long DOFsPerPoint; /*!< \brief Number of unknowns at each vertex, i.e., number of equations solved. */ + su2double Mpoints; /*!< \brief Total number of grid points in millions in the calculation (including ghost points).*/ + su2double MpointsDomain; /*!< \brief Total number of grid points in millions in the calculation (excluding ghost points).*/ + su2double MDOFs; /*!< \brief Total number of DOFs in millions in the calculation (including ghost points).*/ + su2double MDOFsDomain; /*!< \brief Total number of DOFs in millions in the calculation (excluding ghost points).*/ + + ofstream **ConvHist_file; /*!< \brief Convergence history file.*/ + ofstream FSIHist_file; /*!< \brief FSI convergence history file.*/ + + bool StopCalc, /*!< \brief Stop computation flag.*/ + mixingplane, /*!< \brief mixing-plane simulation flag.*/ + fsi, /*!< \brief FSI simulation flag.*/ + fem_solver; /*!< \brief FEM fluid solver simulation flag. */ + + CIteration ***iteration_container; /*!< \brief Container vector with all the iteration methods. */ + CIntegration ****integration_container; /*!< \brief Container vector with all the integration methods. */ + vector > > + interpolator_container; /*!< \brief Definition of the interpolation method between non-matching discretizations of the interface. */ + CInterface ***interface_container; /*!< \brief Definition of the interface of information and physics. */ + bool dry_run; /*!< \brief Flag if SU2_CFD was started as dry-run via "SU2_CFD -d .cfg" */ + public: - - /*! - * \brief Constructor of the class. - * \param[in] confFile - Configuration file name. - * \param[in] val_nZone - Total number of zones. - * \param[in] val_nDim - Number of dimensions. - * \param[in] MPICommunicator - MPI communicator for SU2. - */ - CDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator, bool dummy_geo); - - /*! - * \brief Destructor of the class. - */ - virtual ~CDriver(void); - - /*! - * \brief A virtual member. - */ - virtual void Run() { }; - + + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] val_nZone - Total number of zones. + * \param[in] val_nDim - Number of dimensions. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CDriver(char* confFile, + unsigned short val_nZone, + SU2_Comm MPICommunicator, bool dummy_geo); + + /*! + * \brief Destructor of the class. + */ + virtual ~CDriver(void); + + /*! + * \brief A virtual member. + */ + virtual void Run() { }; + protected: - - /*! - * \brief Init_Containers - */ - void SetContainers_Null(); - - /*! - * \brief Read in the config and mesh files. - */ - void Input_Preprocessing(CConfig **&config, CConfig *&driver_config); - - /*! - * \brief Construction of the edge-based data structure and the multigrid structure. - */ - void Geometrical_Preprocessing(CConfig *config, CGeometry **&geometry, bool dummy); - - /*! - * \brief Do the geometrical preprocessing for the DG FEM solver. - */ - void Geometrical_Preprocessing_DGFEM(CConfig *config, CGeometry **&geometry); - - /*! - * \brief Geometrical_Preprocessing_FVM - */ - void Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geometry); - - /*! - * \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(CConfig *config, CIteration *&iteration) const; - - /*! - * \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(CConfig *config, CGeometry **geometry, CSolver ***&solver); - - /*! - * \brief Restart of the solvers from the restart files. - * \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_Restart(CSolver ***solver, CGeometry **geometry, CConfig *config, bool update_geo); - - /*! - * \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_Postprocessing(CSolver ****solver, CGeometry **geometry, CConfig *config, unsigned short val_iInst); - - /*! - * \brief Definition and allocation of all integration classes. - * \param[in] config - Definition of the particular problem. - * \param[in] solver - Container vector with all the solutions. - * \param[out] integration - Container vector with all the integration methods. - */ - void Integration_Preprocessing(CConfig *config, CSolver **solver, CIntegration **&integration) const; - - /*! - * \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_Postprocessing(CIntegration ***integration, CGeometry **geometry, CConfig *config, unsigned short val_iInst); - - /*! - * \brief Definition and allocation of all interface classes. - */ - void Interface_Preprocessing(CConfig **config, CSolver *****solver, CGeometry ****geometry, - unsigned short **interface_types, CInterface ***interface, - vector > > &interpolation); - - /*! - * \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] geometry - Geometrical definition of the problem. - * \param[in] solver_container - Container vector with all the solutions. - * \param[in] config - Definition of the particular problem. - */ - void Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSolver ***solver, CNumerics ****&numerics) const; - - /*! - * \brief Helper to instantiate turbulence numerics specialized for different flow solvers. - */ - template - void InstantiateTurbulentNumerics(unsigned short nVar_Turb, int offset, const CConfig *config, - const CSolver* turb_solver, CNumerics ****&numerics) const; - - /*! - * \brief Helper to instantiate species transport numerics specialized for different flow solvers. - */ - template - void InstantiateSpeciesNumerics(unsigned short nVar_Species, int offset, const CConfig *config, - const CSolver* species_solver, CNumerics ****&numerics) const; - - /*! - * \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_Postprocessing(CNumerics *****numerics, CSolver ***solver, CGeometry **geometry, CConfig *config, unsigned short val_iInst); - - /*! - * \brief GridMovement_Preprocessing - * \param config - * \param geometry - * \param solver - * \param iteration - * \param grid_movement - * \param surface_movement - */ - void DynamicMesh_Preprocessing(CConfig *config, CGeometry **geometry, CSolver ***solver, CIteration *iteration, CVolumetricMovement *&grid_movement, CSurfaceMovement *&surface_movement) const; - - /*! - * \brief Initialize Python interface functionalities - */ - void PythonInterface_Preprocessing(CConfig** config, CGeometry**** geometry, CSolver***** solver); - - /*! - * \brief Preprocess the output container. - */ - void Output_Preprocessing(CConfig **config, CConfig *driver_config, COutput **&output_container, COutput *&driver_output); - - /*! - * \brief Initiate value for static mesh movement such as the gridVel for the ROTATING frame. - */ - void StaticMesh_Preprocessing(const CConfig *config, CGeometry **geometry); - - /*! - * \brief Initiate value for static mesh movement such as the gridVel for the ROTATING frame. - */ - void Turbomachinery_Preprocessing(CConfig** config, CGeometry**** geometry, CSolver***** solver, - CInterface*** interface); - - /*! - * \brief A virtual member. - * \param[in] donorZone - zone in which the displacements will be predicted. - * \param[in] targetZone - zone which receives the predicted displacements. - */ - virtual void Predict_Displacements(unsigned short donorZone, unsigned short targetZone) {} - - /*! - * \brief A virtual member. - * \param[in] donorZone - zone in which the tractions will be predicted. - * \param[in] targetZone - zone which receives the predicted traction. - */ - virtual void Predict_Tractions(unsigned short donorZone, unsigned short targetZone) {} - - /*! - * \brief A virtual member. - * \param[in] donorZone - zone in which the displacements will be transferred. - * \param[in] targetZone - zone which receives the tractions transferred. - */ - virtual void Transfer_Displacements(unsigned short donorZone, unsigned short targetZone) {} - - /*! - * \brief A virtual member. - * \param[in] donorZone - zone from which the tractions will be transferred. - * \param[in] targetZone - zone which receives the tractions transferred. - */ - virtual void Transfer_Tractions(unsigned short donorZone, unsigned short targetZone) {} - - /*! - * \brief A virtual member. - * \param[in] donorZone - origin of the information. - * \param[in] targetZone - destination of the information. - * \param[in] iOuterIter - Fluid-Structure Interaction subiteration. - */ - virtual void Relaxation_Displacements(unsigned short donorZone, unsigned short targetZone, unsigned long iOuterIter) {} - - /*! - * \brief A virtual member. - * \param[in] donorZone - origin of the information. - * \param[in] targetZone - destination of the information. - * \param[in] iOuterIter - Fluid-Structure Interaction subiteration. - */ - virtual void Relaxation_Tractions(unsigned short donorZone, unsigned short targetZone, unsigned long iOuterIter) {} - - /*! - * \brief A virtual member to run a Block Gauss-Seidel iteration in multizone problems. - */ - virtual void Run_GaussSeidel(){} - - /*! - * \brief A virtual member to run a Block-Jacobi iteration in multizone problems. - */ - virtual void Run_Jacobi(){} - - /*! - * \brief A virtual member. - */ - virtual void Update() {} - - /*! - * \brief Print out the direct residuals. - * \param[in] kind_recording - Type of recording (full list in ENUM_RECORDING, option_structure.hpp) - */ - void Print_DirectResidual(RECORDING kind_recording); - + + /*! + * \brief Init_Containers + */ + void SetContainers_Null(); + + /*! + * \brief Read in the config and mesh files. + */ + void Input_Preprocessing(CConfig **&config, CConfig *&driver_config); + + /*! + * \brief Construction of the edge-based data structure and the multigrid structure. + */ + void Geometrical_Preprocessing(CConfig *config, CGeometry **&geometry, bool dummy); + + /*! + * \brief Do the geometrical preprocessing for the DG FEM solver. + */ + void Geometrical_Preprocessing_DGFEM(CConfig *config, CGeometry **&geometry); + + /*! + * \brief Geometrical_Preprocessing_FVM + */ + void Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geometry); + + /*! + * \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(CConfig *config, CIteration *&iteration) const; + + /*! + * \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(CConfig *config, CGeometry **geometry, CSolver ***&solver); + + /*! + * \brief Restart of the solvers from the restart files. + * \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_Restart(CSolver ***solver, CGeometry **geometry, CConfig *config, bool update_geo); + + /*! + * \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_Postprocessing(CSolver ****solver, CGeometry **geometry, CConfig *config, unsigned short val_iInst); + + /*! + * \brief Definition and allocation of all integration classes. + * \param[in] config - Definition of the particular problem. + * \param[in] solver - Container vector with all the solutions. + * \param[out] integration - Container vector with all the integration methods. + */ + void Integration_Preprocessing(CConfig *config, CSolver **solver, CIntegration **&integration) const; + + /*! + * \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_Postprocessing(CIntegration ***integration, CGeometry **geometry, CConfig *config, unsigned short val_iInst); + + /*! + * \brief Definition and allocation of all interface classes. + */ + void Interface_Preprocessing(CConfig **config, CSolver *****solver, CGeometry ****geometry, + unsigned short **interface_types, CInterface ***interface, + vector > > &interpolation); + + /*! + * \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] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + */ + void Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSolver ***solver, CNumerics ****&numerics) const; + + /*! + * \brief Helper to instantiate turbulence numerics specialized for different flow solvers. + */ + template + void InstantiateTurbulentNumerics(unsigned short nVar_Turb, int offset, const CConfig *config, + const CSolver* turb_solver, CNumerics ****&numerics) const; + + /*! + * \brief Helper to instantiate species transport numerics specialized for different flow solvers. + */ + template + void InstantiateSpeciesNumerics(unsigned short nVar_Species, int offset, const CConfig *config, + const CSolver* species_solver, CNumerics ****&numerics) const; + + /*! + * \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_Postprocessing(CNumerics *****numerics, CSolver ***solver, CGeometry **geometry, CConfig *config, unsigned short val_iInst); + + /*! + * \brief GridMovement_Preprocessing + * \param config + * \param geometry + * \param solver + * \param iteration + * \param grid_movement + * \param surface_movement + */ + void DynamicMesh_Preprocessing(CConfig *config, CGeometry **geometry, CSolver ***solver, CIteration *iteration, CVolumetricMovement *&grid_movement, CSurfaceMovement *&surface_movement) const; + + /*! + * \brief Initialize Python interface functionalities + */ + void PythonInterface_Preprocessing(CConfig** config, CGeometry**** geometry, CSolver***** solver); + + /*! + * \brief Preprocess the output container. + */ + void Output_Preprocessing(CConfig **config, CConfig *driver_config, COutput **&output_container, COutput *&driver_output); + + /*! + * \brief Initiate value for static mesh movement such as the gridVel for the ROTATING frame. + */ + void StaticMesh_Preprocessing(const CConfig *config, CGeometry **geometry); + + /*! + * \brief Initiate value for static mesh movement such as the gridVel for the ROTATING frame. + */ + void Turbomachinery_Preprocessing(CConfig** config, CGeometry**** geometry, CSolver***** solver, + CInterface*** interface); + + /*! + * \brief A virtual member. + * \param[in] donorZone - zone in which the displacements will be predicted. + * \param[in] targetZone - zone which receives the predicted displacements. + */ + virtual void Predict_Displacements(unsigned short donorZone, unsigned short targetZone) {} + + /*! + * \brief A virtual member. + * \param[in] donorZone - zone in which the tractions will be predicted. + * \param[in] targetZone - zone which receives the predicted traction. + */ + virtual void Predict_Tractions(unsigned short donorZone, unsigned short targetZone) {} + + /*! + * \brief A virtual member. + * \param[in] donorZone - zone in which the displacements will be transferred. + * \param[in] targetZone - zone which receives the tractions transferred. + */ + virtual void Transfer_Displacements(unsigned short donorZone, unsigned short targetZone) {} + + /*! + * \brief A virtual member. + * \param[in] donorZone - zone from which the tractions will be transferred. + * \param[in] targetZone - zone which receives the tractions transferred. + */ + virtual void Transfer_Tractions(unsigned short donorZone, unsigned short targetZone) {} + + /*! + * \brief A virtual member. + * \param[in] donorZone - origin of the information. + * \param[in] targetZone - destination of the information. + * \param[in] iOuterIter - Fluid-Structure Interaction subiteration. + */ + virtual void Relaxation_Displacements(unsigned short donorZone, unsigned short targetZone, unsigned long iOuterIter) {} + + /*! + * \brief A virtual member. + * \param[in] donorZone - origin of the information. + * \param[in] targetZone - destination of the information. + * \param[in] iOuterIter - Fluid-Structure Interaction subiteration. + */ + virtual void Relaxation_Tractions(unsigned short donorZone, unsigned short targetZone, unsigned long iOuterIter) {} + + /*! + * \brief A virtual member to run a Block Gauss-Seidel iteration in multizone problems. + */ + virtual void Run_GaussSeidel(){} + + /*! + * \brief A virtual member to run a Block-Jacobi iteration in multizone problems. + */ + virtual void Run_Jacobi(){} + + /*! + * \brief A virtual member. + */ + virtual void Update() {} + + /*! + * \brief Print out the direct residuals. + * \param[in] kind_recording - Type of recording (full list in ENUM_RECORDING, option_structure.hpp) + */ + void Print_DirectResidual(RECORDING kind_recording); + public: - - /*! - * \brief Launch the computation for all zones and all physics. - */ - virtual void StartSolver() {} - - /*! - * \brief Deallocation routine - */ - void Postprocessing(); - - /*! - * \brief A virtual member. - */ - virtual void ResetConvergence(); - - /*! - * \brief Perform some pre-processing before an iteration of the physics. - */ - virtual void Preprocess(unsigned long TimeIter){ } - - /*! - * \brief Monitor the computation. - */ - virtual bool Monitor(unsigned long TimeIter){ return false; } - - /*! - * \brief Output the solution in solution file. - */ - virtual void Output(unsigned long TimeIter){ } - - /*! - * \brief Perform a dynamic mesh deformation, including grid velocity computation and update of the multigrid structure. - */ - virtual void DynamicMeshUpdate(unsigned long TimeIter) { } - - /*! - * \brief Perform a dynamic mesh deformation, including grid velocity computation and update of the multigrid structure. - */ - virtual void DynamicMeshUpdate(unsigned short val_iZone, unsigned long TimeIter) { } - - /*! - * \brief Perform a mesh deformation as initial condition. - */ - virtual void SetInitialMesh() { } - - /*! - * \brief Process the boundary conditions and update the multigrid structure. - */ - void BoundaryConditionsUpdate(); - - /*! - * \brief Get the total drag. - * \return Total drag. - */ - passivedouble Get_Drag() const; - - /*! - * \brief Get the total lift. - * \return Total lift. - */ - passivedouble Get_Lift() const; - - /*! - * \brief Get the total x moment. - * \return Total x moment. - */ - passivedouble Get_Mx() const; - - /*! - * \brief Get the total y moment. - * \return Total y moment. - */ - passivedouble Get_My() const; - - /*! - * \brief Get the total z moment. - * \return Total z moment. - */ - passivedouble Get_Mz() const; - - /*! - * \brief Get the total drag coefficient. - * \return Total drag coefficient. - */ - passivedouble Get_DragCoeff() const; - - /*! - * \brief Get the total lift coefficient. - * \return Total lift coefficient. - */ - passivedouble Get_LiftCoeff() const; - - /*! - * \brief Get the number of vertices (halo nodes included) from a specified marker. - * \param[in] iMarker - Marker identifier. - * \return Number of vertices. - */ - unsigned long GetNumberVertices(unsigned short iMarker) const; - - /*! - * \brief Get the number of halo vertices from a specified marker. - * \param[in] iMarker - Marker identifier. - * \return Number of vertices. - */ - unsigned long GetNumberHaloVertices(unsigned short iMarker) const; - - /*! - * \brief Check if a vertex is physical or not (halo node) on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return True if the specified vertex is a halo node. - */ - bool IsAHaloNode(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get the number of external iterations. - * \return Number of external iterations. - */ - unsigned long GetnTimeIter() const; - - /*! - * \brief Get the current external iteration. - * \return Current external iteration. - */ - unsigned long GetTime_Iter() const; - - /*! - * \brief Get the unsteady time step. - * \return Unsteady time step. - */ - passivedouble GetUnsteady_TimeStep() const; - - /*! - * \brief Get the name of the output file for the surface. - * \return File name for the surface output. - */ - string GetSurfaceFileName() const; - - /*! - * \brief Get the global index of a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Vertex global index. - */ - unsigned long GetVertexGlobalIndex(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get undeformed coordinates from the mesh solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return x,y,z coordinates of the vertex. - */ - vector GetInitialMeshCoord(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get the temperature at a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Temperature of the vertex. - */ - passivedouble GetVertexTemperature(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Set the temperature of a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] val_WallTemp - Value of the temperature. - */ - void SetVertexTemperature(unsigned short iMarker, unsigned long iVertex, passivedouble val_WallTemp); - - /*! - * \brief Get the heat flux at a vertex on a specified marker (3 components). - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return True if the vertex is a halo node. - */ - vector GetVertexHeatFluxes(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get the wall normal component of the heat flux at a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Wall normal component of the heat flux at the vertex. - */ - passivedouble GetVertexNormalHeatFlux(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Set the wall normal component of the heat flux at a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] val_WallHeatFlux - Value of the normal heat flux. - */ - void SetVertexNormalHeatFlux(unsigned short iMarker, unsigned long iVertex, passivedouble val_WallHeatFlux); - - /*! - * \brief Get the thermal conductivity at a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Thermal conductivity at the vertex. - */ - passivedouble GetThermalConductivity(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Preprocess the inlets via file input for all solvers. - * \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 Inlet_Preprocessing(CSolver ***solver, CGeometry **geometry, CConfig *config) const; - - /*! - * \brief Get the normal (vector) at a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] unitNormal - Bool to normalise the vector. - * \return Normal (vector) at the vertex. - */ - vector GetVertexNormal(unsigned short iMarker, unsigned long iVertex, bool unitNormal = false) const; - - /*! - * \brief Get the unit normal (vector) at a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Unit normal (vector) at the vertex. - */ - inline vector GetVertexUnitNormal(unsigned short iMarker, unsigned long iVertex) const { - return GetVertexNormal(iMarker, iVertex, true); - } - - /*! - * \brief Get all the boundary markers tags. - * \return List of boundary markers tags. - */ - vector GetAllBoundaryMarkersTag() const; - - /*! - * \brief Get all the deformable boundary marker tags. - * \return List of deformable boundary markers tags. - */ - vector GetAllDeformMeshMarkersTag() const; - - /*! - * \brief Get all the heat transfer boundary markers tags. - * \return List of heat transfer boundary markers tags. - */ - vector GetAllCHTMarkersTag() const; - - /*! - * \brief Get all the (subsonic) inlet boundary markers tags. - * \return List of inlet boundary markers tags. - */ - vector GetAllInletMarkersTag() const; - - /*! - * \brief Get all the boundary markers tags with their associated indices. - * \return List of boundary markers tags with their indices. - */ - map GetAllBoundaryMarkers() const; - - /*! - * \brief Get all the boundary markers tags with their associated types. - * \return List of boundary markers tags with their types. - */ - map GetAllBoundaryMarkersType() const; - - /*! - * \brief Set the mesh displacement for the elasticity mesh solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] DispX - Value of the mesh displacement in the direction X. - * \param[in] DispY - Value of the mesh displacement in the direction Y. - * \param[in] DispZ - Value of the mesh displacement in the direction Z. - */ - void SetMeshDisplacement(unsigned short iMarker, unsigned long iVertex, passivedouble DispX, passivedouble DispY, passivedouble DispZ); - - /*! - * \brief Communicate the boundary mesh displacements in a python call - */ - void CommunicateMeshDisplacement(void); - - /*! - * \brief Return the sensitivities of the mesh boundary vertices. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Vector of sensitivities. - */ - vector GetMeshDisp_Sensitivity(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Set the load in X direction for the structural solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] LoadX - Value of the load in the direction X. - * \param[in] LoadX - Value of the load in the direction Y. - * \param[in] LoadX - Value of the load in the direction Z. - */ - void SetFEA_Loads(unsigned short iMarker, unsigned long iVertex, passivedouble LoadX, - passivedouble LoadY, passivedouble LoadZ); - - /*! - * \brief Return the displacements from the FEA solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Vector of displacements. - */ - vector GetFEA_Displacements(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Return the velocities from the FEA Solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Vector of velocities. - */ - vector GetFEA_Velocity(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Return the velocities from the FEA Solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Vector of velocities at time n. - */ - vector GetFEA_Velocity_n(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get the sensitivity of the flow loads for the structural solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] LoadX - Value of the load in the direction X. - * \param[in] LoadX - Value of the load in the direction Y. - * \param[in] LoadX - Value of the load in the direction Z. - */ - vector GetFlowLoad_Sensitivity(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get the flow load (from the extra step - the repeated methods should be unified once the postprocessing - * strategy is in place). - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - */ - vector GetFlowLoad(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Set the adjoint of the flow tractions (from the extra step - - * the repeated methods should be unified once the postprocessing strategy is in place). - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] val_AdjointX - Value of the adjoint in the direction X. - * \param[in] val_AdjointY - Value of the adjoint in the direction Y. - * \param[in] val_AdjointZ - Value of the adjoint in the direction Z. - */ - void SetFlowLoad_Adjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, - passivedouble val_AdjointY, passivedouble val_AdjointZ); - - /*! - * \brief Set the adjoint of the structural displacements (from an outside source) - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] val_AdjointX - Value of the adjoint in the direction X. - * \param[in] val_AdjointY - Value of the adjoint in the direction Y. - * \param[in] val_AdjointZ - Value of the adjoint in the direction Z. - */ - void SetSourceTerm_DispAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, - passivedouble val_AdjointY, passivedouble val_AdjointZ); - void SetSourceTerm_VelAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, - passivedouble val_AdjointY, passivedouble val_AdjointZ); - - /*! - * \brief Set the position of the heat source. - * \param[in] alpha - Angle of rotation respect to Z axis. - * \param[in] pos_x - Position X. - * \param[in] pos_y - Position Y. - * \param[in] pos_z - Position Z. - */ - void SetHeatSource_Position(passivedouble alpha, passivedouble pos_x, passivedouble pos_y, passivedouble pos_z); - - /*! - * \brief Set the direction of the inlet. - * \param[in] iMarker - Marker index. - * \param[in] alpha - Angle (Zpos). - */ - void SetInlet_Angle(unsigned short iMarker, passivedouble alpha); - - /*! - * \brief Sum the number of primal or adjoint variables for all solvers in a given zone. - * \param[in] iZone - Index of the zone. - * \param[in] adjoint - True to consider adjoint solvers instead of primal. - * \return Total number of solution variables. - */ - unsigned short GetTotalNumberOfVariables(unsigned short iZone, bool adjoint) const { - unsigned short nVar = 0; - for (auto iSol = 0u; iSol < MAX_SOLS; iSol++) { - auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver && (solver->GetAdjoint() == adjoint)) nVar += solver->GetnVar(); + + /*! + * \brief Launch the computation for all zones and all physics. + */ + virtual void StartSolver() {} + + /*! + * \brief Deallocation routine + */ + void Postprocessing(); + + /*! + * \brief A virtual member. + */ + virtual void ResetConvergence(); + + /*! + * \brief Perform some pre-processing before an iteration of the physics. + */ + virtual void Preprocess(unsigned long TimeIter){ } + + /*! + * \brief Monitor the computation. + */ + virtual bool Monitor(unsigned long TimeIter){ return false; } + + /*! + * \brief Output the solution in solution file. + */ + virtual void Output(unsigned long TimeIter){ } + + /*! + * \brief Perform a dynamic mesh deformation, including grid velocity computation and update of the multigrid structure. + */ + virtual void DynamicMeshUpdate(unsigned long TimeIter) { } + + /*! + * \brief Perform a dynamic mesh deformation, including grid velocity computation and update of the multigrid structure. + */ + virtual void DynamicMeshUpdate(unsigned short val_iZone, unsigned long TimeIter) { } + + /*! + * \brief Perform a mesh deformation as initial condition. + */ + virtual void SetInitialMesh() { } + + /*! + * \brief Process the boundary conditions and update the multigrid structure. + */ + void BoundaryConditionsUpdate(); + + /*! + * \brief Get the total drag. + * \return Total drag. + */ + passivedouble Get_Drag() const; + + /*! + * \brief Get the total lift. + * \return Total lift. + */ + passivedouble Get_Lift() const; + + /*! + * \brief Get the total x moment. + * \return Total x moment. + */ + passivedouble Get_Mx() const; + + /*! + * \brief Get the total y moment. + * \return Total y moment. + */ + passivedouble Get_My() const; + + /*! + * \brief Get the total z moment. + * \return Total z moment. + */ + passivedouble Get_Mz() const; + + /*! + * \brief Get the total drag coefficient. + * \return Total drag coefficient. + */ + passivedouble Get_DragCoeff() const; + + /*! + * \brief Get the total lift coefficient. + * \return Total lift coefficient. + */ + passivedouble Get_LiftCoeff() const; + + /*! + * \brief Get the number of external iterations. + * \return Number of external iterations. + */ + unsigned long GetnTimeIter() const; + + /*! + * \brief Get the current external iteration. + * \return Current external iteration. + */ + unsigned long GetTime_Iter() const; + + /*! + * \brief Get the unsteady time step. + * \return Unsteady time step. + */ + passivedouble GetUnsteady_TimeStep() const; + + /*! + * \brief Get the name of the output file for the surface. + * \return File name for the surface output. + */ + string GetSurfaceFileName() const; + + /*! + * \brief Get the temperature at a vertex on a specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Temperature of the vertex. + */ + passivedouble GetVertexTemperature(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Set the temperature of a vertex on a specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \param[in] val_WallTemp - Value of the temperature. + */ + void SetVertexTemperature(unsigned short iMarker, unsigned long iVertex, passivedouble val_WallTemp); + + /*! + * \brief Get the heat flux at a vertex on a specified marker (3 components). + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return True if the vertex is a halo node. + */ + vector GetVertexHeatFluxes(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get the wall normal component of the heat flux at a vertex on a specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Wall normal component of the heat flux at the vertex. + */ + passivedouble GetVertexNormalHeatFlux(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Set the wall normal component of the heat flux at a vertex on a specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \param[in] val_WallHeatFlux - Value of the normal heat flux. + */ + void SetVertexNormalHeatFlux(unsigned short iMarker, unsigned long iVertex, passivedouble val_WallHeatFlux); + + /*! + * \brief Get the thermal conductivity at a vertex on a specified marker. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Thermal conductivity at the vertex. + */ + passivedouble GetThermalConductivity(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Preprocess the inlets via file input for all solvers. + * \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 Inlet_Preprocessing(CSolver ***solver, CGeometry **geometry, CConfig *config) const; + + /*! + * \brief Get all the boundary markers tags. + * \return List of boundary markers tags. + */ + vector GetAllBoundaryMarkersTag() const; + + /*! + * \brief Get all the heat transfer boundary markers tags. + * \return List of heat transfer boundary markers tags. + */ + vector GetAllCHTMarkersTag() const; + + /*! + * \brief Get all the (subsonic) inlet boundary markers tags. + * \return List of inlet boundary markers tags. + */ + vector GetAllInletMarkersTag() const; + + /*! + * \brief Return the sensitivities of the mesh boundary vertices. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Vector of sensitivities. + */ + vector GetMeshDisp_Sensitivity(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Set the load in X direction for the structural solver. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \param[in] LoadX - Value of the load in the direction X. + * \param[in] LoadX - Value of the load in the direction Y. + * \param[in] LoadX - Value of the load in the direction Z. + */ + void SetFEA_Loads(unsigned short iMarker, unsigned long iVertex, passivedouble LoadX, passivedouble LoadY, passivedouble LoadZ); + + /*! + * \brief Return the displacements from the FEA solver. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Vector of displacements. + */ + vector GetFEA_Displacements(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Return the velocities from the FEA Solver. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Vector of velocities. + */ + vector GetFEA_Velocity(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Return the velocities from the FEA Solver. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \return Vector of velocities at time n. + */ + vector GetFEA_Velocity_n(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get the sensitivity of the flow loads for the structural solver. + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \param[in] LoadX - Value of the load in the direction X. + * \param[in] LoadX - Value of the load in the direction Y. + * \param[in] LoadX - Value of the load in the direction Z. + */ + vector GetFlowLoad_Sensitivity(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get the flow load (from the extra step - the repeated methods should be unified once the postprocessing + * strategy is in place). + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + */ + vector GetFlowLoad(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Set the adjoint of the flow tractions (from the extra step - + * the repeated methods should be unified once the postprocessing strategy is in place). + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \param[in] val_AdjointX - Value of the adjoint in the direction X. + * \param[in] val_AdjointY - Value of the adjoint in the direction Y. + * \param[in] val_AdjointZ - Value of the adjoint in the direction Z. + */ + void SetFlowLoad_Adjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, + passivedouble val_AdjointY, passivedouble val_AdjointZ); + + /*! + * \brief Set the adjoint of the structural displacements (from an outside source) + * \param[in] iMarker - Marker identifier. + * \param[in] iVertex - Vertex identifier. + * \param[in] val_AdjointX - Value of the adjoint in the direction X. + * \param[in] val_AdjointY - Value of the adjoint in the direction Y. + * \param[in] val_AdjointZ - Value of the adjoint in the direction Z. + */ + void SetSourceTerm_DispAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, + passivedouble val_AdjointY, passivedouble val_AdjointZ); + void SetSourceTerm_VelAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, + passivedouble val_AdjointY, passivedouble val_AdjointZ); + + /*! + * \brief Set the position of the heat source. + * \param[in] alpha - Angle of rotation respect to Z axis. + * \param[in] pos_x - Position X. + * \param[in] pos_y - Position Y. + * \param[in] pos_z - Position Z. + */ + void SetHeatSource_Position(passivedouble alpha, passivedouble pos_x, passivedouble pos_y, passivedouble pos_z); + + /*! + * \brief Set the direction of the inlet. + * \param[in] iMarker - Marker index. + * \param[in] alpha - Angle (Zpos). + */ + void SetInlet_Angle(unsigned short iMarker, passivedouble alpha); + + /*! + * \brief Sum the number of primal or adjoint variables for all solvers in a given zone. + * \param[in] iZone - Index of the zone. + * \param[in] adjoint - True to consider adjoint solvers instead of primal. + * \return Total number of solution variables. + */ + unsigned short GetTotalNumberOfVariables(unsigned short iZone, bool adjoint) const { + unsigned short nVar = 0; + for (auto iSol = 0u; iSol < MAX_SOLS; iSol++) { + auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; + if (solver && (solver->GetAdjoint() == adjoint)) nVar += solver->GetnVar(); + } + return nVar; } - return nVar; - } - - /*! - * \brief Set the solution of all solvers (adjoint or primal) in a zone. - * \param[in] iZone - Index of the zone. - * \param[in] adjoint - True to consider adjoint solvers instead of primal. - * \param[in] solution - Solution object with interface (iPoint,iVar). - * \tparam Old - If true set "old solutions" instead. - */ - template - void SetAllSolutions(unsigned short iZone, bool adjoint, const Container& solution) { - const auto nPoint = geometry_container[iZone][INST_0][MESH_0]->GetnPoint(); - for (auto iSol = 0u, offset = 0u; iSol < MAX_SOLS; ++iSol) { - auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (!(solver && (solver->GetAdjoint() == adjoint))) continue; - for (auto iPoint = 0ul; iPoint < nPoint; ++iPoint) - for (auto iVar = 0ul; iVar < solver->GetnVar(); ++iVar) - if (!Old) solver->GetNodes()->SetSolution(iPoint, iVar, solution(iPoint,offset+iVar)); - else solver->GetNodes()->SetSolution_Old(iPoint, iVar, solution(iPoint,offset+iVar)); - offset += solver->GetnVar(); + + /*! + * \brief Set the solution of all solvers (adjoint or primal) in a zone. + * \param[in] iZone - Index of the zone. + * \param[in] adjoint - True to consider adjoint solvers instead of primal. + * \param[in] solution - Solution object with interface (iPoint,iVar). + * \tparam Old - If true set "old solutions" instead. + */ + template + void SetAllSolutions(unsigned short iZone, bool adjoint, const Container& solution) { + const auto nPoint = geometry_container[iZone][INST_0][MESH_0]->GetnPoint(); + for (auto iSol = 0u, offset = 0u; iSol < MAX_SOLS; ++iSol) { + auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; + if (!(solver && (solver->GetAdjoint() == adjoint))) continue; + for (auto iPoint = 0ul; iPoint < nPoint; ++iPoint) + for (auto iVar = 0ul; iVar < solver->GetnVar(); ++iVar) + if (!Old) solver->GetNodes()->SetSolution(iPoint, iVar, solution(iPoint,offset+iVar)); + else solver->GetNodes()->SetSolution_Old(iPoint, iVar, solution(iPoint,offset+iVar)); + offset += solver->GetnVar(); + } } - } - - /*! - * \brief Set the "old solution" of all solvers (adjoint or primal) in a zone. - */ - template - void SetAllSolutionsOld(unsigned short iZone, bool adjoint, const Container& solution) { - SetAllSolutions(iZone, adjoint, solution); - } - - /*! - * \brief Get the solution of all solvers (adjoint or primal) in a zone. - * \param[in] iZone - Index of the zone. - * \param[in] adjoint - True to consider adjoint solvers instead of primal. - * \param[out] solution - Solution object with interface (iPoint,iVar). - */ - template - void GetAllSolutions(unsigned short iZone, bool adjoint, Container& solution) const { - const auto nPoint = geometry_container[iZone][INST_0][MESH_0]->GetnPoint(); - for (auto iSol = 0u, offset = 0u; iSol < MAX_SOLS; ++iSol) { - auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (!(solver && (solver->GetAdjoint() == adjoint))) continue; - const auto& sol = solver->GetNodes()->GetSolution(); - for (auto iPoint = 0ul; iPoint < nPoint; ++iPoint) - for (auto iVar = 0ul; iVar < solver->GetnVar(); ++iVar) - solution(iPoint,offset+iVar) = SU2_TYPE::GetValue(sol(iPoint,iVar)); - offset += solver->GetnVar(); + + /*! + * \brief Set the "old solution" of all solvers (adjoint or primal) in a zone. + */ + template + void SetAllSolutionsOld(unsigned short iZone, bool adjoint, const Container& solution) { + SetAllSolutions(iZone, adjoint, solution); } - } - + + /*! + * \brief Get the solution of all solvers (adjoint or primal) in a zone. + * \param[in] iZone - Index of the zone. + * \param[in] adjoint - True to consider adjoint solvers instead of primal. + * \param[out] solution - Solution object with interface (iPoint,iVar). + */ + template + void GetAllSolutions(unsigned short iZone, bool adjoint, Container& solution) const { + const auto nPoint = geometry_container[iZone][INST_0][MESH_0]->GetnPoint(); + for (auto iSol = 0u, offset = 0u; iSol < MAX_SOLS; ++iSol) { + auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; + if (!(solver && (solver->GetAdjoint() == adjoint))) continue; + const auto& sol = solver->GetNodes()->GetSolution(); + for (auto iPoint = 0ul; iPoint < nPoint; ++iPoint) + for (auto iVar = 0ul; iVar < solver->GetnVar(); ++iVar) + solution(iPoint,offset+iVar) = SU2_TYPE::GetValue(sol(iPoint,iVar)); + offset += solver->GetnVar(); + } + } + }; /*! @@ -789,69 +680,69 @@ class CDriver { * \author T. Economon, G. Gori */ class CFluidDriver : public CDriver { - + protected: - unsigned long Max_Iter; - + unsigned long Max_Iter; + protected: - - /*! - * \brief Constructor of the class. - * \param[in] confFile - Configuration file name. - * \param[in] val_nZone - Total number of zones. - * \param[in] val_nDim - Number of dimensions. - * \param[in] MPICommunicator - MPI communicator for SU2. - */ - CFluidDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator); - + + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] val_nZone - Total number of zones. + * \param[in] val_nDim - Number of dimensions. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CFluidDriver(char* confFile, + unsigned short val_nZone, + SU2_Comm MPICommunicator); + public: - /*! - * \brief Destructor of the class. - */ - ~CFluidDriver(void) override; - - /*! - * \brief Launch the computation for all zones and all physics. - */ - void StartSolver() override; - - /*! - * \brief Run a single iteration of the physics within multiple zones. - */ - void Run() override; - - /*! - * \brief Update the dual-time solution within multiple zones. - */ - void Update() override; - - /*! - * \brief Output the solution in solution file. - */ - void Output(unsigned long InnerIter) override; - - /*! - * \brief Monitor the computation. - */ - bool Monitor(unsigned long ExtIter) override; - - /*! - * \brief Perform some pre-processing before an iteration of the physics. - */ - void Preprocess(unsigned long Iter) override; - - /*! - * \brief Perform a dynamic mesh deformation, included grid velocity computation and the update of the multigrid structure (multiple zone). - */ - void DynamicMeshUpdate(unsigned long TimeIter) override; - - /*! - * \brief Transfer data among different zones (multiple zone). - */ - void Transfer_Data(unsigned short donorZone, unsigned short targetZone); - + /*! + * \brief Destructor of the class. + */ + ~CFluidDriver(void) override; + + /*! + * \brief Launch the computation for all zones and all physics. + */ + void StartSolver() override; + + /*! + * \brief Run a single iteration of the physics within multiple zones. + */ + void Run() override; + + /*! + * \brief Update the dual-time solution within multiple zones. + */ + void Update() override; + + /*! + * \brief Output the solution in solution file. + */ + void Output(unsigned long InnerIter) override; + + /*! + * \brief Monitor the computation. + */ + bool Monitor(unsigned long ExtIter) override; + + /*! + * \brief Perform some pre-processing before an iteration of the physics. + */ + void Preprocess(unsigned long Iter) override; + + /*! + * \brief Perform a dynamic mesh deformation, included grid velocity computation and the update of the multigrid structure (multiple zone). + */ + void DynamicMeshUpdate(unsigned long TimeIter) override; + + /*! + * \brief Transfer data among different zones (multiple zone). + */ + void Transfer_Data(unsigned short donorZone, unsigned short targetZone); + }; @@ -862,50 +753,50 @@ class CFluidDriver : public CDriver { */ class CTurbomachineryDriver : public CFluidDriver { private: - COutputLegacy* output_legacy; - + COutputLegacy* output_legacy; + public: - - /*! - * \brief Constructor of the class. - * \param[in] confFile - Configuration file name. - * \param[in] val_nZone - Total number of zones. - * \param[in] val_nDim - Number of dimensions. - * \param[in] val_periodic - Bool for periodic BCs. - * \param[in] MPICommunicator - MPI communicator for SU2. - */ - CTurbomachineryDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator); - - /*! - * \brief Destructor of the class. - */ - ~CTurbomachineryDriver(void) override; - - /*! - * \brief Run a single iteration of the physics within multiple zones. - */ - - void Run() override; - - /*! - * \brief Set Mixing Plane interface within multiple zones. - */ - void SetMixingPlane(unsigned short iZone); - - /*! - * \brief Set Mixing Plane interface within multiple zones. - */ - void SetTurboPerformance(unsigned short targetZone); - - /*! - * \brief Monitor the computation. - */ - bool Monitor(unsigned long TimeIter) override; - - - + + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] val_nZone - Total number of zones. + * \param[in] val_nDim - Number of dimensions. + * \param[in] val_periodic - Bool for periodic BCs. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CTurbomachineryDriver(char* confFile, + unsigned short val_nZone, + SU2_Comm MPICommunicator); + + /*! + * \brief Destructor of the class. + */ + ~CTurbomachineryDriver(void) override; + + /*! + * \brief Run a single iteration of the physics within multiple zones. + */ + + void Run() override; + + /*! + * \brief Set Mixing Plane interface within multiple zones. + */ + void SetMixingPlane(unsigned short iZone); + + /*! + * \brief Set Mixing Plane interface within multiple zones. + */ + void SetTurboPerformance(unsigned short targetZone); + + /*! + * \brief Monitor the computation. + */ + bool Monitor(unsigned long TimeIter) override; + + + }; /*! @@ -914,61 +805,61 @@ class CTurbomachineryDriver : public CFluidDriver { * \author T. Economon */ class CHBDriver : public CFluidDriver { - + private: - COutputLegacy* output_legacy; - unsigned short nInstHB; - su2double **D; /*!< \brief Harmonic Balance operator. */ - + COutputLegacy* output_legacy; + unsigned short nInstHB; + su2double **D; /*!< \brief Harmonic Balance operator. */ + public: - - /*! - * \brief Constructor of the class. - * \param[in] confFile - Configuration file name. - * \param[in] val_nZone - Total number of zones. - * \param[in] val_nDim - Number of dimensions. - * \param[in] MPICommunicator - MPI communicator for SU2. - */ - CHBDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator); - - /*! - * \brief Destructor of the class. - */ - ~CHBDriver(void) override; - - /*! - * \brief Run a single iteration of a Harmonic Balance problem. - */ - void Run() override; - - /*! - * \brief Computation and storage of the Harmonic Balance method source terms. - * \author T. Economon, K. Naik - * \param[in] iZone - Current zone number. - */ - void SetHarmonicBalance(unsigned short iZone); - - /*! - * \brief Precondition Harmonic Balance source term for stability - * \author J. Howison - */ - void StabilizeHarmonicBalance(); - - /*! - * \brief Computation of the Harmonic Balance operator matrix for harmonic balance. - * \author A. Rubino, S. Nimmagadda - */ - void ComputeHB_Operator(); - - /*! - * \brief Update the solution for the Harmonic Balance. - */ - void Update() override; - - /*! - * \brief Reset the convergence flag (set to false) of the solver for the Harmonic Balance. - */ - void ResetConvergence() override; + + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] val_nZone - Total number of zones. + * \param[in] val_nDim - Number of dimensions. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CHBDriver(char* confFile, + unsigned short val_nZone, + SU2_Comm MPICommunicator); + + /*! + * \brief Destructor of the class. + */ + ~CHBDriver(void) override; + + /*! + * \brief Run a single iteration of a Harmonic Balance problem. + */ + void Run() override; + + /*! + * \brief Computation and storage of the Harmonic Balance method source terms. + * \author T. Economon, K. Naik + * \param[in] iZone - Current zone number. + */ + void SetHarmonicBalance(unsigned short iZone); + + /*! + * \brief Precondition Harmonic Balance source term for stability + * \author J. Howison + */ + void StabilizeHarmonicBalance(); + + /*! + * \brief Computation of the Harmonic Balance operator matrix for harmonic balance. + * \author A. Rubino, S. Nimmagadda + */ + void ComputeHB_Operator(); + + /*! + * \brief Update the solution for the Harmonic Balance. + */ + void Update() override; + + /*! + * \brief Reset the convergence flag (set to false) of the solver for the Harmonic Balance. + */ + void ResetConvergence() override; }; diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index fa14d73fe34..dcb8447d591 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -107,8 +107,7 @@ #include CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator, bool dummy_geo) : - config_file_name(confFile), StartTime(0.0), StopTime(0.0), UsedTime(0.0), - TimeIter(0), nZone(val_nZone), StopCalc(false), fsi(false), fem_solver(false), dry_run(dummy_geo) { + CDriverBase(confFile, val_nZone, MPICommunicator), StopCalc(false), fsi(false), fem_solver(false), dry_run(dummy_geo) { /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ #ifdef HAVE_MPI diff --git a/SU2_CFD/src/python_wrapper_structure.cpp b/SU2_CFD/src/python_wrapper_structure.cpp index 206c81492d1..2f85546f4d3 100644 --- a/SU2_CFD/src/python_wrapper_structure.cpp +++ b/SU2_CFD/src/python_wrapper_structure.cpp @@ -166,99 +166,6 @@ passivedouble CDriver::Get_LiftCoeff() const { return SU2_TYPE::GetValue(CLift); } -///////////////////////////////////////////////////////////////////////////// -/* Functions to obtain information from the geometry/mesh */ -///////////////////////////////////////////////////////////////////////////// - -unsigned long CDriver::GetNumberVertices(unsigned short iMarker) const { - - return geometry_container[ZONE_0][INST_0][MESH_0]->nVertex[iMarker]; - -} - -unsigned long CDriver::GetNumberHaloVertices(unsigned short iMarker) const { - - unsigned long nHaloVertices, iVertex, iPoint; - - nHaloVertices = 0; - for(iVertex = 0; iVertex < geometry_container[ZONE_0][INST_0][MESH_0]->nVertex[iMarker]; iVertex++){ - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - if(!(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint))) nHaloVertices += 1; - } - - return nHaloVertices; - -} - -unsigned long CDriver::GetVertexGlobalIndex(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint, GlobalIndex; - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - GlobalIndex = geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetGlobalIndex(iPoint); - - return GlobalIndex; - -} - -bool CDriver::IsAHaloNode(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - if(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint)) return false; - else return true; - -} - -vector CDriver::GetInitialMeshCoord(unsigned short iMarker, unsigned long iVertex) const { - - vector coord(3,0.0); - vector coord_passive(3, 0.0); - - auto iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - for (auto iDim = 0 ; iDim < nDim ; iDim++){ - coord[iDim] = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetMesh_Coord(iPoint,iDim); - } - - coord_passive[0] = SU2_TYPE::GetValue(coord[0]); - coord_passive[1] = SU2_TYPE::GetValue(coord[1]); - coord_passive[2] = SU2_TYPE::GetValue(coord[2]); - - return coord_passive; -} - -vector CDriver::GetVertexNormal(unsigned short iMarker, unsigned long iVertex, bool unitNormal) const { - - su2double *Normal; - su2double Area; - vector ret_Normal(3, 0.0); - vector ret_Normal_passive(3, 0.0); - - Normal = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNormal(); - - if (!unitNormal) { - - ret_Normal_passive[0] = SU2_TYPE::GetValue(Normal[0]); - ret_Normal_passive[1] = SU2_TYPE::GetValue(Normal[1]); - if(nDim>2) ret_Normal_passive[2] = SU2_TYPE::GetValue(Normal[2]); - - return ret_Normal_passive; - } - - Area = GeometryToolbox::Norm(nDim, Normal); - - ret_Normal[0] = Normal[0]/Area; - ret_Normal[1] = Normal[1]/Area; - if(nDim>2) ret_Normal[2] = Normal[2]/Area; - - ret_Normal_passive[0] = SU2_TYPE::GetValue(ret_Normal[0]); - ret_Normal_passive[1] = SU2_TYPE::GetValue(ret_Normal[1]); - ret_Normal_passive[2] = SU2_TYPE::GetValue(ret_Normal[2]); - - return ret_Normal_passive; -} - ////////////////////////////////////////////////////////////////////////////////// /* Functions to obtain global parameters from SU2 (time steps, delta t, ecc...) */ ////////////////////////////////////////////////////////////////////////////////// @@ -430,23 +337,6 @@ vector CDriver::GetAllBoundaryMarkersTag() const { return boundariesTagList; } -vector CDriver::GetAllDeformMeshMarkersTag() const { - - vector interfaceBoundariesTagList; - unsigned short iMarker, nBoundariesMarker; - string Marker_Tag; - - nBoundariesMarker = config_container[ZONE_0]->GetnMarker_Deform_Mesh(); - interfaceBoundariesTagList.resize(nBoundariesMarker); - - for(iMarker=0; iMarker < nBoundariesMarker; iMarker++){ - Marker_Tag = config_container[ZONE_0]->GetMarker_Deform_Mesh_TagBound(iMarker); - interfaceBoundariesTagList[iMarker] = Marker_Tag; - } - - return interfaceBoundariesTagList; -} - vector CDriver::GetAllCHTMarkersTag() const { vector CHTBoundariesTagList; @@ -486,65 +376,6 @@ vector CDriver::GetAllInletMarkersTag() const { return BoundariesTagList; } -map CDriver::GetAllBoundaryMarkers() const { - - map allBoundariesMap; - unsigned short iMarker, nBoundaryMarkers; - string Marker_Tag; - - nBoundaryMarkers = config_container[ZONE_0]->GetnMarker_All(); - - for(iMarker=0; iMarker < nBoundaryMarkers; iMarker++){ - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - allBoundariesMap[Marker_Tag] = iMarker; - } - - return allBoundariesMap; -} - -map CDriver::GetAllBoundaryMarkersType() const { - - map allBoundariesTypeMap; - unsigned short iMarker, KindBC; - string Marker_Tag, Marker_Type; - - for(iMarker=0; iMarker < config_container[ZONE_0]->GetnMarker_All(); iMarker++){ - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - KindBC = config_container[ZONE_0]->GetMarker_All_KindBC(iMarker); - switch(KindBC){ - case EULER_WALL: - Marker_Type = "EULER_WALL"; - break; - case FAR_FIELD: - Marker_Type = "FARFIELD"; - break; - case ISOTHERMAL: - Marker_Type = "ISOTHERMAL"; - break; - case HEAT_FLUX: - Marker_Type = "HEATFLUX"; - break; - case INLET_FLOW: - Marker_Type = "INLET_FLOW"; - break; - case OUTLET_FLOW: - Marker_Type = "OUTLET_FLOW"; - break; - case SYMMETRY_PLANE: - Marker_Type = "SYMMETRY"; - break; - case SEND_RECEIVE: - Marker_Type = "SEND_RECEIVE"; - break; - default: - Marker_Type = "UNKNOWN_TYPE"; - } - allBoundariesTypeMap[Marker_Tag] = Marker_Type; - } - - return allBoundariesTypeMap; -} - void CDriver::SetHeatSource_Position(passivedouble alpha, passivedouble pos_x, passivedouble pos_y, passivedouble pos_z){ CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][RAD_SOL]; @@ -837,34 +668,6 @@ void CDriver::SetSourceTerm_VelAdjoint(unsigned short iMarker, unsigned long iVe } -//////////////////////////////////////////////////////////////////////////////// -/* Functions related to mesh deformation */ -//////////////////////////////////////////////////////////////////////////////// - -void CDriver::SetMeshDisplacement(unsigned short iMarker, unsigned long iVertex, passivedouble DispX, passivedouble DispY, passivedouble DispZ) { - - unsigned long iPoint; - su2double MeshDispl[3] = {0.0,0.0,0.0}; - - MeshDispl[0] = DispX; - MeshDispl[1] = DispY; - MeshDispl[2] = DispZ; - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint,MeshDispl); - -} - -void CDriver::CommunicateMeshDisplacement(void) { - - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->InitiateComms(geometry_container[ZONE_0][INST_0][MESH_0], - config_container[ZONE_0], MESH_DISPLACEMENTS); - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->CompleteComms(geometry_container[ZONE_0][INST_0][MESH_0], - config_container[ZONE_0], MESH_DISPLACEMENTS); - -} - //////////////////////////////////////////////////////////////////////////////// /* Functions related to flow loads */ //////////////////////////////////////////////////////////////////////////////// diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index 8196faeda5a..5c1d7c0da4e 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -1,8 +1,8 @@ - /*! +/*! * \file CDeformationDriver.hpp * \brief Headers of the main subroutines for driving the mesh deformation. - * \author T. Economon, H. Kline, R. Sanchez - * \version 7.1.1 "Blackbird" + * \author A. Gastaldi, H. Patel + * \version 7.3.0 "Blackbird" * * SU2 Project Website: https://su2code.github.io * @@ -38,32 +38,12 @@ #include "../../../SU2_CFD/include/output/COutput.hpp" #include "../../../SU2_CFD/include/numerics/CNumerics.hpp" #include "../../../Common/include/geometry/CGeometry.hpp" +#include "../../../Common/include/drivers/CDriverBase.hpp" + +class CDeformationDriver : public CDriverBase { -/*! - * \class CDeformationDriver - * \brief Class for driving mesh deformation solvers. - * \author A. Gastaldi, H. Patel - * \version 7.1.1 "Blackbird" - */ -class CDeformationDriver { protected: - char config_file_name[MAX_STRING_SIZE]; - int rank, - size; - su2double StartTime, /*!< \brief Start point of the timer for performance benchmarking.*/ - StopTime, /*!< \brief Stop point of the timer for performance benchmarking.*/ - UsedTimePreproc, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking preprocessing phase.*/ - UsedTimeCompute, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking compute phase.*/ - UsedTime; /*!< \brief Elapsed time between Start and Stop point of the timer.*/ - unsigned short iZone, nZone = SINGLE_ZONE; - CConfig *driver_config; /*!< \brief Definition of the driver configuration. */ - CConfig **config_container; /*!< \brief Definition of the particular problem. */ - CGeometry **geometry_container; /*!< \brief Geometrical definition of the problem. */ - CSurfaceMovement **surface_movement; /*!< \brief Surface movement classes of the problem. */ - CVolumetricMovement **grid_movement; /*!< \brief Volume grid movement classes of the problem. */ - CSolver **solver_container; CNumerics ***numerics_container; - COutput **output_container; /*!< \brief Pointer to the COutput class. */ public: /*! @@ -93,88 +73,7 @@ class CDeformationDriver { */ void Postprocessing(); - /*! - * \brief Get all the deformable boundary marker tags. - * \return List of deformable boundary markers tags. - */ - vector GetAllDeformMeshMarkersTag() const; - - /*! - * \brief Get all the boundary markers tags with their associated indices. - * \return List of boundary markers tags with their indices. - */ - map GetAllBoundaryMarkers() const; - - /*! - * \brief Get all the boundary markers tags with their associated types. - * \return List of boundary markers tags with their types. - */ - map GetAllBoundaryMarkersType() const; - - /*! - * \brief Get the number of vertices (halo nodes included) from a specified marker. - * \param[in] iMarker - Marker identifier. - * \return Number of vertices. - */ - unsigned long GetNumberVertices(unsigned short iMarker) const; - - /*! - * \brief Get the number of halo vertices from a specified marker. - * \param[in] iMarker - Marker identifier. - * \return Number of vertices. - */ - unsigned long GetNumberHaloVertices(unsigned short iMarker) const; - - /*! - * \brief Check if a vertex is physical or not (halo node) on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return True if the specified vertex is a halo node. - */ - bool IsAHaloNode(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get the global index of a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Vertex global index. - */ - unsigned long GetVertexGlobalIndex(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get undeformed coordinates from the mesh solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return x,y,z coordinates of the vertex. - */ - vector GetInitialMeshCoord(unsigned short iMarker, unsigned long iVertex) const; - - /*! - * \brief Get the unit normal (vector) at a vertex on a specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \return Unit normal (vector) at the vertex. - */ - vector GetVertexNormal(unsigned short iMarker, unsigned long iVertex, bool unitNormal = false) const; - - inline vector GetVertexUnitNormal(unsigned short iMarker, unsigned long iVertex) const { - return GetVertexNormal(iMarker, iVertex, true); - } - - /*! - * \brief Set the mesh displacement for the elasticity mesh solver. - * \param[in] iMarker - Marker identifier. - * \param[in] iVertex - Vertex identifier. - * \param[in] DispX - Value of the mesh displacement in the direction X. - * \param[in] DispY - Value of the mesh displacement in the direction Y. - * \param[in] DispZ - Value of the mesh displacement in the direction Z. - */ - void SetMeshDisplacement(unsigned short iMarker, unsigned long iVertex, passivedouble DispX, passivedouble DispY, passivedouble DispZ); - - /*! - * \brief Communicate the boundary mesh displacements in a python call - */ - void CommunicateMeshDisplacement(void); + void CommunicateMeshDisplacements(void); protected: /*! diff --git a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp index 36cf9daab8f..41a1df49b2c 100644 --- a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp @@ -1,8 +1,8 @@ /*! -* \file CDiscAdjDeformationDriver.cpp -* \brief Main subroutines for driving the projection of sensitivities. + * \file CDiscAdjDeformationDriver.cpp + * \brief Headers of the main subroutines for driving the projection of sensitivities. * \author T. Economon, H. Kline, R. Sanchez - * \version 7.1.1 "Blackbird" + * \version 7.3.0 "Blackbird" * * SU2 Project Website: https://su2code.github.io * @@ -40,115 +40,126 @@ #include "../../../SU2_CFD/include/output/CBaselineOutput.hpp" #include "../../../SU2_CFD/include/solvers/CBaselineSolver.hpp" +#include "../../../Common/include/drivers/CDriverBase.hpp" +#include "../../../SU2_CFD/include/solvers/CGradientSmoothingSolver.hpp" +#include "../../../SU2_CFD/include/numerics/CGradSmoothing.hpp" + /*! * \class CDiscAdjDeformationDriver - * \brief Class for driving sensitivity DiscAdjDeformations. + * \brief Class for driving sensitivity projections. * \author A. Gastaldi, H. Patel - * \version 7.1.1 "Blackbird" + * \version 7.3.0 "Blackbird" */ -class CDiscAdjDeformationDriver { -protected: - char config_file_name[MAX_STRING_SIZE]; - int rank, - size; - unsigned short iZone, nZone = SINGLE_ZONE; - unsigned short iInst; - unsigned short* nInst; - su2double StartTime, /*!< \brief Start point of the timer for performance benchmarking.*/ - StopTime, /*!< \brief Stop point of the timer for performance benchmarking.*/ - UsedTimePreproc, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking preprocessing phase.*/ - UsedTimeCompute, /*!< \brief Elapsed time between Start and Stop point of the timer for tracking compute phase.*/ - UsedTime; /*!< \brief Elapsed time between Start and Stop point of the timer.*/ - su2double** Gradient; - ofstream Gradient_file; - CConfig *driver_config; /*!< \brief Definition of the driver configuration. */ - CConfig **config_container; /*!< \brief Definition of the particular problem. */ - CGeometry ***geometry_container; /*!< \brief Geometrical definition of the problem. */ - CSurfaceMovement **surface_movement; - CVolumetricMovement **grid_movement; - COutput **output_container; /*!< \brief Pointer to the COutput class. */ +class CDiscAdjDeformationDriver : public CDriverBase { +protected: + su2double** Gradient; + ofstream Gradient_file; + CGeometry ***geometry_container; /*!< \brief Geometrical definition of the problem. */ + CSurfaceMovement **surface_movement; + CVolumetricMovement **grid_movement; + public: - /*! - * \brief Constructor of the class. - * \param[in] confFile - Configuration file name. - * \param[in] MPICommunicator - MPI communicator for SU2. - */ - CDiscAdjDeformationDriver(char* confFile, SU2_Comm MPICommunicator); - - /*! - * \brief Destructor of the class. - */ - ~CDiscAdjDeformationDriver(void); - - /*! - * \brief [Overload] Launch the computation for single-zone problems. - */ - void Run(); - - /*! - * \brief Deallocation routine - */ - void Postprocessing(); - + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CDiscAdjDeformationDriver(char* confFile, SU2_Comm MPICommunicator); + + /*! + * \brief Destructor of the class. + */ + ~CDiscAdjDeformationDriver(void); + + /*! + * \brief [Overload] Launch the computation for single-zone problems. + */ + void Run(); + + /*! + * \brief Deallocation routine + */ + void Postprocessing(); + protected: - /*! - * \brief Init_Containers - */ - void SetContainers_Null(); - - /*! - * \brief Read in the config and mesh files. - */ - void Input_Preprocessing(); - - /*! - * \brief Construction of the edge-based data structure. - */ - void Geometrical_Preprocessing(); - - /*! - * \brief Preprocess the output container. - */ - void Output_Preprocessing(); - - /*! - * \brief DiscAdjDeformation of the surface sensitivity using finite differences (FD). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] surface_movement - Surface movement class of the problem. - * \param[in] Gradient_file - Output file to store the gradient data. - */ - - void SetDiscAdjDeformation_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double **Gradient); - - /*! - * \brief DiscAdjDeformation of the surface sensitivity using algorithmic differentiation (AD). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] surface_movement - Surface movement class of the problem. - * \param[in] Gradient_file - Output file to store the gradient data. - */ - - void SetDiscAdjDeformation_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double **Gradient); - - /*! - * \brief Prints the gradient information to a file. - * \param[in] Gradient - The gradient data. - * \param[in] config - Definition of the particular problem. - * \param[in] Gradient_file - Output file to store the gradient data. - */ - - void OutputGradient(su2double** Gradient, CConfig* config, ofstream& Gradient_file); - - /*! - * \brief Write the sensitivity (including mesh sensitivity) computed with the discrete adjoint method - * on the surface and in the volume to a file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] val_nZone - Number of Zones. - */ - - void SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone); - + /*! + * \brief Init_Containers + */ + void SetContainers_Null(); + + /*! + * \brief Read in the config and mesh files. + */ + void Input_Preprocessing(); + + /*! + * \brief Construction of the edge-based data structure. + */ + void Geometrical_Preprocessing(); + + /*! + * \brief Preprocess the output container. + */ + void Output_Preprocessing(); + + /*! + * \brief Projection of the surface sensitivity using finite differences (FD). + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement class of the problem. + * \param[in] Gradient_file - Output file to store the gradient data. + */ + + void SetProjection_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double **Gradient); + + /*! + * \brief Projection of the surface sensitivity using algorithmic differentiation (AD). + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement class of the problem. + * \param[in] Gradient_file - Output file to store the gradient data. + */ + + void SetProjection_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double **Gradient); + + /*! + * \brief Prints the gradient information to a file. + * \param[in] Gradient - The gradient data. + * \param[in] config - Definition of the particular problem. + * \param[in] Gradient_file - Output file to store the gradient data. + */ + + void OutputGradient(su2double** Gradient, CConfig* config, ofstream& Gradient_file); + + /*! + * \brief Write the sensitivity (including mesh sensitivity) computed with the discrete adjoint method + * on the surface and in the volume to a file. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] val_nZone - Number of Zones. + */ + + void SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone); + + /*! + * \brief Treatment of derivatives with the Sobolev smoothing solver. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] grid_movement - Volumetric movement class of the problem. + */ + + void DerivativeTreatment_MeshSensitivity(CGeometry *geometry, CConfig *config, CVolumetricMovement *grid_movement); + + /*! + * \brief Treatment of derivatives with the Sobolev smoothing solver. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] grid_movement - Volumetric movement class of the problem. + * \param[in] surface_movement - Surface movement class of the problem. + * \param[in] Gradient - Output array to store the gradient data. + */ + + void DerivativeTreatment_Gradient(CGeometry *geometry, CConfig *config, CVolumetricMovement *grid_movement, CSurfaceMovement *surface_movement, su2double **Gradient); + }; diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 81973fc7608..90563e93f2f 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -1,8 +1,8 @@ /*! - * \file CDeformationDriver.hpp + * \file CDeformationDriver.cpp * \brief Main subroutines for driving the mesh deformation. - * \author T. Economon, H. Kline, R. Sanchez - * \version 7.1.1 "Blackbird" + * \author A. Gastaldi, H. Patel + * \version 7.3.0 "Blackbird" * * SU2 Project Website: https://su2code.github.io * @@ -25,7 +25,6 @@ * License along with SU2. If not, see . */ - #include "../../include/drivers/CDeformationDriver.hpp" #include "../../../Common/include/geometry/CPhysicalGeometry.hpp" @@ -36,770 +35,589 @@ using namespace std; -CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) { - - /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ - #ifdef HAVE_MPI - #if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE) - SU2_MPI::Init_AMPI(); - #endif - #endif - - SU2_MPI::SetComm(MPICommunicator); - - rank = SU2_MPI::GetRank(); - size = SU2_MPI::GetSize(); - - /*--- Copy the config filename ---*/ - strcpy(config_file_name, confFile); - - /*--- Initialize the configuration of the driver ---*/ - driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); - - nZone = driver_config->GetnZone(); - - /*--- Initialize containers --- */ - - SetContainers_Null(); - - /*--- Preprocessing of the config files. ---*/ - - Input_Preprocessing(); - - /*--- Set up a timer for performance benchmarking ---*/ - - StartTime = SU2_MPI::Wtime(); - - /*--- Preprocessing of the geometry for all zones. ---*/ - - Geometrical_Preprocessing(); - - /*--- Preprocessing of the output for all zones. ---*/ - - Output_Preprocessing(); - - if (driver_config->GetDeform_Mesh()){ - - /*--- Preprocessing of the mesh solver for all zones. ---*/ - - Solver_Preprocessing(); - - /*--- Preprocessing of the mesh solver for all zones. ---*/ - - Numerics_Preprocessing(); - - } - - /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ - - StopTime = SU2_MPI::Wtime(); - - /*--- Compute/print the total time for performance benchmarking. ---*/ - - UsedTime = StopTime-StartTime; - UsedTimePreproc = UsedTime; - UsedTimeCompute = 0.0; - +CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator): + CDriverBase(confFile, 1, MPICommunicator) +{ + + /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ +#ifdef HAVE_MPI +#if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE) + SU2_MPI::Init_AMPI(); +#endif +#endif + + SU2_MPI::SetComm(MPICommunicator); + + rank = SU2_MPI::GetRank(); + size = SU2_MPI::GetSize(); + + /*--- Copy the config filename ---*/ + strcpy(config_file_name, confFile); + + /*--- Initialize the configuration of the driver ---*/ + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); + + nZone = driver_config->GetnZone(); + + /*--- Initialize containers --- */ + + SetContainers_Null(); + + /*--- Preprocessing of the config files. ---*/ + + Input_Preprocessing(); + + /*--- Set up a timer for performance benchmarking ---*/ + + StartTime = SU2_MPI::Wtime(); + + /*--- Preprocessing of the geometry for all zones. ---*/ + + Geometrical_Preprocessing(); + + /*--- Preprocessing of the output for all zones. ---*/ + + Output_Preprocessing(); + + if (driver_config->GetDeform_Mesh()){ + + /*--- Preprocessing of the mesh solver for all zones. ---*/ + + Solver_Preprocessing(); + + /*--- Preprocessing of the mesh solver for all zones. ---*/ + + Numerics_Preprocessing(); + + } + + /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ + + StopTime = SU2_MPI::Wtime(); + + /*--- Compute/print the total time for performance benchmarking. ---*/ + + UsedTime = StopTime-StartTime; + UsedTimePreproc = UsedTime; + UsedTimeCompute = 0.0; + } CDeformationDriver::~CDeformationDriver(void) { - + } void CDeformationDriver::SetContainers_Null() { - + /*--- Create pointers to all of the classes that may be used throughout - the SU2_DEF code. In general, the pointers are instantiated down a - hierarchy over all zones as described in the comments below. ---*/ + the SU2_DEF code. In general, the pointers are instantiated down a + hierarchy over all zones as described in the comments below. ---*/ config_container = new CConfig*[nZone]; output_container = new COutput*[nZone]; - geometry_container = new CGeometry*[nZone]; + geometry_container = new CGeometry***[nZone]; surface_movement = new CSurfaceMovement*[nZone]; - grid_movement = new CVolumetricMovement*[nZone]; - - solver_container = new CSolver*[nZone]; + grid_movement = new CVolumetricMovement**[nZone]; + + solver_container = new CSolver****[nZone]; numerics_container = new CNumerics**[nZone]; - + for (iZone = 0; iZone < nZone; iZone++) { - config_container[iZone] = nullptr; - output_container[iZone] = nullptr; - geometry_container[iZone] = nullptr; - surface_movement[iZone] = nullptr; - grid_movement[iZone] = nullptr; - solver_container[iZone] = nullptr; - numerics_container[iZone] = nullptr; + config_container[iZone] = nullptr; + output_container[iZone] = nullptr; + geometry_container[iZone] = nullptr; + surface_movement[iZone] = nullptr; + grid_movement[iZone] = nullptr; + solver_container[iZone] = nullptr; + numerics_container[iZone] = nullptr; } } void CDeformationDriver::Input_Preprocessing() { - + /*--- Initialize a char to store the zone filename ---*/ char zone_file_name[MAX_STRING_SIZE]; - + /*--- Loop over all zones to initialize the various classes. In most - cases, nZone is equal to one. This represents the solution of a partial - differential equation on a single block, unstructured mesh. ---*/ - + cases, nZone is equal to one. This represents the solution of a partial + differential equation on a single block, unstructured mesh. ---*/ + for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Definition of the configuration option class for all zones. In this - constructor, the input configuration file is parsed and all options are - read and stored. ---*/ - + + /*--- Definition of the configuration option class for all zones. In this + constructor, the input configuration file is parsed and all options are + read and stored. ---*/ + if (driver_config->GetnConfigFiles() > 0){ strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); } else { config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); } - + config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); } - + /*--- Set the multizone part of the problem. ---*/ - + if (driver_config->GetMultizone_Problem()){ for (iZone = 0; iZone < nZone; iZone++) { - + /*--- Set the interface markers for multizone ---*/ - + config_container[iZone]->SetMultizone(driver_config, config_container); } } } void CDeformationDriver::Geometrical_Preprocessing() { - + for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ - - CGeometry *geometry_aux = nullptr; - - /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ - - geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); - - /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - - geometry_aux->SetColorGrid_Parallel(config_container[iZone]); - - /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - - geometry_container[iZone] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); - - /*--- Deallocate the memory of geometry_aux ---*/ - - delete geometry_aux; - - /*--- Add the Send/Receive boundaries ---*/ - - geometry_container[iZone]->SetSendReceive(config_container[iZone]); - - /*--- Add the Send/Receive boundaries ---*/ - - geometry_container[iZone]->SetBoundaries(config_container[iZone]); - - /*--- Computational grid preprocesing ---*/ - - if (rank == MASTER_NODE) cout << endl << "----------------------- Preprocessing computations ----------------------" << endl; - - /*--- Compute elements surrounding points, points surrounding points ---*/ - - if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); - - /*--- Check the orientation before computing geometrical quantities ---*/ - - geometry_container[iZone]->SetBoundVolume(); - if (config_container[iZone]->GetReorientElements()) { - if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config_container[iZone]); - geometry_container[iZone]->Check_BoundElem_Orientation(config_container[iZone]); - } - - /*--- Create the edge structure ---*/ - - if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); - geometry_container[iZone]->SetVertex(config_container[iZone]); - - if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { - - /*--- Create the dual control volume structures ---*/ - - if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; - geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); - geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); - } - - /*--- Create the point-to-point MPI communication structures. ---*/ - - geometry_container[iZone]->PreprocessP2PComms(geometry_container[iZone], config_container[iZone]); - + + /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ + + CGeometry *geometry_aux = nullptr; + + /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ + + geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); + + /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ + + geometry_aux->SetColorGrid_Parallel(config_container[iZone]); + + /*--- Build the grid data structures using the ParMETIS coloring. ---*/ + + geometry_container[iZone][INST_0][MESH_0] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); + + /*--- Deallocate the memory of geometry_aux ---*/ + + delete geometry_aux; + + /*--- Add the Send/Receive boundaries ---*/ + + geometry_container[iZone][INST_0][MESH_0]->SetSendReceive(config_container[iZone]); + + /*--- Add the Send/Receive boundaries ---*/ + + geometry_container[iZone][INST_0][MESH_0]->SetBoundaries(config_container[iZone]); + + /*--- Computational grid preprocesing ---*/ + + if (rank == MASTER_NODE) cout << endl << "----------------------- Preprocessing computations ----------------------" << endl; + + /*--- Compute elements surrounding points, points surrounding points ---*/ + + if (rank == MASTER_NODE) cout << "Setting local point connectivity." <SetPoint_Connectivity(); + + /*--- Check the orientation before computing geometrical quantities ---*/ + + geometry_container[iZone][INST_0][MESH_0]->SetBoundVolume(); + if (config_container[iZone]->GetReorientElements()) { + if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the interior elements." <Check_IntElem_Orientation(config_container[iZone]); + geometry_container[iZone][INST_0][MESH_0]->Check_BoundElem_Orientation(config_container[iZone]); + } + + /*--- Create the edge structure ---*/ + + if (rank == MASTER_NODE) cout << "Identify edges and vertices." <SetEdges(); + geometry_container[iZone][INST_0][MESH_0]->SetVertex(config_container[iZone]); + + if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { + + /*--- Create the dual control volume structures ---*/ + + if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; + geometry_container[iZone][INST_0][MESH_0]->SetControlVolume(config_container[iZone], ALLOCATE); + geometry_container[iZone][INST_0][MESH_0]->SetBoundControlVolume(config_container[iZone], ALLOCATE); + } + + /*--- Create the point-to-point MPI communication structures. ---*/ + + geometry_container[iZone][INST_0][MESH_0]->PreprocessP2PComms(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); + } } void CDeformationDriver::Output_Preprocessing() { - - for (iZone = 0; iZone < nZone; iZone++) { - + + for (iZone = 0; iZone < nZone; iZone++) { + /*--- Allocate the mesh output ---*/ - - output_container[iZone] = new CMeshOutput(config_container[iZone], geometry_container[iZone]->GetnDim()); - + + output_container[iZone] = new CMeshOutput(config_container[iZone], geometry_container[iZone][INST_0][MESH_0]->GetnDim()); + /*--- Preprocess the volume output ---*/ - + output_container[iZone]->PreprocessVolumeOutput(config_container[iZone]); - + /*--- Preprocess history --- */ - + output_container[iZone]->PreprocessHistoryOutput(config_container[iZone], false); - + } } void CDeformationDriver::Solver_Preprocessing() { - - for (iZone = 0; iZone < nZone; iZone++) { - solver_container[iZone] = new CMeshSolver(geometry_container[iZone], config_container[iZone]); - } - + + for (iZone = 0; iZone < nZone; iZone++) { + solver_container[iZone][INST_0][MESH_0][MESH_SOL] = new CMeshSolver(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); + } + } void CDeformationDriver::Numerics_Preprocessing() { - - for (iZone = 0; iZone < nZone; iZone++) { - numerics_container[iZone] = new CNumerics* [omp_get_num_threads() * MAX_TERMS](); - - for (int thread = 0; thread < omp_get_max_threads(); ++thread) { - const int iTerm = FEA_TERM + thread * MAX_TERMS; - const int nDim = geometry_container[iZone]->GetnDim(); - - numerics_container[iZone][iTerm] = new CFEAMeshElasticity(nDim, nDim, geometry_container[iZone]->GetnElem(), config_container[iZone]); + + for (iZone = 0; iZone < nZone; iZone++) { + numerics_container[iZone] = new CNumerics* [omp_get_num_threads() * MAX_TERMS](); + + for (int thread = 0; thread < omp_get_max_threads(); ++thread) { + const int iTerm = FEA_TERM + thread * MAX_TERMS; + const int nDim = geometry_container[iZone][INST_0][MESH_0]->GetnDim(); + + numerics_container[iZone][iTerm] = new CFEAMeshElasticity(nDim, nDim, geometry_container[iZone][INST_0][MESH_0]->GetnElem(), config_container[iZone]); + } + } - - } - + } void CDeformationDriver::Run() { - + /* --- Start measuring computation time ---*/ - + StartTime = SU2_MPI::Wtime(); - + /*--- Surface grid deformation using design variables ---*/ - + if (driver_config->GetDeform_Mesh()) { Update(); } else { Update_Legacy(); } - + /*--- Synchronization point after a single solver iteration. Compute the - wall clock time required. ---*/ - + wall clock time required. ---*/ + StopTime = SU2_MPI::Wtime(); - + UsedTimeCompute = StopTime-StartTime; if (rank == MASTER_NODE) { - cout << "\nCompleted in " << fixed << UsedTimeCompute << " seconds on "<< size; - - if (size == 1) cout << " core." << endl; else cout << " cores." << endl; + cout << "\nCompleted in " << fixed << UsedTimeCompute << " seconds on "<< size; + + if (size == 1) cout << " core." << endl; else cout << " cores." << endl; } - + /*--- Output the deformed mesh ---*/ Output(); - + } void CDeformationDriver::Update() { - + for (iZone = 0; iZone < nZone; iZone++){ - - /*--- Set the stiffness of each element mesh into the mesh numerics ---*/ - - solver_container[iZone]->SetMesh_Stiffness(numerics_container[iZone], config_container[iZone]); - - /*--- Deform the volume grid around the new boundary locations ---*/ - - solver_container[iZone]->DeformMesh(geometry_container[iZone], numerics_container[iZone], config_container[iZone]); - + + /*--- Set the stiffness of each element mesh into the mesh numerics ---*/ + + solver_container[iZone][INST_0][MESH_0][MESH_SOL]->SetMesh_Stiffness(numerics_container[iZone], config_container[iZone]); + + /*--- Deform the volume grid around the new boundary locations ---*/ + + solver_container[iZone][INST_0][MESH_0][MESH_SOL]->DeformMesh(geometry_container[iZone][INST_0][MESH_0], numerics_container[iZone], config_container[iZone]); + } } void CDeformationDriver::Update_Legacy() { - + for (iZone = 0; iZone < nZone; iZone++){ - - if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { - - /*--- Definition of the Class for grid movement ---*/ - grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone], config_container[iZone]); - - /*--- Save original coordinates to be reused in convexity checking procedure ---*/ - auto OriginalCoordinates = geometry_container[iZone]->nodes->GetCoord(); - - /*--- First check for volumetric grid deformation/transformations ---*/ - - if (config_container[iZone]->GetDesign_Variable(0) == SCALE_GRID) { - - if (rank == MASTER_NODE) - cout << endl << "--------------------- Volumetric grid scaling (ZONE " << iZone <<") ------------------" << endl; - grid_movement[iZone]->SetVolume_Scaling(geometry_container[iZone], config_container[iZone], false); - - } else if (config_container[iZone]->GetDesign_Variable(0) == TRANSLATE_GRID) { - - if (rank == MASTER_NODE) - cout << endl << "------------------- Volumetric grid translation (ZONE " << iZone <<") ----------------" << endl; - grid_movement[iZone]->SetVolume_Translation(geometry_container[iZone], config_container[iZone], false); - - } else if (config_container[iZone]->GetDesign_Variable(0) == ROTATE_GRID) { - - if (rank == MASTER_NODE) - cout << endl << "--------------------- Volumetric grid rotation (ZONE " << iZone <<") -----------------" << endl; - grid_movement[iZone]->SetVolume_Rotation(geometry_container[iZone], config_container[iZone], false); - - } else { - - /*--- If no volume-type deformations are requested, then this is a - surface-based deformation or FFD set up. ---*/ - - if (rank == MASTER_NODE) - cout << endl << "--------------------- Surface grid deformation (ZONE " << iZone <<") -----------------" << endl; - - /*--- Definition and initialization of the surface deformation class ---*/ - - surface_movement[iZone] = new CSurfaceMovement(); - - /*--- Copy coordinates to the surface structure ---*/ - - surface_movement[iZone]->CopyBoundary(geometry_container[iZone], config_container[iZone]); - - /*--- Surface grid deformation ---*/ - - if (rank == MASTER_NODE) cout << "Performing the deformation of the surface grid." << endl; - auto TotalDeformation = surface_movement[iZone]->SetSurface_Deformation(geometry_container[iZone], config_container[iZone]); - - if (config_container[iZone]->GetDesign_Variable(0) != FFD_SETTING) { - - if (rank == MASTER_NODE) - cout << endl << "------------------- Volumetric grid deformation (ZONE " << iZone <<") ----------------" << endl; - - if (rank == MASTER_NODE) - cout << "Performing the deformation of the volumetric grid." << endl; - grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone], config_container[iZone], false); - - /*--- Get parameters for convexity check ---*/ - bool ConvexityCheck; - unsigned short ConvexityCheck_MaxIter, ConvexityCheck_MaxDepth; - - tie(ConvexityCheck, ConvexityCheck_MaxIter, ConvexityCheck_MaxDepth) = config_container[iZone]->GetConvexityCheck(); - - /*--- Recursively change deformations if there are nonconvex elements. ---*/ - - if (ConvexityCheck && geometry_container[iZone]->GetnNonconvexElements() > 0) { - if (rank == MASTER_NODE) { - cout << "Nonconvex elements present after deformation. " << endl; - cout << "Recursively lowering deformation magnitude." << endl; - } - - /*--- Load initial deformation values ---*/ - auto InitialDeformation = TotalDeformation; - - unsigned short ConvexityCheckIter, RecursionDepth = 0; - su2double DeformationFactor = 1.0, DeformationDifference = 1.0; - for (ConvexityCheckIter = 1; ConvexityCheckIter <= ConvexityCheck_MaxIter; ConvexityCheckIter++) { - - /*--- Recursively change deformation magnitude: - decrease if there are nonconvex elements, increase otherwise ---*/ - DeformationDifference /= 2.0; - - if (geometry_container[iZone]->GetnNonconvexElements() > 0) { - DeformationFactor -= DeformationDifference; - } else { - RecursionDepth += 1; - - if (RecursionDepth == ConvexityCheck_MaxDepth) { - if (rank == MASTER_NODE) { - cout << "Maximum recursion depth reached." << endl; - cout << "Remaining amount of original deformation: "; - cout << DeformationFactor*100.0 << " percent. " << endl; - } - break; - } - - DeformationFactor += DeformationDifference; - } - - /*--- Load mesh to start every iteration with an undeformed grid ---*/ - for (auto iPoint = 0ul; iPoint < OriginalCoordinates.rows(); iPoint++) { - for (auto iDim = 0ul; iDim < OriginalCoordinates.cols(); iDim++) { - geometry_container[iZone]->nodes->SetCoord(iPoint, iDim, OriginalCoordinates(iPoint,iDim)); - } - } - - /*--- Set deformation magnitude as percentage of initial deformation ---*/ - for (auto iDV = 0u; iDV < driver_config->GetnDV(); iDV++) { - for (auto iDV_Value = 0u; iDV_Value < driver_config->GetnDV_Value(iDV); iDV_Value++) { - config_container[iZone]->SetDV_Value(iDV, iDV_Value, InitialDeformation[iDV][iDV_Value]*DeformationFactor); - } - } - - /*--- Surface grid deformation ---*/ - if (rank == MASTER_NODE) cout << "Performing the deformation of the surface grid." << endl; - - TotalDeformation = surface_movement[iZone]->SetSurface_Deformation(geometry_container[iZone], config_container[iZone]); - + + if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { + + /*--- Definition of the Class for grid movement ---*/ + grid_movement[iZone][INST_0] = new CVolumetricMovement(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); + + /*--- Save original coordinates to be reused in convexity checking procedure ---*/ + auto OriginalCoordinates = geometry_container[iZone][INST_0][MESH_0]->nodes->GetCoord(); + + /*--- First check for volumetric grid deformation/transformations ---*/ + + if (config_container[iZone]->GetDesign_Variable(0) == SCALE_GRID) { + if (rank == MASTER_NODE) - cout << endl << "------------------- Volumetric grid deformation (ZONE " << iZone <<") ----------------" << endl; - + cout << endl << "--------------------- Volumetric grid scaling (ZONE " << iZone <<") ------------------" << endl; + grid_movement[iZone][INST_0]->SetVolume_Scaling(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], false); + + } else if (config_container[iZone]->GetDesign_Variable(0) == TRANSLATE_GRID) { + if (rank == MASTER_NODE) - cout << "Performing the deformation of the volumetric grid." << endl; - grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone], config_container[iZone], false); - - if (rank == MASTER_NODE) { - cout << "Number of nonconvex elements for iteration " << ConvexityCheckIter << ": "; - cout << geometry_container[iZone]->GetnNonconvexElements() << endl; - cout << "Remaining amount of original deformation: "; - cout << DeformationFactor*100.0 << " percent. " << endl; + cout << endl << "------------------- Volumetric grid translation (ZONE " << iZone <<") ----------------" << endl; + grid_movement[iZone][INST_0]->SetVolume_Translation(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], false); + + } else if (config_container[iZone]->GetDesign_Variable(0) == ROTATE_GRID) { + + if (rank == MASTER_NODE) + cout << endl << "--------------------- Volumetric grid rotation (ZONE " << iZone <<") -----------------" << endl; + grid_movement[iZone][INST_0]->SetVolume_Rotation(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], false); + + } else { + + /*--- If no volume-type deformations are requested, then this is a + surface-based deformation or FFD set up. ---*/ + + if (rank == MASTER_NODE) + cout << endl << "--------------------- Surface grid deformation (ZONE " << iZone <<") -----------------" << endl; + + /*--- Definition and initialization of the surface deformation class ---*/ + + surface_movement[iZone] = new CSurfaceMovement(); + + /*--- Copy coordinates to the surface structure ---*/ + + surface_movement[iZone]->CopyBoundary(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); + + /*--- Surface grid deformation ---*/ + + if (rank == MASTER_NODE) cout << "Performing the deformation of the surface grid." << endl; + auto TotalDeformation = surface_movement[iZone]->SetSurface_Deformation(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); + + if (config_container[iZone]->GetDesign_Variable(0) != FFD_SETTING) { + + if (rank == MASTER_NODE) + cout << endl << "------------------- Volumetric grid deformation (ZONE " << iZone <<") ----------------" << endl; + + if (rank == MASTER_NODE) + cout << "Performing the deformation of the volumetric grid." << endl; + grid_movement[iZone][INST_0]->SetVolume_Deformation(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], false); + + /*--- Get parameters for convexity check ---*/ + bool ConvexityCheck; + unsigned short ConvexityCheck_MaxIter, ConvexityCheck_MaxDepth; + + tie(ConvexityCheck, ConvexityCheck_MaxIter, ConvexityCheck_MaxDepth) = config_container[iZone]->GetConvexityCheck(); + + /*--- Recursively change deformations if there are nonconvex elements. ---*/ + + if (ConvexityCheck && geometry_container[iZone][INST_0][MESH_0]->GetnNonconvexElements() > 0) { + if (rank == MASTER_NODE) { + cout << "Nonconvex elements present after deformation. " << endl; + cout << "Recursively lowering deformation magnitude." << endl; + } + + /*--- Load initial deformation values ---*/ + auto InitialDeformation = TotalDeformation; + + unsigned short ConvexityCheckIter, RecursionDepth = 0; + su2double DeformationFactor = 1.0, DeformationDifference = 1.0; + for (ConvexityCheckIter = 1; ConvexityCheckIter <= ConvexityCheck_MaxIter; ConvexityCheckIter++) { + + /*--- Recursively change deformation magnitude: + decrease if there are nonconvex elements, increase otherwise ---*/ + DeformationDifference /= 2.0; + + if (geometry_container[iZone][INST_0][MESH_0]->GetnNonconvexElements() > 0) { + DeformationFactor -= DeformationDifference; + } else { + RecursionDepth += 1; + + if (RecursionDepth == ConvexityCheck_MaxDepth) { + if (rank == MASTER_NODE) { + cout << "Maximum recursion depth reached." << endl; + cout << "Remaining amount of original deformation: "; + cout << DeformationFactor*100.0 << " percent. " << endl; + } + break; + } + + DeformationFactor += DeformationDifference; + } + + /*--- Load mesh to start every iteration with an undeformed grid ---*/ + for (auto iPoint = 0ul; iPoint < OriginalCoordinates.rows(); iPoint++) { + for (auto iDim = 0ul; iDim < OriginalCoordinates.cols(); iDim++) { + geometry_container[iZone][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, OriginalCoordinates(iPoint,iDim)); + } + } + + /*--- Set deformation magnitude as percentage of initial deformation ---*/ + for (auto iDV = 0u; iDV < driver_config->GetnDV(); iDV++) { + for (auto iDV_Value = 0u; iDV_Value < driver_config->GetnDV_Value(iDV); iDV_Value++) { + config_container[iZone]->SetDV_Value(iDV, iDV_Value, InitialDeformation[iDV][iDV_Value]*DeformationFactor); + } + } + + /*--- Surface grid deformation ---*/ + if (rank == MASTER_NODE) cout << "Performing the deformation of the surface grid." << endl; + + TotalDeformation = surface_movement[iZone]->SetSurface_Deformation(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); + + if (rank == MASTER_NODE) + cout << endl << "------------------- Volumetric grid deformation (ZONE " << iZone <<") ----------------" << endl; + + if (rank == MASTER_NODE) + cout << "Performing the deformation of the volumetric grid." << endl; + grid_movement[iZone][INST_0]->SetVolume_Deformation(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], false); + + if (rank == MASTER_NODE) { + cout << "Number of nonconvex elements for iteration " << ConvexityCheckIter << ": "; + cout << geometry_container[iZone][INST_0][MESH_0]->GetnNonconvexElements() << endl; + cout << "Remaining amount of original deformation: "; + cout << DeformationFactor*100.0 << " percent. " << endl; + } + + } + + } + } - - } - + } - - } - + } - - } - + } - + } void CDeformationDriver::Output() { - + /*--- Output deformed grid for visualization, if requested (surface and volumetric), in parallel - requires to move all the data to the master node---*/ - + requires to move all the data to the master node---*/ + if (rank == MASTER_NODE) cout << endl << "----------------------- Write deformed grid files -----------------------" << endl; - + for (iZone = 0; iZone < nZone; iZone++){ - - /*--- Compute Mesh Quality if requested. Necessary geometry preprocessing re-done beforehand. ---*/ - - if (config_container[iZone]->GetWrt_MeshQuality() && !driver_config->GetStructuralProblem()) { - - if (rank == MASTER_NODE) cout << "Recompute geometry properties necessary to evaluate mesh quality statistics.\n"; - - geometry_container[iZone]->SetPoint_Connectivity(); - geometry_container[iZone]->SetBoundVolume(); - geometry_container[iZone]->SetEdges(); - geometry_container[iZone]->SetVertex(config_container[iZone]); - geometry_container[iZone]->SetControlVolume(config_container[iZone], ALLOCATE); - geometry_container[iZone]->SetBoundControlVolume(config_container[iZone], ALLOCATE); - - if (rank == MASTER_NODE) cout << "Computing mesh quality statistics for the dual control volumes.\n"; - geometry_container[iZone]->ComputeMeshQualityStatistics(config_container[iZone]); - }// Mesh Quality Output - - /*--- Load the data --- */ - - output_container[iZone]->Load_Data(geometry_container[iZone], config_container[iZone], nullptr); - - output_container[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], OUTPUT_TYPE::MESH, driver_config->GetMesh_Out_FileName()); - - /*--- Set the file names for the visualization files ---*/ - - output_container[iZone]->SetVolume_Filename("volume_deformed"); - output_container[iZone]->SetSurface_Filename("surface_deformed"); - - for (unsigned short iFile = 0; iFile < config_container[iZone]->GetnVolumeOutputFiles(); iFile++){ - auto FileFormat = config_container[iZone]->GetVolumeOutputFiles(); - if (FileFormat[iFile] != OUTPUT_TYPE::RESTART_ASCII && - FileFormat[iFile] != OUTPUT_TYPE::RESTART_BINARY && - FileFormat[iFile] != OUTPUT_TYPE::CSV) - output_container[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone], FileFormat[iFile]); - } + + /*--- Compute Mesh Quality if requested. Necessary geometry preprocessing re-done beforehand. ---*/ + + if (config_container[iZone]->GetWrt_MeshQuality() && !driver_config->GetStructuralProblem()) { + + if (rank == MASTER_NODE) cout << "Recompute geometry properties necessary to evaluate mesh quality statistics.\n"; + + geometry_container[iZone][INST_0][MESH_0]->SetPoint_Connectivity(); + geometry_container[iZone][INST_0][MESH_0]->SetBoundVolume(); + geometry_container[iZone][INST_0][MESH_0]->SetEdges(); + geometry_container[iZone][INST_0][MESH_0]->SetVertex(config_container[iZone]); + geometry_container[iZone][INST_0][MESH_0]->SetControlVolume(config_container[iZone], ALLOCATE); + geometry_container[iZone][INST_0][MESH_0]->SetBoundControlVolume(config_container[iZone], ALLOCATE); + + if (rank == MASTER_NODE) cout << "Computing mesh quality statistics for the dual control volumes.\n"; + geometry_container[iZone][INST_0][MESH_0]->ComputeMeshQualityStatistics(config_container[iZone]); + }// Mesh Quality Output + + /*--- Load the data --- */ + + output_container[iZone]->Load_Data(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], nullptr); + + output_container[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone][INST_0][MESH_0], OUTPUT_TYPE::MESH, driver_config->GetMesh_Out_FileName()); + + /*--- Set the file names for the visualization files ---*/ + + output_container[iZone]->SetVolume_Filename("volume_deformed"); + output_container[iZone]->SetSurface_Filename("surface_deformed"); + + for (unsigned short iFile = 0; iFile < config_container[iZone]->GetnVolumeOutputFiles(); iFile++){ + auto FileFormat = config_container[iZone]->GetVolumeOutputFiles(); + if (FileFormat[iFile] != OUTPUT_TYPE::RESTART_ASCII && + FileFormat[iFile] != OUTPUT_TYPE::RESTART_BINARY && + FileFormat[iFile] != OUTPUT_TYPE::CSV) + output_container[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone][INST_0][MESH_0], FileFormat[iFile]); + } } - + if (!driver_config->GetDeform_Mesh()) { - if ((config_container[ZONE_0]->GetDesign_Variable(0) != NO_DEFORMATION) && - (config_container[ZONE_0]->GetDesign_Variable(0) != SCALE_GRID) && - (config_container[ZONE_0]->GetDesign_Variable(0) != TRANSLATE_GRID) && - (config_container[ZONE_0]->GetDesign_Variable(0) != ROTATE_GRID)) { - - /*--- Write the the free-form deformation boxes after deformation. ---*/ - - if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; - - surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); - + if ((config_container[ZONE_0]->GetDesign_Variable(0) != NO_DEFORMATION) && + (config_container[ZONE_0]->GetDesign_Variable(0) != SCALE_GRID) && + (config_container[ZONE_0]->GetDesign_Variable(0) != TRANSLATE_GRID) && + (config_container[ZONE_0]->GetDesign_Variable(0) != ROTATE_GRID)) { + + /*--- Write the the free-form deformation boxes after deformation. ---*/ + + if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; + + surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container[INST_0][MESH_0], config_container); + + } } - } } void CDeformationDriver::Postprocessing() { - + if (rank == MASTER_NODE) - cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; - + cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; + delete driver_config; driver_config = nullptr; - + for (iZone = 0; iZone < nZone; iZone++) { - if (numerics_container[iZone] != nullptr) { - for (unsigned int iTerm = 0; iTerm < MAX_TERMS*omp_get_max_threads(); iTerm++) { - delete numerics_container[iZone][iTerm]; + if (numerics_container[iZone] != nullptr) { + for (unsigned int iTerm = 0; iTerm < MAX_TERMS*omp_get_max_threads(); iTerm++) { + delete numerics_container[iZone][iTerm]; + } + delete [] numerics_container[iZone]; } - delete [] numerics_container[iZone]; - } } delete [] numerics_container; if (rank == MASTER_NODE) cout << "Deleted CNumerics container." << endl; - + for (iZone = 0; iZone < nZone; iZone++) { - delete solver_container[iZone]; + delete solver_container[iZone][INST_0][MESH_0][MESH_SOL]; } delete [] solver_container; if (rank == MASTER_NODE) cout << "Deleted CSolver container." << endl; - + if (geometry_container != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - delete geometry_container[iZone]; - } - delete [] geometry_container; + for (iZone = 0; iZone < nZone; iZone++) { + delete geometry_container[iZone][INST_0][MESH_0]; + } + delete [] geometry_container; } if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; - + if (surface_movement != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - delete surface_movement[iZone]; - } - delete [] surface_movement; + for (iZone = 0; iZone < nZone; iZone++) { + delete surface_movement[iZone]; + } + delete [] surface_movement; } if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; - + if (grid_movement != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - delete grid_movement[iZone]; - } - delete [] grid_movement; + for (iZone = 0; iZone < nZone; iZone++) { + delete grid_movement[iZone][INST_0]; + } + delete [] grid_movement; } if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; - + if (config_container != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - delete config_container[iZone]; - } - delete [] config_container; + for (iZone = 0; iZone < nZone; iZone++) { + delete config_container[iZone]; + } + delete [] config_container; } if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; - + if (output_container != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - delete output_container[iZone]; - } - delete [] output_container; + for (iZone = 0; iZone < nZone; iZone++) { + delete output_container[iZone]; + } + delete [] output_container; } if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; - + /*--- Exit the solver cleanly ---*/ - + if (rank == MASTER_NODE) - cout << endl << "------------------------- Exit Success (SU2_DEF) ------------------------" << endl << endl; -} - -vector CDeformationDriver::GetAllDeformMeshMarkersTag() const { - - vector interfaceBoundariesTagList; - unsigned short iMarker, nBoundariesMarker; - string Marker_Tag; - - nBoundariesMarker = config_container[ZONE_0]->GetnMarker_Deform_Mesh(); - interfaceBoundariesTagList.resize(nBoundariesMarker); - - for(iMarker=0; iMarker < nBoundariesMarker; iMarker++){ - Marker_Tag = config_container[ZONE_0]->GetMarker_Deform_Mesh_TagBound(iMarker); - interfaceBoundariesTagList[iMarker] = Marker_Tag; - } - - return interfaceBoundariesTagList; -} - -map CDeformationDriver::GetAllBoundaryMarkers() const { - - map allBoundariesMap; - unsigned short iMarker, nBoundaryMarkers; - string Marker_Tag; - - nBoundaryMarkers = config_container[ZONE_0]->GetnMarker_All(); - - for(iMarker=0; iMarker < nBoundaryMarkers; iMarker++){ - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - allBoundariesMap[Marker_Tag] = iMarker; - } - - return allBoundariesMap; -} - -map CDeformationDriver::GetAllBoundaryMarkersType() const { - - map allBoundariesTypeMap; - unsigned short iMarker, KindBC; - string Marker_Tag, Marker_Type; - - for(iMarker=0; iMarker < config_container[ZONE_0]->GetnMarker_All(); iMarker++){ - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - KindBC = config_container[ZONE_0]->GetMarker_All_KindBC(iMarker); - switch(KindBC){ - case EULER_WALL: - Marker_Type = "EULER_WALL"; - break; - case FAR_FIELD: - Marker_Type = "FARFIELD"; - break; - case ISOTHERMAL: - Marker_Type = "ISOTHERMAL"; - break; - case HEAT_FLUX: - Marker_Type = "HEATFLUX"; - break; - case INLET_FLOW: - Marker_Type = "INLET_FLOW"; - break; - case OUTLET_FLOW: - Marker_Type = "OUTLET_FLOW"; - break; - case SYMMETRY_PLANE: - Marker_Type = "SYMMETRY"; - break; - case SEND_RECEIVE: - Marker_Type = "SEND_RECEIVE"; - break; - default: - Marker_Type = "UNKNOWN_TYPE"; - } - allBoundariesTypeMap[Marker_Tag] = Marker_Type; - } - - return allBoundariesTypeMap; -} - -unsigned long CDeformationDriver::GetNumberVertices(unsigned short iMarker) const { - - return geometry_container[ZONE_0]->nVertex[iMarker]; - -} - -unsigned long CDeformationDriver::GetNumberHaloVertices(unsigned short iMarker) const { - - unsigned long nHaloVertices, iVertex, iPoint; - - nHaloVertices = 0; - for(iVertex = 0; iVertex < geometry_container[ZONE_0]->nVertex[iMarker]; iVertex++){ - iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); - if(!(geometry_container[ZONE_0]->nodes->GetDomain(iPoint))) nHaloVertices += 1; - } - - return nHaloVertices; - -} - -unsigned long CDeformationDriver::GetVertexGlobalIndex(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint, GlobalIndex; - - iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); - GlobalIndex = geometry_container[ZONE_0]->nodes->GetGlobalIndex(iPoint); - - return GlobalIndex; - -} - -bool CDeformationDriver::IsAHaloNode(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - - iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); - if(geometry_container[ZONE_0]->nodes->GetDomain(iPoint)) return false; - else return true; - -} - -vector CDeformationDriver::GetInitialMeshCoord(unsigned short iMarker, unsigned long iVertex) const { - - vector coord(3,0.0); - vector coord_passive(3, 0.0); - - auto iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); - - for (auto iDim = 0 ; iDim < geometry_container[ZONE_0]->GetnDim(); iDim++){ - coord[iDim] = solver_container[ZONE_0]->GetNodes()->GetMesh_Coord(iPoint,iDim); - } - - coord_passive[0] = SU2_TYPE::GetValue(coord[0]); - coord_passive[1] = SU2_TYPE::GetValue(coord[1]); - coord_passive[2] = SU2_TYPE::GetValue(coord[2]); - - return coord_passive; + cout << endl << "------------------------- Exit Success (SU2_DEF) ------------------------" << endl << endl; } -vector CDeformationDriver::GetVertexNormal(unsigned short iMarker, unsigned long iVertex, bool unitNormal) const { - - int nDim = geometry_container[ZONE_0]->GetnDim(); - - su2double *Normal; - su2double Area; - vector ret_Normal(3, 0.0); - vector ret_Normal_passive(3, 0.0); - - Normal = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNormal(); - - if (!unitNormal) { - - ret_Normal_passive[0] = SU2_TYPE::GetValue(Normal[0]); - ret_Normal_passive[1] = SU2_TYPE::GetValue(Normal[1]); - if(nDim>2) ret_Normal_passive[2] = SU2_TYPE::GetValue(Normal[2]); - - return ret_Normal_passive; - } - - Area = GeometryToolbox::Norm(nDim, Normal); - - ret_Normal[0] = Normal[0]/Area; - ret_Normal[1] = Normal[1]/Area; - if(nDim>2) ret_Normal[2] = Normal[2]/Area; - - ret_Normal_passive[0] = SU2_TYPE::GetValue(ret_Normal[0]); - ret_Normal_passive[1] = SU2_TYPE::GetValue(ret_Normal[1]); - ret_Normal_passive[2] = SU2_TYPE::GetValue(ret_Normal[2]); - - return ret_Normal_passive; -} - -void CDeformationDriver::SetMeshDisplacement(unsigned short iMarker, unsigned long iVertex, passivedouble DispX, passivedouble DispY, passivedouble DispZ) { - - unsigned long iPoint; - su2double MeshDispl[3] = {0.0,0.0,0.0}; - - MeshDispl[0] = DispX; - MeshDispl[1] = DispY; - MeshDispl[2] = DispZ; - - iPoint = geometry_container[ZONE_0]->vertex[iMarker][iVertex]->GetNode(); - - solver_container[ZONE_0]->GetNodes()->SetBound_Disp(iPoint, MeshDispl); - -} - -void CDeformationDriver::CommunicateMeshDisplacement(void) { - - solver_container[ZONE_0]->InitiateComms(geometry_container[ZONE_0], config_container[ZONE_0], MESH_DISPLACEMENTS); - solver_container[ZONE_0]->CompleteComms(geometry_container[ZONE_0], config_container[ZONE_0], MESH_DISPLACEMENTS); - +void CDeformationDriver::CommunicateMeshDisplacements(void) { + + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->InitiateComms(geometry_container[ZONE_0][INST_0][MESH_0], config_container[ZONE_0], MESH_DISPLACEMENTS); + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->CompleteComms(geometry_container[ZONE_0][INST_0][MESH_0], config_container[ZONE_0], MESH_DISPLACEMENTS); + } diff --git a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp index 195dbf59aa6..63555b249c2 100644 --- a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp @@ -1,8 +1,8 @@ /*! * \file CDiscAdjDeformationDriver.cpp * \brief Main subroutines for driving the projection of sensitivities. - * \author T. Economon, H. Kline, R. Sanchez - * \version 7.1.1 "Blackbird" + * \author T. Economon, H. Kline, R. Sanchez, A. Gastaldi, H. Patel + * \version 7.3.0 "Blackbird" * * SU2 Project Website: https://su2code.github.io * @@ -31,76 +31,77 @@ using namespace std; -CDiscAdjDeformationDriver::CDiscAdjDeformationDriver(char* confFile, SU2_Comm MPICommunicator) { - +CDiscAdjDeformationDriver::CDiscAdjDeformationDriver(char* confFile, SU2_Comm MPICommunicator): + CDriverBase(confFile, 1, MPICommunicator) +{ /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ - #ifdef HAVE_MPI - #if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE) - SU2_MPI::Init_AMPI(); - #endif - #endif - +#ifdef HAVE_MPI +#if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE) + SU2_MPI::Init_AMPI(); +#endif +#endif + SU2_MPI::SetComm(MPICommunicator); - + rank = SU2_MPI::GetRank(); size = SU2_MPI::GetSize(); - + /*--- Copy the config filename ---*/ strcpy(config_file_name, confFile); - + /*--- Read the name and format of the input mesh file to get from the mesh - file the number of zones and dimensions from the numerical grid (required - for variables allocation) ---*/ - + file the number of zones and dimensions from the numerical grid (required + for variables allocation) ---*/ + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DOT); - + nZone = driver_config->GetnZone(); - + /*--- Initialize containers --- */ - + SetContainers_Null(); - + /*--- Preprocessing of the config files. ---*/ - + Input_Preprocessing(); - + /*--- Set up a timer for performance benchmarking ---*/ - + StartTime = SU2_MPI::Wtime(); - + /*--- Preprocessing of the geometry for all zones. ---*/ - + Geometrical_Preprocessing(); - + /*--- Preprocessing of the outputs for all zones. ---*/ - + Output_Preprocessing(); - + /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ - + StopTime = SU2_MPI::Wtime(); - + /*--- Compute/print the total time for performance benchmarking. ---*/ - + UsedTime = StopTime-StartTime; UsedTimePreproc = UsedTime; UsedTimeCompute = 0.0; - + } CDiscAdjDeformationDriver::~CDiscAdjDeformationDriver(void) { - + } void CDiscAdjDeformationDriver::SetContainers_Null() { - + /*--- Definition of the containers per zones ---*/ - + config_container = new CConfig*[nZone] (); geometry_container = new CGeometry**[nZone] (); surface_movement = new CSurfaceMovement*[nZone] (); grid_movement = new CVolumetricMovement*[nZone] (); - + nInst = new unsigned short[nZone]; for (iZone = 0; iZone < nZone; iZone++) { nInst[iZone] = 1; @@ -108,32 +109,34 @@ void CDiscAdjDeformationDriver::SetContainers_Null() { } void CDiscAdjDeformationDriver::Input_Preprocessing() { - - // TODO Check that config is for Discrete Adjoint ! + + if (!config_container[iZone]->GetDiscrete_Adjoint()) { + SU2_MPI::Error("The discrete adjoint solver was not specified in the configuration file.", CURRENT_FUNCTION); + } /*--- Initialize a char to store the zone filename ---*/ char zone_file_name[MAX_STRING_SIZE]; - + /*--- Loop over all zones to initialize the various classes. In most - cases, nZone is equal to one. This represents the solution of a partial - differential equation on a single block, unstructured mesh. ---*/ - + cases, nZone is equal to one. This represents the solution of a partial + differential equation on a single block, unstructured mesh. ---*/ + for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Definition of the configuration option class for all zones. In this - constructor, the input configuration file is parsed and all options are - read and stored. ---*/ - + + /*--- Definition of the configuration option class for all zones. In this + constructor, the input configuration file is parsed and all options are + read and stored. ---*/ + if (driver_config->GetnConfigFiles() > 0){ strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DOT, iZone, nZone, true); } else { config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DOT, iZone, nZone, true); } - + config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); } - + /*--- Set the multizone part of the problem. ---*/ if (driver_config->GetMultizone_Problem()){ for (iZone = 0; iZone < nZone; iZone++) { @@ -144,216 +147,224 @@ void CDiscAdjDeformationDriver::Input_Preprocessing() { } void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { - + /*--- Loop over all zones to initialize the various classes. In most cases, nZone is equal to one. This represents the solution of a partial differential equation on a single block, unstructured mesh. ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - + + for (iZone = 0; iZone < nZone; iZone++) { + /*--- Determine whether or not the FEM solver is used, which decides the type of geometry classes that are instantiated. ---*/ const bool fem_solver = config_container[iZone]->GetFEMSolver(); - + /*--- Read the number of instances for each zone ---*/ - + nInst[iZone] = config_container[iZone]->GetnTimeInstances(); - + geometry_container[iZone] = new CGeometry*[nInst[iZone]]; - + for (iInst = 0; iInst < nInst[iZone]; iInst++){ - + /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ - + CGeometry *geometry_aux = nullptr; - + /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ - + geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); - + /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - + if ( fem_solver ) geometry_aux->SetColorFEMGrid_Parallel(config_container[iZone]); else geometry_aux->SetColorGrid_Parallel(config_container[iZone]); - + /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - + if( fem_solver ) { switch( config_container[iZone]->GetKind_FEM_Flow() ) { - case DG: { - geometry_container[iZone][iInst] = new CMeshFEM_DG(geometry_aux, config_container[iZone]); - break; - } + case DG: { + geometry_container[iZone][iInst] = new CMeshFEM_DG(geometry_aux, config_container[iZone]); + break; + } } } else { geometry_container[iZone][iInst] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); } - + /*--- Deallocate the memory of geometry_aux ---*/ - + delete geometry_aux; - + /*--- Add the Send/Receive boundaries ---*/ - + geometry_container[iZone][iInst]->SetSendReceive(config_container[iZone]); - + /*--- Add the Send/Receive boundaries ---*/ - + geometry_container[iZone][iInst]->SetBoundaries(config_container[iZone]); - + /*--- Create the vertex structure (required for MPI) ---*/ - + if (rank == MASTER_NODE) cout << "Identify vertices." << endl; geometry_container[iZone][iInst]->SetVertex(config_container[iZone]); - + /*--- Store the global to local mapping after preprocessing. ---*/ - + if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; geometry_container[iZone][iInst]->SetGlobal_to_Local_Point(); - + /* Test for a fem solver, because some more work must be done. */ - + if (fem_solver) { - + /*--- Carry out a dynamic cast to CMeshFEM_DG, such that it is not needed to define all virtual functions in the base class CGeometry. ---*/ CMeshFEM_DG *DGMesh = dynamic_cast(geometry_container[iZone][iInst]); - + /*--- Determine the standard elements for the volume elements. ---*/ if (rank == MASTER_NODE) cout << "Creating standard volume elements." << endl; DGMesh->CreateStandardVolumeElements(config_container[iZone]); - + /*--- Create the face information needed to compute the contour integral for the elements in the Discontinuous Galerkin formulation. ---*/ if (rank == MASTER_NODE) cout << "Creating face information." << endl; DGMesh->CreateFaces(config_container[iZone]); } } - + if (rank == MASTER_NODE) - cout << "\n----------------------- Preprocessing computations ----------------------" << endl; - + cout << "\n----------------------- Preprocessing computations ----------------------" << endl; + /*--- Compute elements surrounding points, points surrounding points ---*/ - + if (rank == MASTER_NODE) cout << "Setting local point connectivity." << endl; geometry_container[iZone][INST_0]->SetPoint_Connectivity(); - + /*--- Check the orientation before computing geometrical quantities ---*/ - + geometry_container[iZone][INST_0]->SetBoundVolume(); if (config_container[iZone]->GetReorientElements()) { if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the elements." << endl; geometry_container[iZone][INST_0]->Check_IntElem_Orientation(config_container[iZone]); geometry_container[iZone][INST_0]->Check_BoundElem_Orientation(config_container[iZone]); } - + /*--- Create the edge structure ---*/ - + if (rank == MASTER_NODE) cout << "Identify edges and vertices." << endl; geometry_container[iZone][INST_0]->SetEdges(); geometry_container[iZone][INST_0]->SetVertex(config_container[iZone]); - + /*--- Create the dual control volume structures ---*/ - + if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; geometry_container[iZone][INST_0]->SetBoundControlVolume(config_container[ZONE_0], ALLOCATE); - + /*--- Store the global to local mapping after preprocessing. ---*/ - + if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; geometry_container[iZone][INST_0]->SetGlobal_to_Local_Point(); - + /*--- Create the point-to-point MPI communication structures. ---*/ - + geometry_container[iZone][INST_0]->PreprocessP2PComms(geometry_container[iZone][INST_0], config_container[iZone]); - + } } void CDiscAdjDeformationDriver::Output_Preprocessing() { - + } void CDiscAdjDeformationDriver::Run() { - + for (iZone = 0; iZone < nZone; iZone++) { - if (rank == MASTER_NODE) cout << "Reading volume sensitivities at each node from file." << endl; - grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone][INST_0], config_container[iZone]); - - /*--- Read in sensitivities from file. ---*/ - if (config_container[ZONE_0]->GetSensitivity_Format() == UNORDERED_ASCII) - geometry_container[iZone][INST_0]->ReadUnorderedSensitivity(config_container[iZone]); - else - geometry_container[iZone][INST_0]->SetSensitivity(config_container[iZone]); - - if (rank == MASTER_NODE) cout << "\n---------------------- Mesh sensitivity computation ---------------------" << endl; + if (rank == MASTER_NODE) cout << "Reading volume sensitivities at each node from file." << endl; + grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone][INST_0], config_container[iZone]); + + /*--- Read in sensitivities from file. ---*/ + if (config_container[ZONE_0]->GetSensitivity_Format() == UNORDERED_ASCII) + geometry_container[iZone][INST_0]->ReadUnorderedSensitivity(config_container[iZone]); + else + geometry_container[iZone][INST_0]->SetSensitivity(config_container[iZone]); + + if (rank == MASTER_NODE) cout << "\n---------------------- Mesh sensitivity computation ---------------------" << endl; + if (config_container[iZone]->GetDiscrete_Adjoint() && config_container[iZone]->GetSmoothGradient() && + config_container[iZone]->GetSobMode() == ENUM_SOBOLEV_MODUS::MESH_LEVEL) { + DerivativeTreatment_MeshSensitivity(geometry_container[iZone][INST_0], config_container[iZone], grid_movement[iZone]); + } else { grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone][INST_0], config_container[iZone], false, true); + } } - + if (rank == MASTER_NODE) cout << "\n------------------------ Mesh sensitivity Output ------------------------" << endl; SetSensitivity_Files(geometry_container, config_container, nZone); - + /*--- Initialize structure to store the gradient ---*/ Gradient = new su2double*[config_container[ZONE_0]->GetnDV()]; - + for (auto iDV = 0u; iDV < config_container[ZONE_0]->GetnDV(); iDV++) { /*--- Initialize to zero ---*/ Gradient[iDV] = new su2double[config_container[ZONE_0]->GetnDV_Value(iDV)](); } - + Gradient_file.precision(driver_config->OptionIsSet("OUTPUT_PRECISION") ? driver_config->GetOutput_Precision() : 6); - + /*--- For multizone computations the gradient contributions are summed up and written into one file. ---*/ for (iZone = 0; iZone < nZone; iZone++){ if ((config_container[iZone]->GetDesign_Variable(0) != NONE) && (config_container[iZone]->GetDesign_Variable(0) != SURFACE_FILE)) { - - if (rank == MASTER_NODE) - cout << "\n---------- Start gradient evaluation using sensitivity information ----------" << endl; - - /*--- Definition of the Class for surface deformation ---*/ - - surface_movement[iZone] = new CSurfaceMovement(); - - /*--- Copy coordinates to the surface structure ---*/ - - surface_movement[iZone]->CopyBoundary(geometry_container[iZone][INST_0], config_container[iZone]); - - /*--- If AD mode is enabled we can use it to compute the projection, - * otherwise we use finite differences. ---*/ - - if (config_container[iZone]->GetAD_Mode()) - SetDiscAdjDeformation_AD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); - else - SetDiscAdjDeformation_FD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); - + + if (rank == MASTER_NODE) + cout << "\n---------- Start gradient evaluation using sensitivity information ----------" << endl; + + /*--- Definition of the Class for surface deformation ---*/ + + surface_movement[iZone] = new CSurfaceMovement(); + + /*--- Copy coordinates to the surface structure ---*/ + + surface_movement[iZone]->CopyBoundary(geometry_container[iZone][INST_0], config_container[iZone]); + + /*--- If AD mode is enabled we can use it to compute the projection, + * otherwise we use finite differences. ---*/ + + if (config_container[iZone]->GetAD_Mode()) + if (config_container[iZone]->GetSmoothGradient()) { + DerivativeTreatment_Gradient(geometry_container[iZone][INST_0], config_container[iZone], grid_movement[iZone], surface_movement[iZone] , Gradient); + } else { + SetProjection_AD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); + } + } else { + SetProjection_FD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); } } // for iZone - + /*--- Write the gradient to a file ---*/ - + if (rank == MASTER_NODE) Gradient_file.open(config_container[ZONE_0]->GetObjFunc_Grad_FileName().c_str(), ios::out); - + /*--- Print gradients to screen and writes to file ---*/ - + OutputGradient(Gradient, config_container[ZONE_0], Gradient_file); - + } void CDiscAdjDeformationDriver::Postprocessing() { - + for (auto iDV = 0u; iDV < config_container[ZONE_0]->GetnDV(); iDV++){ - delete [] Gradient[iDV]; + delete [] Gradient[iDV]; } delete [] Gradient; - + delete driver_config; driver_config = nullptr; - + if (rank == MASTER_NODE) cout << "\n------------------------- Solver Postprocessing -------------------------" << endl; - + if (geometry_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { if (geometry_container[iZone] != nullptr) { @@ -366,7 +377,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { delete [] geometry_container; } if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; - + if (surface_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { delete surface_movement[iZone]; @@ -374,7 +385,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { delete [] surface_movement; } if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; - + if (grid_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { delete grid_movement[iZone]; @@ -382,7 +393,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { delete [] grid_movement; } if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; - + if (config_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { delete config_container[iZone]; @@ -390,540 +401,620 @@ void CDiscAdjDeformationDriver::Postprocessing() { delete [] config_container; } if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; - + } -void CDiscAdjDeformationDriver::SetDiscAdjDeformation_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ - - unsigned short iDV, nDV, iFFDBox, nDV_Value, iMarker, iDim; - unsigned long iVertex, iPoint; - su2double delta_eps, my_Gradient, localGradient, *Normal, dS, *VarCoord, Sensitivity, - dalpha[3], deps[3], dalpha_deps; - bool *UpdatePoint, MoveSurface, Local_MoveSurface; - CFreeFormDefBox **FFDBox; - - int rank = SU2_MPI::GetRank(); - - nDV = config->GetnDV(); - - /*--- Boolean controlling points to be updated ---*/ - - UpdatePoint = new bool[geometry->GetnPoint()]; - - /*--- Definition of the FFD deformation class ---*/ - - unsigned short nFFDBox = MAX_NUMBER_FFD; - FFDBox = new CFreeFormDefBox*[nFFDBox]; - for (iFFDBox = 0; iFFDBox < MAX_NUMBER_FFD; iFFDBox++) FFDBox[iFFDBox] = nullptr; - - for (iDV = 0; iDV < nDV; iDV++){ - nDV_Value = config->GetnDV_Value(iDV); - if (nDV_Value != 1){ - SU2_MPI::Error("The DiscAdjDeformation using finite differences currently only supports a fixed direction of movement for FFD points.", CURRENT_FUNCTION); +void CDiscAdjDeformationDriver::SetProjection_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ + + unsigned short iDV, nDV, iFFDBox, nDV_Value, iMarker, iDim; + unsigned long iVertex, iPoint; + su2double delta_eps, my_Gradient, localGradient, *Normal, dS, *VarCoord, Sensitivity, + dalpha[3], deps[3], dalpha_deps; + bool *UpdatePoint, MoveSurface, Local_MoveSurface; + CFreeFormDefBox **FFDBox; + + int rank = SU2_MPI::GetRank(); + + nDV = config->GetnDV(); + + /*--- Boolean controlling points to be updated ---*/ + + UpdatePoint = new bool[geometry->GetnPoint()]; + + /*--- Definition of the FFD deformation class ---*/ + + unsigned short nFFDBox = MAX_NUMBER_FFD; + FFDBox = new CFreeFormDefBox*[nFFDBox]; + for (iFFDBox = 0; iFFDBox < MAX_NUMBER_FFD; iFFDBox++) FFDBox[iFFDBox] = nullptr; + + for (iDV = 0; iDV < nDV; iDV++){ + nDV_Value = config->GetnDV_Value(iDV); + if (nDV_Value != 1){ + SU2_MPI::Error("The projection using finite differences currently only supports a fixed direction of movement for FFD points.", CURRENT_FUNCTION); + } } - } - - /*--- Continuous adjoint gradient computation ---*/ - - if (rank == MASTER_NODE) - cout << "Evaluate functional gradient using Finite Differences." << endl; - - for (iDV = 0; iDV < nDV; iDV++) { - - MoveSurface = true; - Local_MoveSurface = true; - - /*--- Free Form deformation based ---*/ - - if ((config->GetDesign_Variable(iDV) == FFD_CONTROL_POINT_2D) || - (config->GetDesign_Variable(iDV) == FFD_CAMBER_2D) || - (config->GetDesign_Variable(iDV) == FFD_THICKNESS_2D) || - (config->GetDesign_Variable(iDV) == FFD_TWIST_2D) || - (config->GetDesign_Variable(iDV) == FFD_CONTROL_POINT) || - (config->GetDesign_Variable(iDV) == FFD_NACELLE) || - (config->GetDesign_Variable(iDV) == FFD_GULL) || - (config->GetDesign_Variable(iDV) == FFD_TWIST) || - (config->GetDesign_Variable(iDV) == FFD_ROTATION) || - (config->GetDesign_Variable(iDV) == FFD_CAMBER) || - (config->GetDesign_Variable(iDV) == FFD_THICKNESS) || - (config->GetDesign_Variable(iDV) == FFD_ANGLE_OF_ATTACK)) { - - /*--- Read the FFD information in the first iteration ---*/ - - if (iDV == 0) { - - if (rank == MASTER_NODE) - cout << "Read the FFD information from mesh file." << endl; - - /*--- Read the FFD information from the grid file ---*/ - - surface_movement->ReadFFDInfo(geometry, config, FFDBox, config->GetMesh_FileName()); - - /*--- If the FFDBox was not defined in the input file ---*/ - if (!surface_movement->GetFFDBoxDefinition()) { - SU2_MPI::Error("The input grid doesn't have the entire FFD information!", CURRENT_FUNCTION); + + /*--- Continuous adjoint gradient computation ---*/ + + if (rank == MASTER_NODE) + cout << "Evaluate functional gradient using Finite Differences." << endl; + + for (iDV = 0; iDV < nDV; iDV++) { + + MoveSurface = true; + Local_MoveSurface = true; + + /*--- Free Form deformation based ---*/ + + if ((config->GetDesign_Variable(iDV) == FFD_CONTROL_POINT_2D) || + (config->GetDesign_Variable(iDV) == FFD_CAMBER_2D) || + (config->GetDesign_Variable(iDV) == FFD_THICKNESS_2D) || + (config->GetDesign_Variable(iDV) == FFD_TWIST_2D) || + (config->GetDesign_Variable(iDV) == FFD_CONTROL_POINT) || + (config->GetDesign_Variable(iDV) == FFD_NACELLE) || + (config->GetDesign_Variable(iDV) == FFD_GULL) || + (config->GetDesign_Variable(iDV) == FFD_TWIST) || + (config->GetDesign_Variable(iDV) == FFD_ROTATION) || + (config->GetDesign_Variable(iDV) == FFD_CAMBER) || + (config->GetDesign_Variable(iDV) == FFD_THICKNESS) || + (config->GetDesign_Variable(iDV) == FFD_ANGLE_OF_ATTACK)) { + + /*--- Read the FFD information in the first iteration ---*/ + + if (iDV == 0) { + + if (rank == MASTER_NODE) + cout << "Read the FFD information from mesh file." << endl; + + /*--- Read the FFD information from the grid file ---*/ + + surface_movement->ReadFFDInfo(geometry, config, FFDBox, config->GetMesh_FileName()); + + /*--- If the FFDBox was not defined in the input file ---*/ + if (!surface_movement->GetFFDBoxDefinition()) { + SU2_MPI::Error("The input grid doesn't have the entire FFD information!", CURRENT_FUNCTION); + } + + for (iFFDBox = 0; iFFDBox < surface_movement->GetnFFDBox(); iFFDBox++) { + + if (rank == MASTER_NODE) cout << "Checking FFD box dimension." << endl; + surface_movement->CheckFFDDimension(geometry, config, FFDBox[iFFDBox], iFFDBox); + + if (rank == MASTER_NODE) cout << "Check the FFD box intersections with the solid surfaces." << endl; + surface_movement->CheckFFDIntersections(geometry, config, FFDBox[iFFDBox], iFFDBox); + + } + + if (rank == MASTER_NODE) + cout <<"-------------------------------------------------------------------------" << endl; + + } + + if (rank == MASTER_NODE) { + cout << endl << "Design variable number "<< iDV <<"." << endl; + cout << "Performing 3D deformation of the surface." << endl; + } + + /*--- Apply the control point change ---*/ + + MoveSurface = false; + + for (iFFDBox = 0; iFFDBox < surface_movement->GetnFFDBox(); iFFDBox++) { + + /*--- Reset FFD box ---*/ + + switch (config->GetDesign_Variable(iDV) ) { + case FFD_CONTROL_POINT_2D : Local_MoveSurface = surface_movement->SetFFDCPChange_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_CAMBER_2D : Local_MoveSurface = surface_movement->SetFFDCamber_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_THICKNESS_2D : Local_MoveSurface = surface_movement->SetFFDThickness_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_TWIST_2D : Local_MoveSurface = surface_movement->SetFFDTwist_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_CONTROL_POINT : Local_MoveSurface = surface_movement->SetFFDCPChange(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_NACELLE : Local_MoveSurface = surface_movement->SetFFDNacelle(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_GULL : Local_MoveSurface = surface_movement->SetFFDGull(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_TWIST : Local_MoveSurface = surface_movement->SetFFDTwist(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_ROTATION : Local_MoveSurface = surface_movement->SetFFDRotation(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_CAMBER : Local_MoveSurface = surface_movement->SetFFDCamber(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_THICKNESS : Local_MoveSurface = surface_movement->SetFFDThickness(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_CONTROL_SURFACE : Local_MoveSurface = surface_movement->SetFFDControl_Surface(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; + case FFD_ANGLE_OF_ATTACK : Gradient[iDV][0] = config->GetAoA_Sens(); break; + } + + /*--- Recompute cartesian coordinates using the new control points position ---*/ + + if (Local_MoveSurface) { + MoveSurface = true; + surface_movement->SetCartesianCoord(geometry, config, FFDBox[iFFDBox], iFFDBox, true); + } + + } + } - - for (iFFDBox = 0; iFFDBox < surface_movement->GetnFFDBox(); iFFDBox++) { - - if (rank == MASTER_NODE) cout << "Checking FFD box dimension." << endl; - surface_movement->CheckFFDDimension(geometry, config, FFDBox[iFFDBox], iFFDBox); - - if (rank == MASTER_NODE) cout << "Check the FFD box intersections with the solid surfaces." << endl; - surface_movement->CheckFFDIntersections(geometry, config, FFDBox[iFFDBox], iFFDBox); - + + /*--- Hicks Henne design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == HICKS_HENNE) { + surface_movement->SetHicksHenne(geometry, config, iDV, true); } - - if (rank == MASTER_NODE) - cout <<"-------------------------------------------------------------------------" << endl; - - } - - if (rank == MASTER_NODE) { - cout << endl << "Design variable number "<< iDV <<"." << endl; - cout << "Performing 3D deformation of the surface." << endl; - } - - /*--- Apply the control point change ---*/ - - MoveSurface = false; - - for (iFFDBox = 0; iFFDBox < surface_movement->GetnFFDBox(); iFFDBox++) { - - /*--- Reset FFD box ---*/ - - switch (config->GetDesign_Variable(iDV) ) { - case FFD_CONTROL_POINT_2D : Local_MoveSurface = surface_movement->SetFFDCPChange_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_CAMBER_2D : Local_MoveSurface = surface_movement->SetFFDCamber_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_THICKNESS_2D : Local_MoveSurface = surface_movement->SetFFDThickness_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_TWIST_2D : Local_MoveSurface = surface_movement->SetFFDTwist_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_CONTROL_POINT : Local_MoveSurface = surface_movement->SetFFDCPChange(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_NACELLE : Local_MoveSurface = surface_movement->SetFFDNacelle(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_GULL : Local_MoveSurface = surface_movement->SetFFDGull(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_TWIST : Local_MoveSurface = surface_movement->SetFFDTwist(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_ROTATION : Local_MoveSurface = surface_movement->SetFFDRotation(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_CAMBER : Local_MoveSurface = surface_movement->SetFFDCamber(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_THICKNESS : Local_MoveSurface = surface_movement->SetFFDThickness(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_CONTROL_SURFACE : Local_MoveSurface = surface_movement->SetFFDControl_Surface(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_ANGLE_OF_ATTACK : Gradient[iDV][0] = config->GetAoA_Sens(); break; + + /*--- Surface bump design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == SURFACE_BUMP) { + surface_movement->SetSurface_Bump(geometry, config, iDV, true); } - - /*--- Recompute cartesian coordinates using the new control points position ---*/ - - if (Local_MoveSurface) { - MoveSurface = true; - surface_movement->SetCartesianCoord(geometry, config, FFDBox[iFFDBox], iFFDBox, true); + + /*--- Kulfan (CST) design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == CST) { + surface_movement->SetCST(geometry, config, iDV, true); } - - } - - } - - /*--- Hicks Henne design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == HICKS_HENNE) { - surface_movement->SetHicksHenne(geometry, config, iDV, true); - } - - /*--- Surface bump design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == SURFACE_BUMP) { - surface_movement->SetSurface_Bump(geometry, config, iDV, true); - } - - /*--- Kulfan (CST) design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == CST) { - surface_movement->SetCST(geometry, config, iDV, true); - } - - /*--- Displacement design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == TRANSLATION) { - surface_movement->SetTranslation(geometry, config, iDV, true); - } - - /*--- Angle of Attack design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == ANGLE_OF_ATTACK) { - Gradient[iDV][0] = config->GetAoA_Sens(); - } - - /*--- Scale design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == SCALE) { - surface_movement->SetScale(geometry, config, iDV, true); - } - - /*--- Rotation design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == ROTATION) { - surface_movement->SetRotation(geometry, config, iDV, true); - } - - /*--- NACA_4Digits design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == NACA_4DIGITS) { - surface_movement->SetNACA_4Digits(geometry, config); - } - - /*--- Parabolic design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == PARABOLIC) { - surface_movement->SetParabolic(geometry, config); - } - - /*--- Design variable not implement ---*/ - - else { - if (rank == MASTER_NODE) - cout << "Design Variable not implement yet" << endl; - } - - /*--- Load the delta change in the design variable (finite difference step). ---*/ - - if ((config->GetDesign_Variable(iDV) != ANGLE_OF_ATTACK) && - (config->GetDesign_Variable(iDV) != FFD_ANGLE_OF_ATTACK)) { - - /*--- If the Angle of attack is not involved, reset the value of the gradient ---*/ - - my_Gradient = 0.0; Gradient[iDV][0] = 0.0; - - if (MoveSurface) { - - delta_eps = config->GetDV_Value(iDV); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - UpdatePoint[iPoint] = true; - - 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 ((iPoint < geometry->GetnPointDomain()) && UpdatePoint[iPoint]) { - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - Sensitivity = geometry->vertex[iMarker][iVertex]->GetAuxVar(); - - dS = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { - dS += Normal[iDim]*Normal[iDim]; - deps[iDim] = VarCoord[iDim] / delta_eps; - } - dS = sqrt(dS); - - dalpha_deps = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { - dalpha[iDim] = Normal[iDim] / dS; - dalpha_deps -= dalpha[iDim]*deps[iDim]; + + /*--- Displacement design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == TRANSLATION) { + surface_movement->SetTranslation(geometry, config, iDV, true); + } + + /*--- Angle of Attack design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == ANGLE_OF_ATTACK) { + Gradient[iDV][0] = config->GetAoA_Sens(); + } + + /*--- Scale design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == SCALE) { + surface_movement->SetScale(geometry, config, iDV, true); + } + + /*--- Rotation design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == ROTATION) { + surface_movement->SetRotation(geometry, config, iDV, true); + } + + /*--- NACA_4Digits design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == NACA_4DIGITS) { + surface_movement->SetNACA_4Digits(geometry, config); + } + + /*--- Parabolic design variable ---*/ + + else if (config->GetDesign_Variable(iDV) == PARABOLIC) { + surface_movement->SetParabolic(geometry, config); + } + + /*--- Design variable not implemented ---*/ + + else { + if (rank == MASTER_NODE) + cout << "Design Variable not implemented yet" << endl; + } + + /*--- Load the delta change in the design variable (finite difference step). ---*/ + + if ((config->GetDesign_Variable(iDV) != ANGLE_OF_ATTACK) && + (config->GetDesign_Variable(iDV) != FFD_ANGLE_OF_ATTACK)) { + + /*--- If the Angle of attack is not involved, reset the value of the gradient ---*/ + + my_Gradient = 0.0; Gradient[iDV][0] = 0.0; + + if (MoveSurface) { + + delta_eps = config->GetDV_Value(iDV); + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) + UpdatePoint[iPoint] = true; + + 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 ((iPoint < geometry->GetnPointDomain()) && UpdatePoint[iPoint]) { + + Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + Sensitivity = geometry->vertex[iMarker][iVertex]->GetAuxVar(); + + dS = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { + dS += Normal[iDim]*Normal[iDim]; + deps[iDim] = VarCoord[iDim] / delta_eps; + } + dS = sqrt(dS); + + dalpha_deps = 0.0; + for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { + dalpha[iDim] = Normal[iDim] / dS; + dalpha_deps -= dalpha[iDim]*deps[iDim]; + } + + my_Gradient += Sensitivity*dalpha_deps; + UpdatePoint[iPoint] = false; + } + } + } } - - my_Gradient += Sensitivity*dalpha_deps; - UpdatePoint[iPoint] = false; - } } - } + + SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + Gradient[iDV][0] += localGradient; } - } - - SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - Gradient[iDV][0] += localGradient; } - } - - /*--- Delete memory for parameterization. ---*/ - - if (FFDBox != nullptr) { - for (iFFDBox = 0; iFFDBox < MAX_NUMBER_FFD; iFFDBox++) { - if (FFDBox[iFFDBox] != nullptr) { - delete FFDBox[iFFDBox]; - } + + /*--- Delete memory for parameterization. ---*/ + + if (FFDBox != nullptr) { + for (iFFDBox = 0; iFFDBox < MAX_NUMBER_FFD; iFFDBox++) { + if (FFDBox[iFFDBox] != nullptr) { + delete FFDBox[iFFDBox]; + } + } + delete [] FFDBox; } - delete [] FFDBox; - } - - delete [] UpdatePoint; - + + delete [] UpdatePoint; + } -void CDiscAdjDeformationDriver::SetDiscAdjDeformation_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ - - su2double DV_Value, *VarCoord, Sensitivity, my_Gradient, localGradient, *Normal, Area = 0.0; - unsigned short iDV_Value = 0, iMarker, nMarker, iDim, nDim, iDV, nDV, nDV_Value; - unsigned long iVertex, nVertex, iPoint; - - int rank = SU2_MPI::GetRank(); - - nMarker = config->GetnMarker_All(); - nDim = geometry->GetnDim(); - nDV = config->GetnDV(); - - VarCoord = nullptr; - - /*--- Discrete adjoint gradient computation ---*/ - - if (rank == MASTER_NODE) - cout << endl << "Evaluate functional gradient using Algorithmic Differentiation (ZONE " << config->GetiZone() << ")." << endl; - - /*--- Start recording of operations ---*/ - - AD::StartRecording(); - - /*--- Register design variables as input and set them to zero - * (since we want to have the derivative at alpha = 0, i.e. for the current design) ---*/ - - for (iDV = 0; iDV < nDV; iDV++){ - - for (iDV_Value = 0; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++){ - - config->SetDV_Value(iDV, iDV_Value, 0.0); - - AD::RegisterInput(config->GetDV_Value(iDV, iDV_Value)); +void CDiscAdjDeformationDriver::SetProjection_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ + + su2double *VarCoord = nullptr, Sensitivity, my_Gradient, localGradient, *Normal, Area = 0.0; + unsigned short iDV_Value = 0, iMarker, nMarker, iDim, nDim, iDV, nDV; + unsigned long iVertex, nVertex, iPoint; + + const int rank = SU2_MPI::GetRank(); + + nMarker = config->GetnMarker_All(); + nDim = geometry->GetnDim(); + nDV = config->GetnDV(); + + /*--- Discrete adjoint gradient computation ---*/ + + if (rank == MASTER_NODE) + cout << endl << "Evaluate functional gradient using Algorithmic Differentiation (ZONE " << config->GetiZone() << ")." << endl; + + /*--- Start recording of operations ---*/ + + AD::StartRecording(); + + /*--- Register design variables as input and set them to zero + * (since we want to have the derivative at alpha = 0, i.e. for the current design) ---*/ + + for (iDV = 0; iDV < nDV; iDV++){ + + for (iDV_Value = 0; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++){ + + config->SetDV_Value(iDV, iDV_Value, 0.0); + + AD::RegisterInput(config->GetDV_Value(iDV, iDV_Value)); + } } - } - - /*--- Call the surface deformation routine ---*/ - - surface_movement->SetSurface_Deformation(geometry, config); - - /*--- Stop the recording --- */ - - AD::StopRecording(); - - /*--- Create a structure to identify points that have been already visited. - * We need that to make sure to set the sensitivity of surface points only once - * (Markers share points, so we would visit them more than once in the loop over the markers below) ---*/ - - bool* visited = new bool[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++){ - visited[iPoint] = false; - } - - /*--- Initialize the derivatives of the output of the surface deformation routine - * with the discrete adjoints from the CFD solution ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_DV(iMarker) == YES) { - nVertex = geometry->nVertex[iMarker]; - for (iVertex = 0; iVertex vertex[iMarker][iVertex]->GetNode(); - if (!visited[iPoint]){ - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - 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++){ - if (config->GetDiscrete_Adjoint()){ - Sensitivity = geometry->GetSensitivity(iPoint, iDim); - } else { - Sensitivity = -Normal[iDim]*geometry->vertex[iMarker][iVertex]->GetAuxVar()/Area; + + /*--- Call the surface deformation routine ---*/ + + surface_movement->SetSurface_Deformation(geometry, config); + + /*--- Stop the recording --- */ + + AD::StopRecording(); + + /*--- Create a structure to identify points that have been already visited. + * We need that to make sure to set the sensitivity of surface points only once + * (Markers share points, so we would visit them more than once in the loop over the markers below) ---*/ + + vector visited(geometry->GetnPoint(), false); + + /*--- Initialize the derivatives of the output of the surface deformation routine + * with the discrete adjoints from the CFD solution ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_DV(iMarker) == YES) { + nVertex = geometry->nVertex[iMarker]; + for (iVertex = 0; iVertex vertex[iMarker][iVertex]->GetNode(); + if (!visited[iPoint]){ + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + 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++){ + if (config->GetDiscrete_Adjoint()){ + Sensitivity = geometry->GetSensitivity(iPoint, iDim); + } else { + Sensitivity = -Normal[iDim]*geometry->vertex[iMarker][iVertex]->GetAuxVar()/Area; + } + SU2_TYPE::SetDerivative(VarCoord[iDim], SU2_TYPE::GetValue(Sensitivity)); + } + visited[iPoint] = true; + } } - SU2_TYPE::SetDerivative(VarCoord[iDim], SU2_TYPE::GetValue(Sensitivity)); - } - visited[iPoint] = true; } - } } - } - - delete [] visited; - - /*--- Compute derivatives and extract gradient ---*/ - - AD::ComputeAdjoint(); - - for (iDV = 0; iDV < nDV; iDV++){ - nDV_Value = config->GetnDV_Value(iDV); - - for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ - DV_Value = config->GetDV_Value(iDV, iDV_Value); - my_Gradient = SU2_TYPE::GetDerivative(DV_Value); - SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - - /*--- Angle of Attack design variable (this is different, - the value comes form the input file) ---*/ - - if ((config->GetDesign_Variable(iDV) == ANGLE_OF_ATTACK) || - (config->GetDesign_Variable(iDV) == FFD_ANGLE_OF_ATTACK)) { - Gradient[iDV][iDV_Value] = config->GetAoA_Sens(); - } - - Gradient[iDV][iDV_Value] += localGradient; + + /*--- Compute derivatives and extract gradient ---*/ + + AD::ComputeAdjoint(); + + for (iDV = 0; iDV < nDV; iDV++){ + + for (iDV_Value = 0; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++) { + + my_Gradient = SU2_TYPE::GetDerivative(config->GetDV_Value(iDV, iDV_Value)); + + SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); + + /*--- Angle of Attack design variable (this is different, + the value comes form the input file) ---*/ + + if ((config->GetDesign_Variable(iDV) == ANGLE_OF_ATTACK) || + (config->GetDesign_Variable(iDV) == FFD_ANGLE_OF_ATTACK)) { + Gradient[iDV][iDV_Value] = config->GetAoA_Sens(); + } + + Gradient[iDV][iDV_Value] += localGradient; + } } - } - - AD::Reset(); - + + AD::Reset(); + } void CDiscAdjDeformationDriver::OutputGradient(su2double** Gradient, CConfig* config, ofstream& Gradient_file){ - - unsigned short nDV, iDV, iDV_Value, nDV_Value; - - int rank = SU2_MPI::GetRank(); - - nDV = config->GetnDV(); - - /*--- Loop through all design variables and their gradients ---*/ - - for (iDV = 0; iDV < nDV; iDV++){ - nDV_Value = config->GetnDV_Value(iDV); - if (rank == MASTER_NODE){ - - /*--- Print the kind of design variable on screen ---*/ - - cout << endl << "Design variable ("; - for (std::map::const_iterator it = Param_Map.begin(); it != Param_Map.end(); ++it ){ - if (it->second == config->GetDesign_Variable(iDV)){ - cout << it->first << ") number "<< iDV << "." << endl; - } - } - - /*--- Print the kind of objective function to screen ---*/ - - for (std::map::const_iterator it = Objective_Map.begin(); it != Objective_Map.end(); ++it ){ - if (it->second == config->GetKind_ObjFunc()){ - cout << it->first << " gradient : "; - if (iDV == 0) Gradient_file << it->first << " gradient " << endl; + + unsigned short nDV, iDV, iDV_Value, nDV_Value; + + int rank = SU2_MPI::GetRank(); + + nDV = config->GetnDV(); + + /*--- Loop through all design variables and their gradients ---*/ + + for (iDV = 0; iDV < nDV; iDV++){ + nDV_Value = config->GetnDV_Value(iDV); + if (rank == MASTER_NODE){ + + /*--- Print the kind of design variable on screen ---*/ + + cout << endl << "Design variable ("; + for (std::map::const_iterator it = Param_Map.begin(); it != Param_Map.end(); ++it ){ + if (it->second == config->GetDesign_Variable(iDV)){ + cout << it->first << ") number "<< iDV << "." << endl; + } + } + + /*--- Print the kind of objective function to screen ---*/ + + for (std::map::const_iterator it = Objective_Map.begin(); it != Objective_Map.end(); ++it ){ + if (it->second == config->GetKind_ObjFunc()){ + cout << it->first << " gradient : "; + if (iDV == 0) Gradient_file << it->first << " gradient " << endl; + } + } + + /*--- Print the gradient to file and screen ---*/ + + for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ + cout << Gradient[iDV][iDV_Value]; + if (iDV_Value != nDV_Value-1 ){ + cout << ", "; + } + Gradient_file << Gradient[iDV][iDV_Value] << endl; + } + cout << endl; + cout <<"-------------------------------------------------------------------------" << endl; } - } - - /*--- Print the gradient to file and screen ---*/ - - for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ - cout << Gradient[iDV][iDV_Value]; - if (iDV_Value != nDV_Value-1 ){ - cout << ", "; - } - Gradient_file << Gradient[iDV][iDV_Value] << endl; - } - cout << endl; - cout <<"-------------------------------------------------------------------------" << endl; } - } } void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone) { - - unsigned short iMarker,iDim, nDim, nMarker, nVar; - unsigned long iVertex, iPoint, nPoint, nVertex; - su2double *Normal, Prod, Sens = 0.0, SensDim, Area; - - unsigned short iZone; - - CSolver *solver = nullptr; - COutput *output = nullptr; - - for (iZone = 0; iZone < val_nZone; iZone++) { - - nPoint = geometry[iZone][INST_0]->GetnPoint(); - nDim = geometry[iZone][INST_0]->GetnDim(); - nMarker = config[iZone]->GetnMarker_All(); - nVar = nDim + 1; - - /*--- We create a baseline solver to easily merge the sensitivity information ---*/ - - vector fieldnames; - fieldnames.push_back("\"Point\""); - fieldnames.push_back("\"x\""); - fieldnames.push_back("\"y\""); - if (nDim == 3) { - fieldnames.push_back("\"z\""); - } - fieldnames.push_back("\"Sensitivity_x\""); - fieldnames.push_back("\"Sensitivity_y\""); - if (nDim == 3) { - fieldnames.push_back("\"Sensitivity_z\""); - } - fieldnames.push_back("\"Surface_Sensitivity\""); - - solver = new CBaselineSolver(geometry[iZone][INST_0], config[iZone], nVar+nDim, fieldnames); - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) { - solver->GetNodes()->SetSolution(iPoint, iDim, geometry[iZone][INST_0]->nodes->GetCoord(iPoint, iDim)); - solver->GetNodes()->SetSolution(iPoint, iDim+nDim, geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim)); - } - } - - /*--- Compute the sensitivity in normal direction ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if(config[iZone]->GetSolid_Wall(iMarker) || (config[iZone]->GetMarker_All_DV(iMarker) == YES )) { - - nVertex = geometry[iZone][INST_0]->GetnVertex(iMarker); - - for (iVertex = 0; iVertex < nVertex; iVertex++) { - iPoint = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNormal(); - Prod = 0.0; - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - - /*--- Retrieve the gradient calculated with discrete adjoint method ---*/ - - SensDim = geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim); - - /*--- Calculate scalar product for DiscAdjDeformation onto the normal vector ---*/ - - Prod += Normal[iDim]*SensDim; - - Area += Normal[iDim]*Normal[iDim]; - } - - Area = sqrt(Area); - - /*--- DiscAdjDeformation of the gradient onto the normal vector of the surface ---*/ - - Sens = Prod/Area; - - solver->GetNodes()->SetSolution(iPoint, 2*nDim, Sens); - + + unsigned short iMarker,iDim, nDim, nMarker, nVar; + unsigned long iVertex, iPoint, nPoint, nVertex; + su2double *Normal, Prod, Sens = 0.0, SensDim, Area; + + unsigned short iZone; + + CSolver *solver = nullptr; + COutput *output = nullptr; + + for (iZone = 0; iZone < val_nZone; iZone++) { + + nPoint = geometry[iZone][INST_0]->GetnPoint(); + nDim = geometry[iZone][INST_0]->GetnDim(); + nMarker = config[iZone]->GetnMarker_All(); + nVar = nDim + 1; + + /*--- We create a baseline solver to easily merge the sensitivity information ---*/ + + vector fieldnames; + fieldnames.push_back("\"Point\""); + fieldnames.push_back("\"x\""); + fieldnames.push_back("\"y\""); + if (nDim == 3) { + fieldnames.push_back("\"z\""); } - } - } - - output = new CBaselineOutput(config[iZone], nDim, solver); - output->PreprocessVolumeOutput(config[iZone]); - output->PreprocessHistoryOutput(config[iZone], false); - - /*--- Load the data --- */ - - output->Load_Data(geometry[iZone][INST_0], config[iZone], &solver); - - /*--- Set the surface filename ---*/ - - output->SetSurface_Filename(config[iZone]->GetSurfSens_FileName()); - - /*--- Set the volume filename ---*/ - - output->SetVolume_Filename(config[iZone]->GetVolSens_FileName()); - - /*--- Write to file ---*/ + fieldnames.push_back("\"Sensitivity_x\""); + fieldnames.push_back("\"Sensitivity_y\""); + if (nDim == 3) { + fieldnames.push_back("\"Sensitivity_z\""); + } + fieldnames.push_back("\"Surface_Sensitivity\""); + + solver = new CBaselineSolver(geometry[iZone][INST_0], config[iZone], nVar+nDim, fieldnames); + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) { + solver->GetNodes()->SetSolution(iPoint, iDim, geometry[iZone][INST_0]->nodes->GetCoord(iPoint, iDim)); + solver->GetNodes()->SetSolution(iPoint, iDim+nDim, geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim)); + } + } + + /*--- Compute the sensitivity in normal direction ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if(config[iZone]->GetSolid_Wall(iMarker) || (config[iZone]->GetMarker_All_DV(iMarker) == YES )) { + + nVertex = geometry[iZone][INST_0]->GetnVertex(iMarker); + + for (iVertex = 0; iVertex < nVertex; iVertex++) { + iPoint = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNormal(); + Prod = 0.0; + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + + /*--- Retrieve the gradient calculated with discrete adjoint method ---*/ + + SensDim = geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim); + + /*--- Calculate scalar product for projection onto the normal vector ---*/ + + Prod += Normal[iDim]*SensDim; + + Area += Normal[iDim]*Normal[iDim]; + } + + Area = sqrt(Area); + + /*--- Projection of the gradient onto the normal vector of the surface ---*/ + + Sens = Prod/Area; + + solver->GetNodes()->SetSolution(iPoint, 2*nDim, Sens); + + } + } + } + + output = new CBaselineOutput(config[iZone], nDim, solver); + output->PreprocessVolumeOutput(config[iZone]); + output->PreprocessHistoryOutput(config[iZone], false); + + /*--- Load the data --- */ + + output->Load_Data(geometry[iZone][INST_0], config[iZone], &solver); + + /*--- Set the surface filename ---*/ + + output->SetSurface_Filename(config[iZone]->GetSurfSens_FileName()); + + /*--- Set the volume filename ---*/ + + output->SetVolume_Filename(config[iZone]->GetVolSens_FileName()); + + /*--- Write to file ---*/ + + for (unsigned short iFile = 0; iFile < config[iZone]->GetnVolumeOutputFiles(); iFile++){ + auto FileFormat = config[iZone]->GetVolumeOutputFiles(); + if (FileFormat[iFile] != OUTPUT_TYPE::RESTART_ASCII && + FileFormat[iFile] != OUTPUT_TYPE::RESTART_BINARY && + FileFormat[iFile] != OUTPUT_TYPE::CSV) + output->WriteToFile(config[iZone], geometry[iZone][INST_0], FileFormat[iFile]); + } + + /*--- Free memory ---*/ + + delete output; + delete solver; + + } + +} - for (unsigned short iFile = 0; iFile < config[iZone]->GetnVolumeOutputFiles(); iFile++){ - auto FileFormat = config[iZone]->GetVolumeOutputFiles(); - if (FileFormat[iFile] != OUTPUT_TYPE::RESTART_ASCII && - FileFormat[iFile] != OUTPUT_TYPE::RESTART_BINARY && - FileFormat[iFile] != OUTPUT_TYPE::CSV) - output->WriteToFile(config[iZone], geometry[iZone][INST_0], FileFormat[iFile]); +void CDiscAdjDeformationDriver::DerivativeTreatment_MeshSensitivity(CGeometry *geometry, CConfig *config, CVolumetricMovement *grid_movement) { + + int rank = SU2_MPI::GetRank(); + + /*--- Warning if choosen smoothing mode is unsupported. + * This is the default option if the user has not specified a mode in the config file. ---*/ + if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::NONE) { + SU2_MPI::Error("Unsupported operation modus for the Sobolev Smoothing Solver.", CURRENT_FUNCTION); + } + + /*-- Construct the smoothing solver and numerics ---*/ + std::unique_ptr solver(new CGradientSmoothingSolver(geometry, config)); + unsigned dim = (config->GetSmoothOnSurface() ? geometry->GetnDim() - 1 : geometry->GetnDim()); + std::unique_ptr numerics(new CGradSmoothing(dim, config)); + + if (rank == MASTER_NODE) cout << "Sobolev Smoothing of derivatives is active." << endl; + + /*--- Apply the smoothing procedure on the mesh level. ---*/ + if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::MESH_LEVEL) { + if (rank == MASTER_NODE) cout << " working on mesh level" << endl; + + /*--- Work with the surface derivatives. ---*/ + if (config->GetSmoothOnSurface()) { + + /*--- Project to surface and then smooth on surface. ---*/ + grid_movement->SetVolume_Deformation(geometry, config, false, true); + + /*--- Get the sensitivities from the geometry class to work with. ---*/ + solver->ReadSensFromGeometry(geometry); + + /*--- Perform the smoothing procedure on all boundaries marked as DV marker. ---*/ + solver->ApplyGradientSmoothingSurface(geometry, numerics.get(), config); + + /*--- After appling the solver write the results back ---*/ + solver->WriteSensToGeometry(geometry); + + /*--- Work with the volume derivatives. ---*/ + } else { + + /*--- Get the sensitivities from the geometry class to work with. ---*/ + solver->ReadSensFromGeometry(geometry); + + solver->ApplyGradientSmoothingVolume(geometry, numerics.get(), config); + + /*--- After appling the solver write the results back ---*/ + solver->WriteSensToGeometry(geometry); + + /*--- Projection is applied after smoothing. ---*/ + grid_movement->SetVolume_Deformation(geometry, config, false, true); + } + } + +} - /*--- Free memory ---*/ - - delete output; - delete solver; - - } - +void CDiscAdjDeformationDriver::DerivativeTreatment_Gradient(CGeometry *geometry, CConfig *config, CVolumetricMovement* grid_movement, CSurfaceMovement *surface_movement, su2double** Gradient) { + + int rank = SU2_MPI::GetRank(); + + /*--- Error if choosen smoothing mode is unsupported. + * This is the default option if the user has not specified a mode in the config file. ---*/ + if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::NONE) { + SU2_MPI::Error("Unsupported operation modus for the Sobolev Smoothing Solver.", CURRENT_FUNCTION); + } + + /*-- Construct the smoothing solver and numerics ---*/ + std::unique_ptr solver(new CGradientSmoothingSolver(geometry, config)); + unsigned dim = (config->GetSmoothOnSurface() ? geometry->GetnDim() - 1 : geometry->GetnDim()); + std::unique_ptr numerics(new CGradSmoothing(dim, config)); + + if (rank == MASTER_NODE) cout << "Sobolev Smoothing of derivatives is active." << endl; + + /*--- Get the sensitivities from the geometry class to work with. ---*/ + solver->ReadSensFromGeometry(geometry); + + /*--- Apply the smoothing procedure on the DV level. ---*/ + if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::PARAM_LEVEL_COMPLETE) { + solver->ApplyGradientSmoothingDV(geometry, numerics.get(), surface_movement, grid_movement, config, Gradient); + + /*--- If smoothing already took place on the mesh level, or none is requested, just do standard projection. ---*/ + } else if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::ONLY_GRAD || + config->GetSobMode() == ENUM_SOBOLEV_MODUS::MESH_LEVEL) { + solver->RecordTapeAndCalculateOriginalGradient(geometry, surface_movement, grid_movement, config, Gradient); + } + } diff --git a/SU2_DOT/include/SU2_DOT.hpp b/SU2_DOT/include/SU2_DOT.hpp index 857b1e18376..5fa74b3a533 100644 --- a/SU2_DOT/include/SU2_DOT.hpp +++ b/SU2_DOT/include/SU2_DOT.hpp @@ -26,7 +26,6 @@ * License along with SU2. If not, see . */ - #pragma once #define ENABLE_MAPS @@ -41,72 +40,6 @@ #include #include -#include "../../Common/include/geometry/CPhysicalGeometry.hpp" -#include "../../Common/include/fem/fem_geometry_structure.hpp" -#include "../../SU2_CFD/include/output/CBaselineOutput.hpp" -#include "../../SU2_CFD/include/solvers/CBaselineSolver.hpp" - -#include "../../SU2_CFD/include/solvers/CGradientSmoothingSolver.hpp" -#include "../../SU2_CFD/include/numerics/CGradSmoothing.hpp" +#include "../../SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp" using namespace std; - - -/*! - * \brief Projection of the surface sensitivity using finite differences (FD). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] surface_movement - Surface movement class of the problem. - * \param[in] Gradient_file - Output file to store the gradient data. - */ - -void SetProjection_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double **Gradient); - -/*! - * \brief Projection of the surface sensitivity using algorithmic differentiation (AD). - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] surface_movement - Surface movement class of the problem. - * \param[in] Gradient_file - Output file to store the gradient data. - */ - -void SetProjection_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double **Gradient); - -/*! - * \brief Prints the gradient information to a file. - * \param[in] Gradient - The gradient data. - * \param[in] config - Definition of the particular problem. - * \param[in] Gradient_file - Output file to store the gradient data. - */ - -void OutputGradient(su2double** Gradient, CConfig* config, ofstream& Gradient_file); - -/*! - * \brief Write the sensitivity (including mesh sensitivity) computed with the discrete adjoint method - * on the surface and in the volume to a file. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] val_nZone - Number of Zones. - */ - -void SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone); - -/*! - * \brief Treatment of derivatives with the Sobolev smoothing solver. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] grid_movement - Volumetric movement class of the problem. - */ - -void DerivativeTreatment_MeshSensitivity(CGeometry *geometry, CConfig *config, CVolumetricMovement *grid_movement); - -/*! - * \brief Treatment of derivatives with the Sobolev smoothing solver. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] grid_movement - Volumetric movement class of the problem. - * \param[in] surface_movement - Surface movement class of the problem. - * \param[in] Gradient - Output array to store the gradient data. - */ - -void DerivativeTreatment_Gradient(CGeometry *geometry, CConfig *config, CVolumetricMovement *grid_movement, CSurfaceMovement *surface_movement, su2double **Gradient); diff --git a/SU2_DOT/src/SU2_DOT.cpp b/SU2_DOT/src/SU2_DOT.cpp index 077923ea359..c4632a3eac1 100644 --- a/SU2_DOT/src/SU2_DOT.cpp +++ b/SU2_DOT/src/SU2_DOT.cpp @@ -27,1030 +27,50 @@ #include "../include/SU2_DOT.hpp" + using namespace std; int main(int argc, char *argv[]) { - - unsigned short iZone, iInst; - su2double StartTime = 0.0, StopTime = 0.0, UsedTime = 0.0; - - char config_file_name[MAX_STRING_SIZE]; - - /*--- OpenMP initialization ---*/ - - omp_initialize(); - - /*--- MPI initialization, and buffer setting ---*/ - + + char config_file_name[MAX_STRING_SIZE]; + + /*--- Create a pointer to the main SU2_DEF Driver ---*/ + + CDiscAdjDeformationDriver* driver = nullptr; + + /*--- MPI initialization ---*/ + #if defined(HAVE_OMP) && defined(HAVE_MPI) - int provided; - SU2_MPI::Init_thread(&argc, &argv, MPI_THREAD_FUNNELED, &provided); + int provided; + SU2_MPI::Init_thread(&argc, &argv, MPI_THREAD_FUNNELED, &provided); #else - SU2_MPI::Init(&argc, &argv); -#endif - SU2_MPI::Comm MPICommunicator = SU2_MPI::GetComm(); - - const int rank = SU2_MPI::GetRank(); - const int size = SU2_MPI::GetSize(); - - /*--- AD initialization ---*/ -#ifdef HAVE_OPDI - AD::getGlobalTape().initialize(); -#endif - - /*--- Pointer to different structures that will be used throughout the entire code ---*/ - - CConfig **config_container = nullptr; - CConfig *driver_config = nullptr; - CGeometry ***geometry_container = nullptr; - CSurfaceMovement **surface_movement = nullptr; - CVolumetricMovement **grid_movement = nullptr; - unsigned short *nInst = nullptr; - - /*--- Load in the number of zones and spatial dimensions in the mesh file (if no config - file is specified, default.cfg is used) ---*/ - - if (argc == 2) { strcpy(config_file_name,argv[1]); } - else { strcpy(config_file_name, "default.cfg"); } - - /*--- Read the name and format of the input mesh file to get from the mesh - file the number of zones and dimensions from the numerical grid (required - for variables allocation) ---*/ - - CConfig *config = nullptr; - config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DOT); - - const auto nZone = config->GetnZone(); - - /*--- Definition of the containers per zones ---*/ - - config_container = new CConfig*[nZone] (); - geometry_container = new CGeometry**[nZone] (); - surface_movement = new CSurfaceMovement*[nZone] (); - grid_movement = new CVolumetricMovement*[nZone] (); - - nInst = new unsigned short[nZone]; - driver_config = nullptr; - - for (iZone = 0; iZone < nZone; iZone++) { - nInst[iZone] = 1; - } - - /*--- Initialize the configuration of the driver ---*/ - driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DOT, false); - - /*--- Initialize a char to store the zone filename ---*/ - char zone_file_name[MAX_STRING_SIZE]; - - /*--- Loop over all zones to initialize the various classes. In most - cases, nZone is equal to one. This represents the solution of a partial - differential equation on a single block, unstructured mesh. ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Definition of the configuration option class for all zones. In this - constructor, the input configuration file is parsed and all options are - read and stored. ---*/ - - if (driver_config->GetnConfigFiles() > 0){ - strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); - config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DOT, iZone, nZone, true); - } - else{ - config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DOT, iZone, nZone, true); - } - config_container[iZone]->SetMPICommunicator(MPICommunicator); - - } - - /*--- Set the multizone part of the problem. ---*/ - if (driver_config->GetMultizone_Problem()){ - for (iZone = 0; iZone < nZone; iZone++) { - /*--- Set the interface markers for multizone ---*/ - config_container[iZone]->SetMultizone(driver_config, config_container); - } - } - - /*--- Loop over all zones to initialize the various classes. In most - cases, nZone is equal to one. This represents the solution of a partial - differential equation on a single block, unstructured mesh. ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Determine whether or not the FEM solver is used, which decides the - type of geometry classes that are instantiated. ---*/ - const bool fem_solver = config_container[iZone]->GetFEMSolver(); - - /*--- Read the number of instances for each zone ---*/ - - nInst[iZone] = config_container[iZone]->GetnTimeInstances(); - - geometry_container[iZone] = new CGeometry*[nInst[iZone]]; - - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - - /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ - - CGeometry *geometry_aux = nullptr; - - /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ - - geometry_aux = new CPhysicalGeometry(config_container[iZone], iZone, nZone); - - /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - - if ( fem_solver ) geometry_aux->SetColorFEMGrid_Parallel(config_container[iZone]); - else geometry_aux->SetColorGrid_Parallel(config_container[iZone]); - - /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - - if( fem_solver ) { - switch( config_container[iZone]->GetKind_FEM_Flow() ) { - case DG: { - geometry_container[iZone][iInst] = new CMeshFEM_DG(geometry_aux, config_container[iZone]); - break; - } - } - } - else { - geometry_container[iZone][iInst] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); - } - - /*--- Deallocate the memory of geometry_aux ---*/ - - delete geometry_aux; - - /*--- Add the Send/Receive boundaries ---*/ - - geometry_container[iZone][iInst]->SetSendReceive(config_container[iZone]); - - /*--- Add the Send/Receive boundaries ---*/ - - geometry_container[iZone][iInst]->SetBoundaries(config_container[iZone]); - - /*--- Create the vertex structure (required for MPI) ---*/ - - if (rank == MASTER_NODE) cout << "Identify vertices." << endl; - geometry_container[iZone][iInst]->SetVertex(config_container[iZone]); - - /*--- Store the global to local mapping after preprocessing. ---*/ - - if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; - geometry_container[iZone][iInst]->SetGlobal_to_Local_Point(); - - /* Test for a fem solver, because some more work must be done. */ - - if (fem_solver) { - - /*--- Carry out a dynamic cast to CMeshFEM_DG, such that it is not needed to - define all virtual functions in the base class CGeometry. ---*/ - CMeshFEM_DG *DGMesh = dynamic_cast(geometry_container[iZone][iInst]); - - /*--- Determine the standard elements for the volume elements. ---*/ - if (rank == MASTER_NODE) cout << "Creating standard volume elements." << endl; - DGMesh->CreateStandardVolumeElements(config_container[iZone]); - - /*--- Create the face information needed to compute the contour integral - for the elements in the Discontinuous Galerkin formulation. ---*/ - if (rank == MASTER_NODE) cout << "Creating face information." << endl; - DGMesh->CreateFaces(config_container[iZone]); - } - } - } - - /*--- Set up a timer for performance benchmarking (preprocessing time is included) ---*/ - - StartTime = SU2_MPI::Wtime(); - - for (iZone = 0; iZone < nZone; iZone++) { - - if (rank == MASTER_NODE) - cout << "\n----------------------- Preprocessing computations ----------------------" << endl; - - /*--- Compute elements surrounding points, points surrounding points ---*/ - - if (rank == MASTER_NODE) cout << "Setting local point connectivity." << endl; - geometry_container[iZone][INST_0]->SetPoint_Connectivity(); - - /*--- Check the orientation before computing geometrical quantities ---*/ - - geometry_container[iZone][INST_0]->SetBoundVolume(); - if (config_container[iZone]->GetReorientElements()) { - if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the elements." << endl; - geometry_container[iZone][INST_0]->Check_IntElem_Orientation(config_container[iZone]); - geometry_container[iZone][INST_0]->Check_BoundElem_Orientation(config_container[iZone]); - } - - /*--- Create the edge structure ---*/ - - if (rank == MASTER_NODE) cout << "Identify edges and vertices." << endl; - geometry_container[iZone][INST_0]->SetEdges(); geometry_container[iZone][INST_0]->SetVertex(config_container[iZone]); - - /*--- Create the dual control volume structures ---*/ - - if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; - geometry_container[iZone][INST_0]->SetBoundControlVolume(config_container[ZONE_0], ALLOCATE); - - /*--- Store the global to local mapping after preprocessing. ---*/ - - if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; - geometry_container[iZone][INST_0]->SetGlobal_to_Local_Point(); - - /*--- Create the point-to-point MPI communication structures. ---*/ - - geometry_container[iZone][INST_0]->PreprocessP2PComms(geometry_container[iZone][INST_0], config_container[iZone]); - - /*--- Load the surface sensitivities from file. This is done only - once: if this is an unsteady problem, a time-average of the surface - sensitivities at each node is taken within this routine. ---*/ - - if (!config_container[iZone]->GetDiscrete_Adjoint()) { - if (rank == MASTER_NODE) cout << "Reading surface sensitivities at each node from file." << endl; - geometry_container[iZone][INST_0]->SetBoundSensitivity(config_container[iZone]); - } - else { - if (rank == MASTER_NODE) cout << "Reading volume sensitivities at each node from file." << endl; - grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone][INST_0], config_container[iZone]); - - /*--- Read in sensitivities from file. ---*/ - if (config_container[ZONE_0]->GetSensitivity_Format() == UNORDERED_ASCII) - geometry_container[iZone][INST_0]->ReadUnorderedSensitivity(config_container[iZone]); - else - geometry_container[iZone][INST_0]->SetSensitivity(config_container[iZone]); - - if (rank == MASTER_NODE) - cout << "\n---------------------- Mesh sensitivity computation ---------------------" << endl; - - if(config_container[iZone]->GetDiscrete_Adjoint() && config_container[iZone]->GetSmoothGradient() && - config_container[iZone]->GetSobMode() == ENUM_SOBOLEV_MODUS::MESH_LEVEL) { - DerivativeTreatment_MeshSensitivity(geometry_container[iZone][INST_0], config_container[iZone], grid_movement[iZone]); - } else { - grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone][INST_0], config_container[iZone], false, true); - } - - } - } - - - if (config_container[ZONE_0]->GetDiscrete_Adjoint()) { - if (rank == MASTER_NODE) - cout << "\n------------------------ Mesh sensitivity Output ------------------------" << endl; - SetSensitivity_Files(geometry_container, config_container, nZone); - } - - /*--- Initialize structure to store the gradient ---*/ - su2double** Gradient = new su2double*[config_container[ZONE_0]->GetnDV()]; - - for (auto iDV = 0u; iDV < config_container[ZONE_0]->GetnDV(); iDV++) { - /*--- Initialize to zero ---*/ - Gradient[iDV] = new su2double[config_container[ZONE_0]->GetnDV_Value(iDV)](); - } - - ofstream Gradient_file; - Gradient_file.precision(config->OptionIsSet("OUTPUT_PRECISION") ? config->GetOutput_Precision() : 6); - - /*--- For multizone computations the gradient contributions are summed up and written into one file. ---*/ - for (iZone = 0; iZone < nZone; iZone++){ - if ((config_container[iZone]->GetDesign_Variable(0) != NONE) && - (config_container[iZone]->GetDesign_Variable(0) != SURFACE_FILE)) { - - if (rank == MASTER_NODE) - cout << "\n---------- Start gradient evaluation using sensitivity information ----------" << endl; - - /*--- Definition of the Class for surface deformation ---*/ - - surface_movement[iZone] = new CSurfaceMovement(); - - /*--- Copy coordinates to the surface structure ---*/ - - surface_movement[iZone]->CopyBoundary(geometry_container[iZone][INST_0], config_container[iZone]); - - /*--- If AD mode is enabled we can use it to compute the projection, - * otherwise we use finite differences. ---*/ - - if (config_container[iZone]->GetAD_Mode()) { - if (config_container[iZone]->GetSmoothGradient()) { - DerivativeTreatment_Gradient(geometry_container[iZone][INST_0], config_container[iZone], grid_movement[iZone], surface_movement[iZone] , Gradient); - } else { - SetProjection_AD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); - } - } else { - SetProjection_FD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); - } - } - } // for iZone - - /*--- Write the gradient to a file ---*/ - - if (rank == MASTER_NODE) - Gradient_file.open(config_container[ZONE_0]->GetObjFunc_Grad_FileName().c_str(), ios::out); - - /*--- Print gradients to screen and writes to file ---*/ - - OutputGradient(Gradient, config_container[ZONE_0], Gradient_file); - - for (auto iDV = 0u; iDV < config_container[ZONE_0]->GetnDV(); iDV++){ - delete [] Gradient[iDV]; - } - delete [] Gradient; - - delete config; - config = nullptr; - - if (rank == MASTER_NODE) - cout << "\n------------------------- Solver Postprocessing -------------------------" << endl; - - if (geometry_container != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (geometry_container[iZone] != nullptr) { - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - if (geometry_container[iZone][iInst] != nullptr) { - delete geometry_container[iZone][iInst]; - } - } - delete geometry_container[iZone]; - } - } - delete [] geometry_container; - } - if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; - - if (surface_movement != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (surface_movement[iZone] != nullptr) { - delete surface_movement[iZone]; - } - } - delete [] surface_movement; - } - if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; - - if (grid_movement != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (grid_movement[iZone] != nullptr) { - delete grid_movement[iZone]; - } - } - delete [] grid_movement; - } - if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; - - delete config; - config = nullptr; - if (config_container != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (config_container[iZone] != nullptr) { - delete config_container[iZone]; - } - } - delete [] config_container; - } - if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; - - /*--- Synchronization point after a single solver iteration. Compute the - wall clock time required. ---*/ - - StopTime = SU2_MPI::Wtime(); - - /*--- Compute/print the total time for performance benchmarking. ---*/ - - UsedTime = StopTime-StartTime; - if (rank == MASTER_NODE) { - cout << "\nCompleted in " << fixed << UsedTime << " seconds on "<< size; - if (size == 1) cout << " core." << endl; else cout << " cores." << endl; - } - - /*--- Exit the solver cleanly ---*/ - - if (rank == MASTER_NODE) - cout << "\n------------------------- Exit Success (SU2_DOT) ------------------------\n" << endl; - - /*--- Finalize AD, if necessary. ---*/ -#ifdef HAVE_OPDI - AD::getGlobalTape().finalize(); + SU2_MPI::Init(&argc, &argv); #endif - - /*--- Finalize MPI parallelization. ---*/ - SU2_MPI::Finalize(); - - /*--- Finalize OpenMP. ---*/ - omp_finalize(); - - return EXIT_SUCCESS; - -} - -void SetProjection_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ - - unsigned short iDV, nDV, iFFDBox, nDV_Value, iMarker, iDim; - unsigned long iVertex, iPoint; - su2double delta_eps, my_Gradient, localGradient, *Normal, dS, *VarCoord, Sensitivity, - dalpha[3], deps[3], dalpha_deps; - bool *UpdatePoint, MoveSurface, Local_MoveSurface; - CFreeFormDefBox **FFDBox; - - int rank = SU2_MPI::GetRank(); - - nDV = config->GetnDV(); - - /*--- Boolean controlling points to be updated ---*/ - - UpdatePoint = new bool[geometry->GetnPoint()]; - - /*--- Definition of the FFD deformation class ---*/ - - unsigned short nFFDBox = MAX_NUMBER_FFD; - FFDBox = new CFreeFormDefBox*[nFFDBox]; - for (iFFDBox = 0; iFFDBox < MAX_NUMBER_FFD; iFFDBox++) FFDBox[iFFDBox] = nullptr; - - for (iDV = 0; iDV < nDV; iDV++){ - nDV_Value = config->GetnDV_Value(iDV); - if (nDV_Value != 1){ - SU2_MPI::Error("The projection using finite differences currently only supports a fixed direction of movement for FFD points.", CURRENT_FUNCTION); - } - } - - /*--- Continuous adjoint gradient computation ---*/ - - if (rank == MASTER_NODE) - cout << "Evaluate functional gradient using Finite Differences." << endl; - - for (iDV = 0; iDV < nDV; iDV++) { - - MoveSurface = true; - Local_MoveSurface = true; - - /*--- Free Form deformation based ---*/ - - if ((config->GetDesign_Variable(iDV) == FFD_CONTROL_POINT_2D) || - (config->GetDesign_Variable(iDV) == FFD_CAMBER_2D) || - (config->GetDesign_Variable(iDV) == FFD_THICKNESS_2D) || - (config->GetDesign_Variable(iDV) == FFD_TWIST_2D) || - (config->GetDesign_Variable(iDV) == FFD_CONTROL_POINT) || - (config->GetDesign_Variable(iDV) == FFD_NACELLE) || - (config->GetDesign_Variable(iDV) == FFD_GULL) || - (config->GetDesign_Variable(iDV) == FFD_TWIST) || - (config->GetDesign_Variable(iDV) == FFD_ROTATION) || - (config->GetDesign_Variable(iDV) == FFD_CAMBER) || - (config->GetDesign_Variable(iDV) == FFD_THICKNESS) || - (config->GetDesign_Variable(iDV) == FFD_ANGLE_OF_ATTACK)) { - - /*--- Read the FFD information in the first iteration ---*/ - - if (iDV == 0) { - - if (rank == MASTER_NODE) - cout << "Read the FFD information from mesh file." << endl; - - /*--- Read the FFD information from the grid file ---*/ - - surface_movement->ReadFFDInfo(geometry, config, FFDBox, config->GetMesh_FileName()); - - /*--- If the FFDBox was not defined in the input file ---*/ - if (!surface_movement->GetFFDBoxDefinition()) { - SU2_MPI::Error("The input grid doesn't have the entire FFD information!", CURRENT_FUNCTION); - } - - for (iFFDBox = 0; iFFDBox < surface_movement->GetnFFDBox(); iFFDBox++) { - - if (rank == MASTER_NODE) cout << "Checking FFD box dimension." << endl; - surface_movement->CheckFFDDimension(geometry, config, FFDBox[iFFDBox], iFFDBox); - - if (rank == MASTER_NODE) cout << "Check the FFD box intersections with the solid surfaces." << endl; - surface_movement->CheckFFDIntersections(geometry, config, FFDBox[iFFDBox], iFFDBox); - - } - - if (rank == MASTER_NODE) - cout <<"-------------------------------------------------------------------------" << endl; - - } - - if (rank == MASTER_NODE) { - cout << endl << "Design variable number "<< iDV <<"." << endl; - cout << "Performing 3D deformation of the surface." << endl; - } - - /*--- Apply the control point change ---*/ - - MoveSurface = false; - - for (iFFDBox = 0; iFFDBox < surface_movement->GetnFFDBox(); iFFDBox++) { - - /*--- Reset FFD box ---*/ - - switch (config->GetDesign_Variable(iDV) ) { - case FFD_CONTROL_POINT_2D : Local_MoveSurface = surface_movement->SetFFDCPChange_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_CAMBER_2D : Local_MoveSurface = surface_movement->SetFFDCamber_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_THICKNESS_2D : Local_MoveSurface = surface_movement->SetFFDThickness_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_TWIST_2D : Local_MoveSurface = surface_movement->SetFFDTwist_2D(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_CONTROL_POINT : Local_MoveSurface = surface_movement->SetFFDCPChange(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_NACELLE : Local_MoveSurface = surface_movement->SetFFDNacelle(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_GULL : Local_MoveSurface = surface_movement->SetFFDGull(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_TWIST : Local_MoveSurface = surface_movement->SetFFDTwist(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_ROTATION : Local_MoveSurface = surface_movement->SetFFDRotation(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_CAMBER : Local_MoveSurface = surface_movement->SetFFDCamber(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_THICKNESS : Local_MoveSurface = surface_movement->SetFFDThickness(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_CONTROL_SURFACE : Local_MoveSurface = surface_movement->SetFFDControl_Surface(geometry, config, FFDBox[iFFDBox], FFDBox, iDV, true); break; - case FFD_ANGLE_OF_ATTACK : Gradient[iDV][0] = config->GetAoA_Sens(); break; - } - - /*--- Recompute cartesian coordinates using the new control points position ---*/ - - if (Local_MoveSurface) { - MoveSurface = true; - surface_movement->SetCartesianCoord(geometry, config, FFDBox[iFFDBox], iFFDBox, true); - } - - } - - } - - /*--- Hicks Henne design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == HICKS_HENNE) { - surface_movement->SetHicksHenne(geometry, config, iDV, true); - } - - /*--- Surface bump design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == SURFACE_BUMP) { - surface_movement->SetSurface_Bump(geometry, config, iDV, true); - } - - /*--- Kulfan (CST) design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == CST) { - surface_movement->SetCST(geometry, config, iDV, true); - } - - /*--- Displacement design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == TRANSLATION) { - surface_movement->SetTranslation(geometry, config, iDV, true); - } - - /*--- Angle of Attack design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == ANGLE_OF_ATTACK) { - Gradient[iDV][0] = config->GetAoA_Sens(); - } - - /*--- Scale design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == SCALE) { - surface_movement->SetScale(geometry, config, iDV, true); - } - - /*--- Rotation design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == ROTATION) { - surface_movement->SetRotation(geometry, config, iDV, true); - } - - /*--- NACA_4Digits design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == NACA_4DIGITS) { - surface_movement->SetNACA_4Digits(geometry, config); - } - - /*--- Parabolic design variable ---*/ - - else if (config->GetDesign_Variable(iDV) == PARABOLIC) { - surface_movement->SetParabolic(geometry, config); - } - - /*--- Design variable not implemented ---*/ - - else { - if (rank == MASTER_NODE) - cout << "Design Variable not implemented yet" << endl; - } - - /*--- Load the delta change in the design variable (finite difference step). ---*/ - - if ((config->GetDesign_Variable(iDV) != ANGLE_OF_ATTACK) && - (config->GetDesign_Variable(iDV) != FFD_ANGLE_OF_ATTACK)) { - - /*--- If the Angle of attack is not involved, reset the value of the gradient ---*/ - - my_Gradient = 0.0; Gradient[iDV][0] = 0.0; - - if (MoveSurface) { - - delta_eps = config->GetDV_Value(iDV); - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) - UpdatePoint[iPoint] = true; - - 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 ((iPoint < geometry->GetnPointDomain()) && UpdatePoint[iPoint]) { - - Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - Sensitivity = geometry->vertex[iMarker][iVertex]->GetAuxVar(); - - dS = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { - dS += Normal[iDim]*Normal[iDim]; - deps[iDim] = VarCoord[iDim] / delta_eps; - } - dS = sqrt(dS); - - dalpha_deps = 0.0; - for (iDim = 0; iDim < geometry->GetnDim(); iDim++) { - dalpha[iDim] = Normal[iDim] / dS; - dalpha_deps -= dalpha[iDim]*deps[iDim]; - } - - my_Gradient += Sensitivity*dalpha_deps; - UpdatePoint[iPoint] = false; - } - } - } - } - } - - SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - Gradient[iDV][0] += localGradient; - } - } - - /*--- Delete memory for parameterization. ---*/ - - if (FFDBox != nullptr) { - for (iFFDBox = 0; iFFDBox < MAX_NUMBER_FFD; iFFDBox++) { - if (FFDBox[iFFDBox] != nullptr) { - delete FFDBox[iFFDBox]; - } - } - delete [] FFDBox; - } - - delete [] UpdatePoint; - -} - - -void SetProjection_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ - - su2double *VarCoord = nullptr, Sensitivity, my_Gradient, localGradient, *Normal, Area = 0.0; - unsigned short iDV_Value = 0, iMarker, nMarker, iDim, nDim, iDV, nDV; - unsigned long iVertex, nVertex, iPoint; - - const int rank = SU2_MPI::GetRank(); - - nMarker = config->GetnMarker_All(); - nDim = geometry->GetnDim(); - nDV = config->GetnDV(); - - /*--- Discrete adjoint gradient computation ---*/ - - if (rank == MASTER_NODE) - cout << endl << "Evaluate functional gradient using Algorithmic Differentiation (ZONE " << config->GetiZone() << ")." << endl; - - /*--- Start recording of operations ---*/ - - AD::StartRecording(); - - /*--- Register design variables as input and set them to zero - * (since we want to have the derivative at alpha = 0, i.e. for the current design) ---*/ - - for (iDV = 0; iDV < nDV; iDV++){ - - for (iDV_Value = 0; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++){ - - config->SetDV_Value(iDV, iDV_Value, 0.0); - - AD::RegisterInput(config->GetDV_Value(iDV, iDV_Value)); - } - } - - /*--- Call the surface deformation routine ---*/ - - surface_movement->SetSurface_Deformation(geometry, config); - - /*--- Stop the recording --- */ - - AD::StopRecording(); - - /*--- Create a structure to identify points that have been already visited. - * We need that to make sure to set the sensitivity of surface points only once - * (Markers share points, so we would visit them more than once in the loop over the markers below) ---*/ - - vector visited(geometry->GetnPoint(), false); - - /*--- Initialize the derivatives of the output of the surface deformation routine - * with the discrete adjoints from the CFD solution ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_DV(iMarker) == YES) { - nVertex = geometry->nVertex[iMarker]; - for (iVertex = 0; iVertex vertex[iMarker][iVertex]->GetNode(); - if (!visited[iPoint]){ - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - 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++){ - if (config->GetDiscrete_Adjoint()){ - Sensitivity = geometry->GetSensitivity(iPoint, iDim); - } else { - Sensitivity = -Normal[iDim]*geometry->vertex[iMarker][iVertex]->GetAuxVar()/Area; - } - SU2_TYPE::SetDerivative(VarCoord[iDim], SU2_TYPE::GetValue(Sensitivity)); - } - visited[iPoint] = true; - } - } - } - } - - /*--- Compute derivatives and extract gradient ---*/ - - AD::ComputeAdjoint(); - - for (iDV = 0; iDV < nDV; iDV++){ - - for (iDV_Value = 0; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++){ - - my_Gradient = SU2_TYPE::GetDerivative(config->GetDV_Value(iDV, iDV_Value)); - - SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); - - /*--- Angle of Attack design variable (this is different, - the value comes form the input file) ---*/ - - if ((config->GetDesign_Variable(iDV) == ANGLE_OF_ATTACK) || - (config->GetDesign_Variable(iDV) == FFD_ANGLE_OF_ATTACK)) { - Gradient[iDV][iDV_Value] = config->GetAoA_Sens(); - } - - Gradient[iDV][iDV_Value] += localGradient; - } - } - - AD::Reset(); - -} - -void OutputGradient(su2double** Gradient, CConfig* config, ofstream& Gradient_file){ - - unsigned short nDV, iDV, iDV_Value, nDV_Value; - - int rank = SU2_MPI::GetRank(); - - nDV = config->GetnDV(); - - /*--- Loop through all design variables and their gradients ---*/ - - for (iDV = 0; iDV < nDV; iDV++){ - nDV_Value = config->GetnDV_Value(iDV); - if (rank == MASTER_NODE){ - - /*--- Print the kind of design variable on screen ---*/ - - cout << endl << "Design variable ("; - for (std::map::const_iterator it = Param_Map.begin(); it != Param_Map.end(); ++it ){ - if (it->second == config->GetDesign_Variable(iDV)){ - cout << it->first << ") number "<< iDV << "." << endl; - } - } - - /*--- Print the kind of objective function to screen ---*/ - - for (std::map::const_iterator it = Objective_Map.begin(); it != Objective_Map.end(); ++it ){ - if (it->second == config->GetKind_ObjFunc()){ - cout << it->first << " gradient : "; - if (iDV == 0) Gradient_file << it->first << " gradient " << endl; - } - } - - /*--- Print the gradient to file and screen ---*/ - - for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ - cout << Gradient[iDV][iDV_Value]; - if (iDV_Value != nDV_Value-1 ){ - cout << ", "; - } - Gradient_file << Gradient[iDV][iDV_Value] << endl; - } - cout << endl; - cout <<"-------------------------------------------------------------------------" << endl; - } - } -} - - -void SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone) { - - unsigned short iMarker,iDim, nDim, nMarker, nVar; - unsigned long iVertex, iPoint, nPoint, nVertex; - su2double *Normal, Prod, Sens = 0.0, SensDim, Area; - - unsigned short iZone; - - CSolver *solver = nullptr; - COutput *output = nullptr; - - for (iZone = 0; iZone < val_nZone; iZone++) { - - nPoint = geometry[iZone][INST_0]->GetnPoint(); - nDim = geometry[iZone][INST_0]->GetnDim(); - nMarker = config[iZone]->GetnMarker_All(); - nVar = nDim + 1; - - /*--- We create a baseline solver to easily merge the sensitivity information ---*/ - - vector fieldnames; - fieldnames.push_back("\"Point\""); - fieldnames.push_back("\"x\""); - fieldnames.push_back("\"y\""); - if (nDim == 3) { - fieldnames.push_back("\"z\""); - } - fieldnames.push_back("\"Sensitivity_x\""); - fieldnames.push_back("\"Sensitivity_y\""); - if (nDim == 3) { - fieldnames.push_back("\"Sensitivity_z\""); - } - fieldnames.push_back("\"Surface_Sensitivity\""); - - solver = new CBaselineSolver(geometry[iZone][INST_0], config[iZone], nVar+nDim, fieldnames); - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) { - solver->GetNodes()->SetSolution(iPoint, iDim, geometry[iZone][INST_0]->nodes->GetCoord(iPoint, iDim)); - solver->GetNodes()->SetSolution(iPoint, iDim+nDim, geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim)); - } - } - - /*--- Compute the sensitivity in normal direction ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if(config[iZone]->GetSolid_Wall(iMarker) || (config[iZone]->GetMarker_All_DV(iMarker) == YES )) { - - nVertex = geometry[iZone][INST_0]->GetnVertex(iMarker); - - for (iVertex = 0; iVertex < nVertex; iVertex++) { - iPoint = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNormal(); - Prod = 0.0; - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - - /*--- Retrieve the gradient calculated with discrete adjoint method ---*/ - - SensDim = geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim); - - /*--- Calculate scalar product for projection onto the normal vector ---*/ - - Prod += Normal[iDim]*SensDim; - - Area += Normal[iDim]*Normal[iDim]; - } - - Area = sqrt(Area); - - /*--- Projection of the gradient onto the normal vector of the surface ---*/ - - Sens = Prod/Area; - - solver->GetNodes()->SetSolution(iPoint, 2*nDim, Sens); - - } - } - } - - output = new CBaselineOutput(config[iZone], nDim, solver); - output->PreprocessVolumeOutput(config[iZone]); - output->PreprocessHistoryOutput(config[iZone], false); - - /*--- Load the data --- */ - - output->Load_Data(geometry[iZone][INST_0], config[iZone], &solver); - - /*--- Set the surface filename ---*/ - - output->SetSurface_Filename(config[iZone]->GetSurfSens_FileName()); - - /*--- Set the volume filename ---*/ - - output->SetVolume_Filename(config[iZone]->GetVolSens_FileName()); - - /*--- Write to file ---*/ - - for (unsigned short iFile = 0; iFile < config[iZone]->GetnVolumeOutputFiles(); iFile++){ - auto FileFormat = config[iZone]->GetVolumeOutputFiles(); - if (FileFormat[iFile] != OUTPUT_TYPE::RESTART_ASCII && - FileFormat[iFile] != OUTPUT_TYPE::RESTART_BINARY && - FileFormat[iFile] != OUTPUT_TYPE::CSV) - output->WriteToFile(config[iZone], geometry[iZone][INST_0], FileFormat[iFile]); - } - - /*--- Free memory ---*/ - - delete output; - delete solver; - - } - -} - -void DerivativeTreatment_MeshSensitivity(CGeometry *geometry, CConfig *config, CVolumetricMovement *grid_movement) { - - int rank = SU2_MPI::GetRank(); - - /*--- Warning if choosen smoothing mode is unsupported. - * This is the default option if the user has not specified a mode in the config file. ---*/ - if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::NONE) { - SU2_MPI::Error("Unsupported operation modus for the Sobolev Smoothing Solver.", CURRENT_FUNCTION); - } - - /*-- Construct the smoothing solver and numerics ---*/ - std::unique_ptr solver(new CGradientSmoothingSolver(geometry, config)); - unsigned dim = (config->GetSmoothOnSurface() ? geometry->GetnDim() - 1 : geometry->GetnDim()); - std::unique_ptr numerics(new CGradSmoothing(dim, config)); - - if (rank == MASTER_NODE) cout << "Sobolev Smoothing of derivatives is active." << endl; - - /*--- Apply the smoothing procedure on the mesh level. ---*/ - if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::MESH_LEVEL) { - if (rank == MASTER_NODE) cout << " working on mesh level" << endl; - - /*--- Work with the surface derivatives. ---*/ - if (config->GetSmoothOnSurface()) { - - /*--- Project to surface and then smooth on surface. ---*/ - grid_movement->SetVolume_Deformation(geometry, config, false, true); - - /*--- Get the sensitivities from the geometry class to work with. ---*/ - solver->ReadSensFromGeometry(geometry); - - /*--- Perform the smoothing procedure on all boundaries marked as DV marker. ---*/ - solver->ApplyGradientSmoothingSurface(geometry, numerics.get(), config); - - /*--- After appling the solver write the results back ---*/ - solver->WriteSensToGeometry(geometry); - - /*--- Work with the volume derivatives. ---*/ - } else { - - /*--- Get the sensitivities from the geometry class to work with. ---*/ - solver->ReadSensFromGeometry(geometry); - - solver->ApplyGradientSmoothingVolume(geometry, numerics.get(), config); - - /*--- After appling the solver write the results back ---*/ - solver->WriteSensToGeometry(geometry); - - /*--- Projection is applied after smoothing. ---*/ - grid_movement->SetVolume_Deformation(geometry, config, false, true); - } - - } - -} - -void DerivativeTreatment_Gradient(CGeometry *geometry, CConfig *config, CVolumetricMovement* grid_movement, CSurfaceMovement *surface_movement, su2double** Gradient) { - - int rank = SU2_MPI::GetRank(); - - /*--- Error if choosen smoothing mode is unsupported. - * This is the default option if the user has not specified a mode in the config file. ---*/ - if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::NONE) { - SU2_MPI::Error("Unsupported operation modus for the Sobolev Smoothing Solver.", CURRENT_FUNCTION); - } - - /*-- Construct the smoothing solver and numerics ---*/ - std::unique_ptr solver(new CGradientSmoothingSolver(geometry, config)); - unsigned dim = (config->GetSmoothOnSurface() ? geometry->GetnDim() - 1 : geometry->GetnDim()); - std::unique_ptr numerics(new CGradSmoothing(dim, config)); - - if (rank == MASTER_NODE) cout << "Sobolev Smoothing of derivatives is active." << endl; - - /*--- Get the sensitivities from the geometry class to work with. ---*/ - solver->ReadSensFromGeometry(geometry); - - /*--- Apply the smoothing procedure on the DV level. ---*/ - if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::PARAM_LEVEL_COMPLETE) { - solver->ApplyGradientSmoothingDV(geometry, numerics.get(), surface_movement, grid_movement, config, Gradient); - - /*--- If smoothing already took place on the mesh level, or none is requested, just do standard projection. ---*/ - } else if (config->GetSobMode() == ENUM_SOBOLEV_MODUS::ONLY_GRAD || - config->GetSobMode() == ENUM_SOBOLEV_MODUS::MESH_LEVEL) { - solver->RecordTapeAndCalculateOriginalGradient(geometry, surface_movement, grid_movement, config, Gradient); - } - + SU2_MPI::Comm comm = SU2_MPI::GetComm(); + + /*--- Load in the number of zones and spatial dimensions in the mesh file + (if no config file is specified, default.cfg is used) ---*/ + + if (argc == 2) { strcpy(config_file_name, argv[1]); } + else { strcpy(config_file_name, "default.cfg"); } + + /*--- Initialize the mesh deformation driver ---*/ + + driver = new CDiscAdjDeformationDriver(config_file_name, comm); + + /*--- Launch the main external loop of the solver. ---*/ + + driver->Run(); + + /*--- Postprocess all the containers, close history file, exit SU2. ---*/ + + driver->Postprocessing(); + + delete driver; + + /*--- Finalize MPI parallelization ---*/ + SU2_MPI::Finalize(); + + return EXIT_SUCCESS; + } diff --git a/SU2_PY/pySU2/pySU2.i b/SU2_PY/pySU2/pySU2.i index 4cbb9afc3bd..e5cdf388fe0 100644 --- a/SU2_PY/pySU2/pySU2.i +++ b/SU2_PY/pySU2/pySU2.i @@ -50,6 +50,7 @@ threads="1" %import "../../Common/include/code_config.hpp" %import "../../Common/include/basic_types/datatype_structure.hpp" %import "../../Common/include/parallelization/mpi_structure.hpp" +%import "../../Common/include/drivers/CDriverBase.hpp" %include "std_string.i" %include "std_vector.i" %include "std_map.i" diff --git a/SU2_PY/pySU2/pySU2ad.i b/SU2_PY/pySU2/pySU2ad.i index e2e3bfbc54c..f0c6702a940 100644 --- a/SU2_PY/pySU2/pySU2ad.i +++ b/SU2_PY/pySU2/pySU2ad.i @@ -50,6 +50,7 @@ threads="1" %import "../../Common/include/code_config.hpp" %import "../../Common/include/basic_types/datatype_structure.hpp" %import "../../Common/include/parallelization/mpi_structure.hpp" +%import "../../Common/include/drivers/CDriverBase.hpp" %include "std_string.i" %include "std_vector.i" %include "std_map.i" From de94b6dc8057b1f67efe393b13149d6ad53c7f2f Mon Sep 17 00:00:00 2001 From: patelha57 Date: Mon, 14 Feb 2022 10:54:30 -0800 Subject: [PATCH 014/598] Introduce dependency of SU2_DOT on SU2_DEF --- SU2_DOT/src/meson.build | 4 ++-- meson.build | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/SU2_DOT/src/meson.build b/SU2_DOT/src/meson.build index 0f0b5234dcd..3cda6c961ed 100644 --- a/SU2_DOT/src/meson.build +++ b/SU2_DOT/src/meson.build @@ -5,7 +5,7 @@ if get_option('enable-normal') su2_dot = executable('SU2_DOT', su2_dot_src, install: true, - dependencies: [su2_deps, common_dep, su2_cfd_dep], + dependencies: [su2_deps, common_dep, su2_cfd_dep, su2_def_dep], cpp_args :[default_warning_flags, su2_cpp_args]) endif @@ -15,7 +15,7 @@ if get_option('enable-autodiff') su2_dot_ad = executable('SU2_DOT_AD', su2_dot_src, install: true, - dependencies: [su2_deps, codi_dep, commonAD_dep, su2_cfd_dep_ad], + dependencies: [su2_deps, codi_dep, commonAD_dep, su2_cfd_dep_ad, su2_def_dep_ad], cpp_args : [default_warning_flags, su2_cpp_args, codi_rev_args]) endif diff --git a/meson.build b/meson.build index ebb7be89255..597fc38ab7a 100644 --- a/meson.build +++ b/meson.build @@ -230,10 +230,10 @@ endif subdir('Common/src') # compile SU2_CFD executable subdir('SU2_CFD/src') -# compile SU2_DOT executable -subdir('SU2_DOT/src') # compile SU2_DEF executable subdir('SU2_DEF/src') +# compile SU2_DOT executable +subdir('SU2_DOT/src') # compile SU2_GEO executable subdir('SU2_GEO/src') # compile SU2_SOL executable From 1c57ad34350a4c8bba680fd56b8ef51c29e965d9 Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 14 Feb 2022 23:01:35 +0100 Subject: [PATCH 015/598] [WIP] Small fixes --- .../grid_movement/CSurfaceMovement.hpp | 2 +- Common/src/grid_movement/CSurfaceMovement.cpp | 6 +- SU2_CFD/src/drivers/CDriver.cpp | 2 +- .../include/drivers/CDeformationDriver.hpp | 11 +- SU2_DEF/src/drivers/CDeformationDriver.cpp | 105 +++++++++++------- 5 files changed, 75 insertions(+), 51 deletions(-) diff --git a/Common/include/grid_movement/CSurfaceMovement.hpp b/Common/include/grid_movement/CSurfaceMovement.hpp index 45acfd2aa74..700fa6dbe32 100644 --- a/Common/include/grid_movement/CSurfaceMovement.hpp +++ b/Common/include/grid_movement/CSurfaceMovement.hpp @@ -443,7 +443,7 @@ class CSurfaceMovement : public CGridMovement { * \param[in] geometry - Geometrical definition of the problem. * \param[in] val_mesh_filename - Name of the grid output file. */ - void WriteFFDInfo(CSurfaceMovement **surface_movement, CGeometry **geometry, CConfig **config); + void WriteFFDInfo(CSurfaceMovement **surface_movement, CGeometry ****geometry, CConfig **config); /*! * \brief Get information about if there is a complete FFDBox definition, or it is necessary to diff --git a/Common/src/grid_movement/CSurfaceMovement.cpp b/Common/src/grid_movement/CSurfaceMovement.cpp index 3d346c13950..8c57008d9ea 100644 --- a/Common/src/grid_movement/CSurfaceMovement.cpp +++ b/Common/src/grid_movement/CSurfaceMovement.cpp @@ -4674,7 +4674,7 @@ void CSurfaceMovement::MergeFFDInfo(CGeometry *geometry, CConfig *config) { } -void CSurfaceMovement::WriteFFDInfo(CSurfaceMovement** surface_movement, CGeometry **geometry, CConfig **config) { +void CSurfaceMovement::WriteFFDInfo(CSurfaceMovement** surface_movement, CGeometry ****geometry, CConfig **config) { unsigned short iOrder, jOrder, kOrder, iFFDBox, iCornerPoints, iParentFFDBox, iChildFFDBox, iZone; @@ -4685,13 +4685,13 @@ void CSurfaceMovement::WriteFFDInfo(CSurfaceMovement** surface_movement, CGeomet bool polar = (config[ZONE_0]->GetFFD_CoordSystem() == POLAR); - unsigned short nDim = geometry[ZONE_0]->GetnDim(); + unsigned short nDim = geometry[ZONE_0][INST_0][MESH_0]->GetnDim(); for (iZone = 0; iZone < config[ZONE_0]->GetnZone(); iZone++){ /*--- Merge the parallel FFD info ---*/ - surface_movement[iZone]->MergeFFDInfo(geometry[iZone], config[iZone]); + surface_movement[iZone]->MergeFFDInfo(geometry[iZone][INST_0][MESH_0], config[iZone]); if (iZone > 0){ diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index dcb8447d591..53ec9afc51a 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -343,7 +343,7 @@ void CDriver::SetContainers_Null(){ interface_container = new CInterface**[nZone] (); interface_types = new unsigned short*[nZone] (); output_container = new COutput*[nZone] (); - nInst = new unsigned short[nZone] (); + nInst = new unsigned short[nZone] (); // TODO: remove (moved to base class) driver_config = nullptr; driver_output = nullptr; diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index 5c1d7c0da4e..20b260f6eff 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -42,9 +42,6 @@ class CDeformationDriver : public CDriverBase { -protected: - CNumerics ***numerics_container; - public: /*! * \brief Constructor of the class. @@ -76,10 +73,10 @@ class CDeformationDriver : public CDriverBase { void CommunicateMeshDisplacements(void); protected: - /*! - * \brief Init_Containers - */ - void SetContainers_Null(); + // /*! + // * \brief Init_Containers + // */ + // void SetContainer_Null(); /*! * \brief Read in the config and mesh files. diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 90563e93f2f..22f58ebb574 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -54,11 +54,6 @@ CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) /*--- Copy the config filename ---*/ strcpy(config_file_name, confFile); - /*--- Initialize the configuration of the driver ---*/ - driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); - - nZone = driver_config->GetnZone(); - /*--- Initialize containers --- */ SetContainers_Null(); @@ -107,36 +102,41 @@ CDeformationDriver::~CDeformationDriver(void) { } -void CDeformationDriver::SetContainers_Null() { - - /*--- Create pointers to all of the classes that may be used throughout - the SU2_DEF code. In general, the pointers are instantiated down a - hierarchy over all zones as described in the comments below. ---*/ - config_container = new CConfig*[nZone]; - output_container = new COutput*[nZone]; - geometry_container = new CGeometry***[nZone]; - surface_movement = new CSurfaceMovement*[nZone]; - grid_movement = new CVolumetricMovement**[nZone]; - - solver_container = new CSolver****[nZone]; - numerics_container = new CNumerics**[nZone]; - - for (iZone = 0; iZone < nZone; iZone++) { - config_container[iZone] = nullptr; - output_container[iZone] = nullptr; - geometry_container[iZone] = nullptr; - surface_movement[iZone] = nullptr; - grid_movement[iZone] = nullptr; - solver_container[iZone] = nullptr; - numerics_container[iZone] = nullptr; - } -} +// void CDeformationDriver::SetContainers_Null() { +// +// /*--- Create pointers to all of the classes that may be used throughout +// the SU2_DEF code. In general, the pointers are instantiated down a +// hierarchy over all zones as described in the comments below. ---*/ +// config_container = new CConfig*[nZone]; +// output_container = new COutput*[nZone]; +// geometry_container = new CGeometry***[nZone]; +// surface_movement = new CSurfaceMovement*[nZone]; +// grid_movement = new CVolumetricMovement**[nZone]; +// +// solver_container = new CSolver****[nZone]; +// numerics_container = new CNumerics**[nZone]; +// +// for (iZone = 0; iZone < nZone; iZone++) { +// config_container[iZone] = nullptr; +// output_container[iZone] = nullptr; +// geometry_container[iZone] = nullptr; +// surface_movement[iZone] = nullptr; +// grid_movement[iZone] = nullptr; +// solver_container[iZone] = nullptr; +// numerics_container[iZone] = nullptr; +// } +// } void CDeformationDriver::Input_Preprocessing() { /*--- Initialize a char to store the zone filename ---*/ char zone_file_name[MAX_STRING_SIZE]; + /*--- Initialize the configuration of the driver ---*/ + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); + + nZone = driver_config->GetnZone(); + /*--- Loop over all zones to initialize the various classes. In most cases, nZone is equal to one. This represents the solution of a partial differential equation on a single block, unstructured mesh. ---*/ @@ -186,7 +186,11 @@ void CDeformationDriver::Geometrical_Preprocessing() { geometry_aux->SetColorGrid_Parallel(config_container[iZone]); /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - + unsigned short nInst_Zone = nInst[iZone]; + unsigned short nMesh = 1; + + geometry_container[iZone] = new CGeometry**[nInst_Zone] (); + geometry_container[iZone][INST_0] = new CGeometry*[nMesh] (); geometry_container[iZone][INST_0][MESH_0] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); /*--- Deallocate the memory of geometry_aux ---*/ @@ -263,21 +267,36 @@ void CDeformationDriver::Output_Preprocessing() { void CDeformationDriver::Solver_Preprocessing() { for (iZone = 0; iZone < nZone; iZone++) { + unsigned short nInst_Zone = nInst[iZone]; + unsigned short nMesh = 1; + unsigned short nSols = MAX_SOLS; + + + solver_container[iZone] = new CSolver*** [nInst_Zone] (); + solver_container[iZone][INST_0] = new CSolver** [nMesh] (); + solver_container[iZone][INST_0][MESH_0] = new CSolver* [nSols] (); solver_container[iZone][INST_0][MESH_0][MESH_SOL] = new CMeshSolver(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); - } - + } } void CDeformationDriver::Numerics_Preprocessing() { for (iZone = 0; iZone < nZone; iZone++) { - numerics_container[iZone] = new CNumerics* [omp_get_num_threads() * MAX_TERMS](); + unsigned short nInst_Zone = nInst[iZone]; + unsigned short nMesh = 1; + unsigned short nSols = MAX_SOLS; + unsigned int nTerm = omp_get_num_threads() * MAX_TERMS; + + numerics_container[iZone] = new CNumerics**** [nInst_Zone] (); + numerics_container[iZone][INST_0] = new CNumerics*** [nMesh] (); + numerics_container[iZone][INST_0][MESH_0] = new CNumerics** [nSols] (); + numerics_container[iZone][INST_0][MESH_0][MESH_SOL] = new CNumerics* [nTerm] (); for (int thread = 0; thread < omp_get_max_threads(); ++thread) { const int iTerm = FEA_TERM + thread * MAX_TERMS; const int nDim = geometry_container[iZone][INST_0][MESH_0]->GetnDim(); - numerics_container[iZone][iTerm] = new CFEAMeshElasticity(nDim, nDim, geometry_container[iZone][INST_0][MESH_0]->GetnElem(), config_container[iZone]); + numerics_container[iZone][INST_0][MESH_0][MESH_SOL][iTerm] = new CFEAMeshElasticity(nDim, nDim, geometry_container[iZone][INST_0][MESH_0]->GetnElem(), config_container[iZone]); } } @@ -322,11 +341,11 @@ void CDeformationDriver::Update() { /*--- Set the stiffness of each element mesh into the mesh numerics ---*/ - solver_container[iZone][INST_0][MESH_0][MESH_SOL]->SetMesh_Stiffness(numerics_container[iZone], config_container[iZone]); + solver_container[iZone][INST_0][MESH_0][MESH_SOL]->SetMesh_Stiffness(numerics_container[iZone][INST_0][MESH_0][MESH_SOL], config_container[iZone]); /*--- Deform the volume grid around the new boundary locations ---*/ - solver_container[iZone][INST_0][MESH_0][MESH_SOL]->DeformMesh(geometry_container[iZone][INST_0][MESH_0], numerics_container[iZone], config_container[iZone]); + solver_container[iZone][INST_0][MESH_0][MESH_SOL]->DeformMesh(geometry_container[iZone][INST_0][MESH_0], numerics_container[iZone][INST_0][MESH_0][MESH_SOL], config_container[iZone]); } } @@ -511,7 +530,7 @@ void CDeformationDriver::Output() { /*--- Load the data --- */ output_container[iZone]->Load_Data(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], nullptr); - + output_container[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone][INST_0][MESH_0], OUTPUT_TYPE::MESH, driver_config->GetMesh_Out_FileName()); /*--- Set the file names for the visualization files ---*/ @@ -538,7 +557,7 @@ void CDeformationDriver::Output() { if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; - surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container[INST_0][MESH_0], config_container); + surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); } } @@ -555,7 +574,10 @@ void CDeformationDriver::Postprocessing() { for (iZone = 0; iZone < nZone; iZone++) { if (numerics_container[iZone] != nullptr) { for (unsigned int iTerm = 0; iTerm < MAX_TERMS*omp_get_max_threads(); iTerm++) { - delete numerics_container[iZone][iTerm]; + delete numerics_container[iZone][INST_0][MESH_0][MESH_SOL][iTerm]; + delete [] numerics_container[iZone][INST_0][MESH_0][MESH_SOL]; + delete [] numerics_container[iZone][INST_0][MESH_0]; + delete [] numerics_container[iZone][INST_0]; } delete [] numerics_container[iZone]; } @@ -565,6 +587,9 @@ void CDeformationDriver::Postprocessing() { for (iZone = 0; iZone < nZone; iZone++) { delete solver_container[iZone][INST_0][MESH_0][MESH_SOL]; + delete [] solver_container[iZone][INST_0][MESH_0]; + delete [] solver_container[iZone][INST_0]; + delete [] solver_container[iZone]; } delete [] solver_container; if (rank == MASTER_NODE) cout << "Deleted CSolver container." << endl; @@ -572,6 +597,8 @@ void CDeformationDriver::Postprocessing() { if (geometry_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { delete geometry_container[iZone][INST_0][MESH_0]; + delete [] geometry_container[iZone][INST_0]; + delete [] geometry_container[iZone]; } delete [] geometry_container; } From 342d3a204c36f1affc49d8e4b443e6684c7d097b Mon Sep 17 00:00:00 2001 From: patelha57 Date: Tue, 15 Feb 2022 15:21:07 -0800 Subject: [PATCH 016/598] Fix 'unknown module' SWIG warning for CDriverBase --- SU2_PY/pySU2/pySU2.i | 5 +++-- SU2_PY/pySU2/pySU2ad.i | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/SU2_PY/pySU2/pySU2.i b/SU2_PY/pySU2/pySU2.i index e5cdf388fe0..02ba990a514 100644 --- a/SU2_PY/pySU2/pySU2.i +++ b/SU2_PY/pySU2/pySU2.i @@ -38,6 +38,7 @@ threads="1" ) pysu2 %{ +#include "../../Common/include/drivers/CDriverBase.hpp" #include "../../SU2_CFD/include/drivers/CDriver.hpp" #include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" @@ -50,7 +51,7 @@ threads="1" %import "../../Common/include/code_config.hpp" %import "../../Common/include/basic_types/datatype_structure.hpp" %import "../../Common/include/parallelization/mpi_structure.hpp" -%import "../../Common/include/drivers/CDriverBase.hpp" + %include "std_string.i" %include "std_vector.i" %include "std_map.i" @@ -88,7 +89,7 @@ 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. */ -// CDriver class +%include "../../Common/include/drivers/CDriverBase.hpp" %include "../../SU2_CFD/include/drivers/CDriver.hpp" %include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" diff --git a/SU2_PY/pySU2/pySU2ad.i b/SU2_PY/pySU2/pySU2ad.i index f0c6702a940..27a2dfe6cd1 100644 --- a/SU2_PY/pySU2/pySU2ad.i +++ b/SU2_PY/pySU2/pySU2ad.i @@ -38,6 +38,7 @@ threads="1" ) pysu2ad %{ +#include "../../Common/include/drivers/CDriverBase.hpp" #include "../../SU2_CFD/include/drivers/CDriver.hpp" #include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" #include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" @@ -50,7 +51,7 @@ threads="1" %import "../../Common/include/code_config.hpp" %import "../../Common/include/basic_types/datatype_structure.hpp" %import "../../Common/include/parallelization/mpi_structure.hpp" -%import "../../Common/include/drivers/CDriverBase.hpp" + %include "std_string.i" %include "std_vector.i" %include "std_map.i" @@ -88,7 +89,7 @@ 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. */ -// CDriver class +%include "../../Common/include/drivers/CDriverBase.hpp" %include "../../SU2_CFD/include/drivers/CDriver.hpp" %include "../../SU2_CFD/include/drivers/CSinglezoneDriver.hpp" %include "../../SU2_CFD/include/drivers/CMultizoneDriver.hpp" From bfb175c15a5086847a69507869b2071a90a87232 Mon Sep 17 00:00:00 2001 From: aa-g Date: Wed, 16 Feb 2022 20:43:05 +0100 Subject: [PATCH 017/598] Fix small issues in getters, skip FFD output if not defined --- Common/src/drivers/CDriverBase.cpp | 13 ++++---- .../include/drivers/CDeformationDriver.hpp | 3 ++ SU2_DEF/src/drivers/CDeformationDriver.cpp | 30 ++++++++++--------- SU2_PY/pySU2/pySU2.i | 3 ++ SU2_PY/pySU2/pySU2ad.i | 3 ++ 5 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index 094113173ec..7d7de27aabd 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -65,24 +65,23 @@ void CDriverBase::SetContainers_Null() { grid_movement = nullptr; FFDBox = nullptr; - nInst = new unsigned short[nZone] (); - config_container = new CConfig*[nZone] (); output_container = new COutput*[nZone] (); geometry_container = new CGeometry***[nZone] (); solver_container = new CSolver****[nZone] (); numerics_container = new CNumerics*****[nZone] (); - surface_movement = new CSurfaceMovement*[nZone] (); grid_movement = new CVolumetricMovement**[nZone] (); FFDBox = new CFreeFormDefBox**[nZone] (); - driver_config = nullptr; - driver_output = nullptr; + nInst = new unsigned short[nZone] (); for (iZone = 0; iZone < nZone; iZone++) { nInst[iZone] = 1; } + + driver_config = nullptr; + driver_output = nullptr; } map CDriverBase::GetBoundaryMarkerIndices() const { @@ -302,7 +301,7 @@ vector CDriverBase::GetDomain() const { CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; const auto nPoint = geometry->GetnPoint(); - vector values(nPoint); + vector values; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { values.push_back(geometry->nodes->GetDomain(iPoint)); @@ -315,7 +314,7 @@ vector CDriverBase::GetDomainMarker(unsigned short iMarker) const { CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; const auto nVertex = geometry->GetnVertex(iMarker); - vector values(nVertex); + vector values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index 20b260f6eff..6d64c4b6f2f 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -42,6 +42,9 @@ class CDeformationDriver : public CDriverBase { +protected: + bool haveSurfaceDeformation = false; // flag used to determine whether surface deformation is available for output + public: /*! * \brief Constructor of the class. diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 22f58ebb574..c1e6136b970 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -116,14 +116,7 @@ CDeformationDriver::~CDeformationDriver(void) { // solver_container = new CSolver****[nZone]; // numerics_container = new CNumerics**[nZone]; // -// for (iZone = 0; iZone < nZone; iZone++) { -// config_container[iZone] = nullptr; -// output_container[iZone] = nullptr; -// geometry_container[iZone] = nullptr; -// surface_movement[iZone] = nullptr; -// grid_movement[iZone] = nullptr; -// solver_container[iZone] = nullptr; -// numerics_container[iZone] = nullptr; + // } // } @@ -243,6 +236,9 @@ void CDeformationDriver::Geometrical_Preprocessing() { geometry_container[iZone][INST_0][MESH_0]->PreprocessP2PComms(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); } + + /*--- Get the number of dimensions ---*/ + nDim = geometry_container[ZONE_0][INST_0][MESH_0]->GetnDim(); } void CDeformationDriver::Output_Preprocessing() { @@ -351,6 +347,8 @@ void CDeformationDriver::Update() { } void CDeformationDriver::Update_Legacy() { + + std::cout << "UPDATE LEGACY CALLED" << std::endl; for (iZone = 0; iZone < nZone; iZone++){ @@ -393,6 +391,7 @@ void CDeformationDriver::Update_Legacy() { /*--- Definition and initialization of the surface deformation class ---*/ surface_movement[iZone] = new CSurfaceMovement(); + haveSurfaceDeformation = true; /*--- Copy coordinates to the surface structure ---*/ @@ -553,12 +552,15 @@ void CDeformationDriver::Output() { (config_container[ZONE_0]->GetDesign_Variable(0) != TRANSLATE_GRID) && (config_container[ZONE_0]->GetDesign_Variable(0) != ROTATE_GRID)) { - /*--- Write the the free-form deformation boxes after deformation. ---*/ - - if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; - - surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); - + /*--- Write the the free-form deformation boxes after deformation (if defined). ---*/ + if (true) { + if (rank == MASTER_NODE) cout << "No FFD information available." << endl; + } + else { + if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; + + surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); + } } } } diff --git a/SU2_PY/pySU2/pySU2.i b/SU2_PY/pySU2/pySU2.i index 02ba990a514..0125ffd1e6b 100644 --- a/SU2_PY/pySU2/pySU2.i +++ b/SU2_PY/pySU2/pySU2.i @@ -63,6 +63,9 @@ threads="1" #endif namespace std { + %template() vector; + %template() vector; + %template() vector>; %template() vector; %template() vector; %template() vector; diff --git a/SU2_PY/pySU2/pySU2ad.i b/SU2_PY/pySU2/pySU2ad.i index 27a2dfe6cd1..a1f47b6bf2b 100644 --- a/SU2_PY/pySU2/pySU2ad.i +++ b/SU2_PY/pySU2/pySU2ad.i @@ -63,6 +63,9 @@ threads="1" #endif namespace std { + %template() vector; + %template() vector; + %template() vector>; %template() vector; %template() vector; %template() vector; From 1fdb8374e38a89972b4e81c81c786661083f79dc Mon Sep 17 00:00:00 2001 From: aa-g Date: Fri, 18 Feb 2022 20:54:24 +0100 Subject: [PATCH 018/598] Remove some code duplication and fix memory leaks --- Common/include/drivers/CDriverBase.hpp | 2 +- Common/src/drivers/CDriverBase.cpp | 6 +- .../include/drivers/CDeformationDriver.hpp | 5 - .../drivers/CDiscAdjDeformationDriver.hpp | 11 +- SU2_DEF/src/drivers/CDeformationDriver.cpp | 46 ++--- .../src/drivers/CDiscAdjDeformationDriver.cpp | 169 ++++++++++-------- 6 files changed, 123 insertions(+), 116 deletions(-) diff --git a/Common/include/drivers/CDriverBase.hpp b/Common/include/drivers/CDriverBase.hpp index 7291411e397..28619eab44e 100644 --- a/Common/include/drivers/CDriverBase.hpp +++ b/Common/include/drivers/CDriverBase.hpp @@ -80,7 +80,7 @@ class CDriverBase { /*! * \brief Destructor of the class. */ - ~CDriverBase(void); + virtual ~CDriverBase(void); /*! * \brief A virtual member. diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index 7d7de27aabd..4ec2d3b1a27 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -38,7 +38,7 @@ CDriverBase::CDriverBase(char* confFile, unsigned short val_nZone, SU2_Comm MPIC StopTime(0.0), UsedTime(0.0), TimeIter(0), - nZone() + nZone(val_nZone) { } @@ -53,8 +53,6 @@ void CDriverBase::SetContainers_Null() { hierarchy over all zones, multigrid levels, equation sets, and equation terms as described in the comments below. ---*/ - nInst = nullptr; - config_container = nullptr; output_container = nullptr; geometry_container = nullptr; @@ -74,7 +72,7 @@ void CDriverBase::SetContainers_Null() { grid_movement = new CVolumetricMovement**[nZone] (); FFDBox = new CFreeFormDefBox**[nZone] (); - nInst = new unsigned short[nZone] (); + nInst = new unsigned short[nZone]; for (iZone = 0; iZone < nZone; iZone++) { nInst[iZone] = 1; diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index 6d64c4b6f2f..329c660bb4c 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -76,11 +76,6 @@ class CDeformationDriver : public CDriverBase { void CommunicateMeshDisplacements(void); protected: - // /*! - // * \brief Init_Containers - // */ - // void SetContainer_Null(); - /*! * \brief Read in the config and mesh files. */ diff --git a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp index 41a1df49b2c..1f1f79b76c1 100644 --- a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp @@ -54,10 +54,7 @@ class CDiscAdjDeformationDriver : public CDriverBase { protected: su2double** Gradient; - ofstream Gradient_file; - CGeometry ***geometry_container; /*!< \brief Geometrical definition of the problem. */ - CSurfaceMovement **surface_movement; - CVolumetricMovement **grid_movement; + ofstream Gradient_file; public: /*! @@ -83,10 +80,6 @@ class CDiscAdjDeformationDriver : public CDriverBase { void Postprocessing(); protected: - /*! - * \brief Init_Containers - */ - void SetContainers_Null(); /*! * \brief Read in the config and mesh files. @@ -140,7 +133,7 @@ class CDiscAdjDeformationDriver : public CDriverBase { * \param[in] val_nZone - Number of Zones. */ - void SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone); + void SetSensitivity_Files(CGeometry ****geometry, CConfig **config, unsigned short val_nZone); /*! * \brief Treatment of derivatives with the Sobolev smoothing solver. diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index c1e6136b970..8bf4b8b9e98 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -51,9 +51,6 @@ CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) rank = SU2_MPI::GetRank(); size = SU2_MPI::GetSize(); - /*--- Copy the config filename ---*/ - strcpy(config_file_name, confFile); - /*--- Initialize containers --- */ SetContainers_Null(); @@ -102,24 +99,6 @@ CDeformationDriver::~CDeformationDriver(void) { } -// void CDeformationDriver::SetContainers_Null() { -// -// /*--- Create pointers to all of the classes that may be used throughout -// the SU2_DEF code. In general, the pointers are instantiated down a -// hierarchy over all zones as described in the comments below. ---*/ -// config_container = new CConfig*[nZone]; -// output_container = new COutput*[nZone]; -// geometry_container = new CGeometry***[nZone]; -// surface_movement = new CSurfaceMovement*[nZone]; -// grid_movement = new CVolumetricMovement**[nZone]; -// -// solver_container = new CSolver****[nZone]; -// numerics_container = new CNumerics**[nZone]; -// - -// } -// } - void CDeformationDriver::Input_Preprocessing() { /*--- Initialize a char to store the zone filename ---*/ @@ -142,6 +121,7 @@ void CDeformationDriver::Input_Preprocessing() { if (driver_config->GetnConfigFiles() > 0){ strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); + config_container[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); } else { config_container[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_DEF, iZone, nZone, true); @@ -179,6 +159,7 @@ void CDeformationDriver::Geometrical_Preprocessing() { geometry_aux->SetColorGrid_Parallel(config_container[iZone]); /*--- Build the grid data structures using the ParMETIS coloring. ---*/ + unsigned short nInst_Zone = nInst[iZone]; unsigned short nMesh = 1; @@ -348,13 +329,13 @@ void CDeformationDriver::Update() { void CDeformationDriver::Update_Legacy() { - std::cout << "UPDATE LEGACY CALLED" << std::endl; - for (iZone = 0; iZone < nZone; iZone++){ if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { + unsigned short nInst_Zone = nInst[iZone]; /*--- Definition of the Class for grid movement ---*/ + grid_movement[iZone] = new CVolumetricMovement* [nInst_Zone] (); grid_movement[iZone][INST_0] = new CVolumetricMovement(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); /*--- Save original coordinates to be reused in convexity checking procedure ---*/ @@ -588,10 +569,12 @@ void CDeformationDriver::Postprocessing() { if (rank == MASTER_NODE) cout << "Deleted CNumerics container." << endl; for (iZone = 0; iZone < nZone; iZone++) { - delete solver_container[iZone][INST_0][MESH_0][MESH_SOL]; - delete [] solver_container[iZone][INST_0][MESH_0]; - delete [] solver_container[iZone][INST_0]; - delete [] solver_container[iZone]; + if (solver_container[iZone] != nullptr) { + delete solver_container[iZone][INST_0][MESH_0][MESH_SOL]; + delete [] solver_container[iZone][INST_0][MESH_0]; + delete [] solver_container[iZone][INST_0]; + delete [] solver_container[iZone]; + } } delete [] solver_container; if (rank == MASTER_NODE) cout << "Deleted CSolver container." << endl; @@ -606,6 +589,12 @@ void CDeformationDriver::Postprocessing() { } if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; + for (iZone = 0; iZone < nZone; iZone++) { + delete [] FFDBox[iZone]; + } + delete [] FFDBox; + if (rank == MASTER_NODE) cout << "Deleted CFreeFormDefBox class." << endl; + if (surface_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { delete surface_movement[iZone]; @@ -617,6 +606,7 @@ void CDeformationDriver::Postprocessing() { if (grid_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { delete grid_movement[iZone][INST_0]; + delete [] grid_movement[iZone]; } delete [] grid_movement; } @@ -638,6 +628,8 @@ void CDeformationDriver::Postprocessing() { } if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; + if (nInst != nullptr) delete [] nInst; + /*--- Exit the solver cleanly ---*/ if (rank == MASTER_NODE) diff --git a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp index 63555b249c2..fea679b6f55 100644 --- a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp @@ -46,17 +46,6 @@ CDiscAdjDeformationDriver::CDiscAdjDeformationDriver(char* confFile, SU2_Comm MP rank = SU2_MPI::GetRank(); size = SU2_MPI::GetSize(); - /*--- Copy the config filename ---*/ - strcpy(config_file_name, confFile); - - /*--- Read the name and format of the input mesh file to get from the mesh - file the number of zones and dimensions from the numerical grid (required - for variables allocation) ---*/ - - driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DOT); - - nZone = driver_config->GetnZone(); - /*--- Initialize containers --- */ SetContainers_Null(); @@ -93,30 +82,16 @@ CDiscAdjDeformationDriver::~CDiscAdjDeformationDriver(void) { } -void CDiscAdjDeformationDriver::SetContainers_Null() { - - /*--- Definition of the containers per zones ---*/ - - config_container = new CConfig*[nZone] (); - geometry_container = new CGeometry**[nZone] (); - surface_movement = new CSurfaceMovement*[nZone] (); - grid_movement = new CVolumetricMovement*[nZone] (); - - nInst = new unsigned short[nZone]; - for (iZone = 0; iZone < nZone; iZone++) { - nInst[iZone] = 1; - } -} - void CDiscAdjDeformationDriver::Input_Preprocessing() { - - if (!config_container[iZone]->GetDiscrete_Adjoint()) { - SU2_MPI::Error("The discrete adjoint solver was not specified in the configuration file.", CURRENT_FUNCTION); - } /*--- Initialize a char to store the zone filename ---*/ char zone_file_name[MAX_STRING_SIZE]; + /*--- Initialize the configuration of the driver ---*/ + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); + + nZone = driver_config->GetnZone(); + /*--- Loop over all zones to initialize the various classes. In most cases, nZone is equal to one. This represents the solution of a partial differential equation on a single block, unstructured mesh. ---*/ @@ -135,6 +110,11 @@ void CDiscAdjDeformationDriver::Input_Preprocessing() { } config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); + + if (!config_container[iZone]->GetDiscrete_Adjoint()) { + SU2_MPI::Error("The discrete adjoint solver was not specified in the configuration file.", CURRENT_FUNCTION); + } + } /*--- Set the multizone part of the problem. ---*/ @@ -151,6 +131,7 @@ void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { /*--- Loop over all zones to initialize the various classes. In most cases, nZone is equal to one. This represents the solution of a partial differential equation on a single block, unstructured mesh. ---*/ + unsigned short nMesh = 1; for (iZone = 0; iZone < nZone; iZone++) { @@ -162,7 +143,7 @@ void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { nInst[iZone] = config_container[iZone]->GetnTimeInstances(); - geometry_container[iZone] = new CGeometry*[nInst[iZone]]; + geometry_container[iZone] = new CGeometry**[nInst[iZone]]; for (iInst = 0; iInst < nInst[iZone]; iInst++){ @@ -184,13 +165,15 @@ void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { if( fem_solver ) { switch( config_container[iZone]->GetKind_FEM_Flow() ) { case DG: { - geometry_container[iZone][iInst] = new CMeshFEM_DG(geometry_aux, config_container[iZone]); + geometry_container[iZone][iInst] = new CGeometry*[nMesh]; + geometry_container[iZone][iInst][MESH_0] = new CMeshFEM_DG(geometry_aux, config_container[iZone]); break; } } } else { - geometry_container[iZone][iInst] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); + geometry_container[iZone][iInst] = new CGeometry*[nMesh]; + geometry_container[iZone][iInst][MESH_0] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); } /*--- Deallocate the memory of geometry_aux ---*/ @@ -199,21 +182,21 @@ void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { /*--- Add the Send/Receive boundaries ---*/ - geometry_container[iZone][iInst]->SetSendReceive(config_container[iZone]); + geometry_container[iZone][iInst][MESH_0]->SetSendReceive(config_container[iZone]); /*--- Add the Send/Receive boundaries ---*/ - geometry_container[iZone][iInst]->SetBoundaries(config_container[iZone]); + geometry_container[iZone][iInst][MESH_0]->SetBoundaries(config_container[iZone]); /*--- Create the vertex structure (required for MPI) ---*/ if (rank == MASTER_NODE) cout << "Identify vertices." << endl; - geometry_container[iZone][iInst]->SetVertex(config_container[iZone]); + geometry_container[iZone][iInst][MESH_0]->SetVertex(config_container[iZone]); /*--- Store the global to local mapping after preprocessing. ---*/ if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; - geometry_container[iZone][iInst]->SetGlobal_to_Local_Point(); + geometry_container[iZone][iInst][MESH_0]->SetGlobal_to_Local_Point(); /* Test for a fem solver, because some more work must be done. */ @@ -221,7 +204,7 @@ void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { /*--- Carry out a dynamic cast to CMeshFEM_DG, such that it is not needed to define all virtual functions in the base class CGeometry. ---*/ - CMeshFEM_DG *DGMesh = dynamic_cast(geometry_container[iZone][iInst]); + CMeshFEM_DG *DGMesh = dynamic_cast(geometry_container[iZone][iInst][MESH_0]); /*--- Determine the standard elements for the volume elements. ---*/ if (rank == MASTER_NODE) cout << "Creating standard volume elements." << endl; @@ -240,35 +223,35 @@ void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { /*--- Compute elements surrounding points, points surrounding points ---*/ if (rank == MASTER_NODE) cout << "Setting local point connectivity." << endl; - geometry_container[iZone][INST_0]->SetPoint_Connectivity(); + geometry_container[iZone][INST_0][MESH_0]->SetPoint_Connectivity(); /*--- Check the orientation before computing geometrical quantities ---*/ - geometry_container[iZone][INST_0]->SetBoundVolume(); + geometry_container[iZone][INST_0][MESH_0]->SetBoundVolume(); if (config_container[iZone]->GetReorientElements()) { if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation of the elements." << endl; - geometry_container[iZone][INST_0]->Check_IntElem_Orientation(config_container[iZone]); - geometry_container[iZone][INST_0]->Check_BoundElem_Orientation(config_container[iZone]); + geometry_container[iZone][INST_0][MESH_0]->Check_IntElem_Orientation(config_container[iZone]); + geometry_container[iZone][INST_0][MESH_0]->Check_BoundElem_Orientation(config_container[iZone]); } /*--- Create the edge structure ---*/ if (rank == MASTER_NODE) cout << "Identify edges and vertices." << endl; - geometry_container[iZone][INST_0]->SetEdges(); geometry_container[iZone][INST_0]->SetVertex(config_container[iZone]); + geometry_container[iZone][INST_0][MESH_0]->SetEdges(); geometry_container[iZone][INST_0][MESH_0]->SetVertex(config_container[iZone]); /*--- Create the dual control volume structures ---*/ if (rank == MASTER_NODE) cout << "Setting the bound control volume structure." << endl; - geometry_container[iZone][INST_0]->SetBoundControlVolume(config_container[ZONE_0], ALLOCATE); + geometry_container[iZone][INST_0][MESH_0]->SetBoundControlVolume(config_container[ZONE_0], ALLOCATE); /*--- Store the global to local mapping after preprocessing. ---*/ if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; - geometry_container[iZone][INST_0]->SetGlobal_to_Local_Point(); + geometry_container[iZone][INST_0][MESH_0]->SetGlobal_to_Local_Point(); /*--- Create the point-to-point MPI communication structures. ---*/ - geometry_container[iZone][INST_0]->PreprocessP2PComms(geometry_container[iZone][INST_0], config_container[iZone]); + geometry_container[iZone][INST_0][MESH_0]->PreprocessP2PComms(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); } } @@ -281,20 +264,23 @@ void CDiscAdjDeformationDriver::Run() { for (iZone = 0; iZone < nZone; iZone++) { if (rank == MASTER_NODE) cout << "Reading volume sensitivities at each node from file." << endl; - grid_movement[iZone] = new CVolumetricMovement(geometry_container[iZone][INST_0], config_container[iZone]); + unsigned short nInst_Zone = nInst[iZone]; + + grid_movement[iZone] = new CVolumetricMovement* [nInst_Zone] (); + grid_movement[iZone][INST_0] = new CVolumetricMovement(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); /*--- Read in sensitivities from file. ---*/ if (config_container[ZONE_0]->GetSensitivity_Format() == UNORDERED_ASCII) - geometry_container[iZone][INST_0]->ReadUnorderedSensitivity(config_container[iZone]); + geometry_container[iZone][INST_0][MESH_0]->ReadUnorderedSensitivity(config_container[iZone]); else - geometry_container[iZone][INST_0]->SetSensitivity(config_container[iZone]); + geometry_container[iZone][INST_0][MESH_0]->SetSensitivity(config_container[iZone]); if (rank == MASTER_NODE) cout << "\n---------------------- Mesh sensitivity computation ---------------------" << endl; if (config_container[iZone]->GetDiscrete_Adjoint() && config_container[iZone]->GetSmoothGradient() && config_container[iZone]->GetSobMode() == ENUM_SOBOLEV_MODUS::MESH_LEVEL) { - DerivativeTreatment_MeshSensitivity(geometry_container[iZone][INST_0], config_container[iZone], grid_movement[iZone]); + DerivativeTreatment_MeshSensitivity(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], grid_movement[iZone][INST_0]); } else { - grid_movement[iZone]->SetVolume_Deformation(geometry_container[iZone][INST_0], config_container[iZone], false, true); + grid_movement[iZone][INST_0]->SetVolume_Deformation(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], false, true); } } @@ -325,19 +311,19 @@ void CDiscAdjDeformationDriver::Run() { /*--- Copy coordinates to the surface structure ---*/ - surface_movement[iZone]->CopyBoundary(geometry_container[iZone][INST_0], config_container[iZone]); + surface_movement[iZone]->CopyBoundary(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); /*--- If AD mode is enabled we can use it to compute the projection, * otherwise we use finite differences. ---*/ if (config_container[iZone]->GetAD_Mode()) if (config_container[iZone]->GetSmoothGradient()) { - DerivativeTreatment_Gradient(geometry_container[iZone][INST_0], config_container[iZone], grid_movement[iZone], surface_movement[iZone] , Gradient); + DerivativeTreatment_Gradient(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], grid_movement[iZone][INST_0], surface_movement[iZone] , Gradient); } else { - SetProjection_AD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); + SetProjection_AD(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], surface_movement[iZone] , Gradient); } } else { - SetProjection_FD(geometry_container[iZone][INST_0], config_container[iZone], surface_movement[iZone] , Gradient); + SetProjection_FD(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], surface_movement[iZone] , Gradient); } } // for iZone @@ -365,19 +351,42 @@ void CDiscAdjDeformationDriver::Postprocessing() { if (rank == MASTER_NODE) cout << "\n------------------------- Solver Postprocessing -------------------------" << endl; + for (iZone = 0; iZone < nZone; iZone++) { + if (numerics_container[iZone] != nullptr) { + delete [] numerics_container[iZone]; + } + } + delete [] numerics_container; + if (rank == MASTER_NODE) cout << "Deleted CNumerics container." << endl; + + for (iZone = 0; iZone < nZone; iZone++) { + if (solver_container[iZone] != nullptr) { + delete [] solver_container[iZone]; + } + } + delete [] solver_container; + if (rank == MASTER_NODE) cout << "Deleted CSolver container." << endl; + if (geometry_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { if (geometry_container[iZone] != nullptr) { for (iInst = 0; iInst < nInst[iZone]; iInst++){ - delete geometry_container[iZone][iInst]; + delete geometry_container[iZone][iInst][MESH_0]; + delete [] geometry_container[iZone][iInst]; } - delete geometry_container[iZone]; + delete [] geometry_container[iZone]; } } delete [] geometry_container; } if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; + for (iZone = 0; iZone < nZone; iZone++) { + delete [] FFDBox[iZone]; + } + delete [] FFDBox; + if (rank == MASTER_NODE) cout << "Deleted CFreeFormDefBox class." << endl; + if (surface_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { delete surface_movement[iZone]; @@ -388,7 +397,12 @@ void CDiscAdjDeformationDriver::Postprocessing() { if (grid_movement != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { - delete grid_movement[iZone]; + if (grid_movement[iZone] != nullptr) { + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + delete grid_movement[iZone][iInst]; + } + delete [] grid_movement[iZone]; + } } delete [] grid_movement; } @@ -402,6 +416,21 @@ void CDiscAdjDeformationDriver::Postprocessing() { } if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; + if (output_container != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + delete output_container[iZone]; + } + delete [] output_container; + } + if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; + + if (nInst != nullptr) delete [] nInst; + + /*--- Exit the solver cleanly ---*/ + + if (rank == MASTER_NODE) + cout << endl << "------------------------- Exit Success (SU2_DEF_AD) ------------------------" << endl << endl; + } void CDiscAdjDeformationDriver::SetProjection_FD(CGeometry *geometry, CConfig *config, CSurfaceMovement *surface_movement, su2double** Gradient){ @@ -816,7 +845,7 @@ void CDiscAdjDeformationDriver::OutputGradient(su2double** Gradient, CConfig* co } -void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ***geometry, CConfig **config, unsigned short val_nZone) { +void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ****geometry, CConfig **config, unsigned short val_nZone) { unsigned short iMarker,iDim, nDim, nMarker, nVar; unsigned long iVertex, iPoint, nPoint, nVertex; @@ -829,8 +858,8 @@ void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ***geometry, CCon for (iZone = 0; iZone < val_nZone; iZone++) { - nPoint = geometry[iZone][INST_0]->GetnPoint(); - nDim = geometry[iZone][INST_0]->GetnDim(); + nPoint = geometry[iZone][INST_0][MESH_0]->GetnPoint(); + nDim = geometry[iZone][INST_0][MESH_0]->GetnDim(); nMarker = config[iZone]->GetnMarker_All(); nVar = nDim + 1; @@ -850,12 +879,12 @@ void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ***geometry, CCon } fieldnames.push_back("\"Surface_Sensitivity\""); - solver = new CBaselineSolver(geometry[iZone][INST_0], config[iZone], nVar+nDim, fieldnames); + solver = new CBaselineSolver(geometry[iZone][INST_0][MESH_0], config[iZone], nVar+nDim, fieldnames); for (iPoint = 0; iPoint < nPoint; iPoint++) { for (iDim = 0; iDim < nDim; iDim++) { - solver->GetNodes()->SetSolution(iPoint, iDim, geometry[iZone][INST_0]->nodes->GetCoord(iPoint, iDim)); - solver->GetNodes()->SetSolution(iPoint, iDim+nDim, geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim)); + solver->GetNodes()->SetSolution(iPoint, iDim, geometry[iZone][INST_0][MESH_0]->nodes->GetCoord(iPoint, iDim)); + solver->GetNodes()->SetSolution(iPoint, iDim+nDim, geometry[iZone][INST_0][MESH_0]->GetSensitivity(iPoint, iDim)); } } @@ -865,18 +894,18 @@ void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ***geometry, CCon if(config[iZone]->GetSolid_Wall(iMarker) || (config[iZone]->GetMarker_All_DV(iMarker) == YES )) { - nVertex = geometry[iZone][INST_0]->GetnVertex(iMarker); + nVertex = geometry[iZone][INST_0][MESH_0]->GetnVertex(iMarker); for (iVertex = 0; iVertex < nVertex; iVertex++) { - iPoint = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNode(); - Normal = geometry[iZone][INST_0]->vertex[iMarker][iVertex]->GetNormal(); + iPoint = geometry[iZone][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + Normal = geometry[iZone][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNormal(); Prod = 0.0; Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) { /*--- Retrieve the gradient calculated with discrete adjoint method ---*/ - SensDim = geometry[iZone][INST_0]->GetSensitivity(iPoint, iDim); + SensDim = geometry[iZone][INST_0][MESH_0]->GetSensitivity(iPoint, iDim); /*--- Calculate scalar product for projection onto the normal vector ---*/ @@ -903,7 +932,7 @@ void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ***geometry, CCon /*--- Load the data --- */ - output->Load_Data(geometry[iZone][INST_0], config[iZone], &solver); + output->Load_Data(geometry[iZone][INST_0][MESH_0], config[iZone], &solver); /*--- Set the surface filename ---*/ @@ -920,7 +949,7 @@ void CDiscAdjDeformationDriver::SetSensitivity_Files(CGeometry ***geometry, CCon if (FileFormat[iFile] != OUTPUT_TYPE::RESTART_ASCII && FileFormat[iFile] != OUTPUT_TYPE::RESTART_BINARY && FileFormat[iFile] != OUTPUT_TYPE::CSV) - output->WriteToFile(config[iZone], geometry[iZone][INST_0], FileFormat[iFile]); + output->WriteToFile(config[iZone], geometry[iZone][INST_0][MESH_0], FileFormat[iFile]); } /*--- Free memory ---*/ From 58dd9716b427dcdda705eddd5dea8f1519ac8858 Mon Sep 17 00:00:00 2001 From: patelha57 Date: Sun, 20 Feb 2022 14:37:30 -0800 Subject: [PATCH 019/598] Run clang-format on files --- Common/src/drivers/CDriverBase.cpp | 14 +- SU2_CFD/src/drivers/CDriver.cpp | 7264 ++++++++--------- SU2_CFD/src/python_wrapper_structure.cpp | 1034 +-- SU2_DEF/include/SU2_DEF.hpp | 1 - .../include/drivers/CDeformationDriver.hpp | 134 +- .../drivers/CDiscAdjDeformationDriver.hpp | 2 +- SU2_DEF/src/SU2_DEF.cpp | 79 +- SU2_DEF/src/drivers/CDeformationDriver.cpp | 24 +- .../src/drivers/CDiscAdjDeformationDriver.cpp | 16 +- 9 files changed, 4283 insertions(+), 4285 deletions(-) diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index 4ec2d3b1a27..98d05d65305 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -33,12 +33,12 @@ using namespace std; CDriverBase::CDriverBase(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator): - config_file_name(confFile), - StartTime(0.0), - StopTime(0.0), - UsedTime(0.0), - TimeIter(0), - nZone(val_nZone) +config_file_name(confFile), +StartTime(0.0), +StopTime(0.0), +UsedTime(0.0), +TimeIter(0), +nZone(val_nZone) { } @@ -77,7 +77,7 @@ void CDriverBase::SetContainers_Null() { for (iZone = 0; iZone < nZone; iZone++) { nInst[iZone] = 1; } - + driver_config = nullptr; driver_output = nullptr; } diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 53ec9afc51a..082a777d36c 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -107,3889 +107,3889 @@ #include CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator, bool dummy_geo) : - CDriverBase(confFile, val_nZone, MPICommunicator), StopCalc(false), fsi(false), fem_solver(false), dry_run(dummy_geo) { - - /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ +CDriverBase(confFile, val_nZone, MPICommunicator), StopCalc(false), fsi(false), fem_solver(false), dry_run(dummy_geo) { + + /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ #ifdef HAVE_MPI - #if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE) +#if defined(CODI_REVERSE_TYPE) || defined(CODI_FORWARD_TYPE) SU2_MPI::Init_AMPI(); - #endif #endif - - SU2_MPI::SetComm(MPICommunicator); - - rank = SU2_MPI::GetRank(); - size = SU2_MPI::GetSize(); - - /*--- Start timer to track preprocessing for benchmarking. ---*/ - - StartTime = SU2_MPI::Wtime(); - - /*--- Initialize containers with null --- */ - - SetContainers_Null(); - - /*--- Preprocessing of the config files. ---*/ - - Input_Preprocessing(config_container, driver_config); - - /*--- Retrieve dimension from mesh file ---*/ - - nDim = CConfig::GetnDim(config_container[ZONE_0]->GetMesh_FileName(), - config_container[ZONE_0]->GetMesh_FileFormat()); - - /*--- Output preprocessing ---*/ - - Output_Preprocessing(config_container, driver_config, output_container, driver_output); - - - for (iZone = 0; iZone < nZone; iZone++) { - - /*--- Read the number of instances for each zone ---*/ - - nInst[iZone] = config_container[iZone]->GetnTimeInstances(); - - geometry_container[iZone] = new CGeometry** [nInst[iZone]] (); - iteration_container[iZone] = new CIteration* [nInst[iZone]] (); - solver_container[iZone] = new CSolver*** [nInst[iZone]] (); - integration_container[iZone] = new CIntegration** [nInst[iZone]] (); - numerics_container[iZone] = new CNumerics**** [nInst[iZone]] (); - grid_movement[iZone] = new CVolumetricMovement* [nInst[iZone]] (); - - /*--- Allocate transfer and interpolation container --- */ - - interface_container[iZone] = new CInterface*[nZone] (); - interpolator_container[iZone].resize(nZone); - - for (iInst = 0; iInst < nInst[iZone]; iInst++) { - - config_container[iZone]->SetiInst(iInst); - - /*--- Preprocessing of the geometry for all zones. In this routine, the edge- - based data structure is constructed, i.e. node and cell neighbors are - identified and linked, face areas and volumes of the dual mesh cells are - computed, and the multigrid levels are created using an agglomeration procedure. ---*/ - - Geometrical_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], dry_run); - +#endif + + SU2_MPI::SetComm(MPICommunicator); + + rank = SU2_MPI::GetRank(); + size = SU2_MPI::GetSize(); + + /*--- Start timer to track preprocessing for benchmarking. ---*/ + + StartTime = SU2_MPI::Wtime(); + + /*--- Initialize containers with null --- */ + + SetContainers_Null(); + + /*--- Preprocessing of the config files. ---*/ + + Input_Preprocessing(config_container, driver_config); + + /*--- Retrieve dimension from mesh file ---*/ + + nDim = CConfig::GetnDim(config_container[ZONE_0]->GetMesh_FileName(), + config_container[ZONE_0]->GetMesh_FileFormat()); + + /*--- Output preprocessing ---*/ + + Output_Preprocessing(config_container, driver_config, output_container, driver_output); + + + for (iZone = 0; iZone < nZone; iZone++) { + + /*--- Read the number of instances for each zone ---*/ + + nInst[iZone] = config_container[iZone]->GetnTimeInstances(); + + geometry_container[iZone] = new CGeometry** [nInst[iZone]] (); + iteration_container[iZone] = new CIteration* [nInst[iZone]] (); + solver_container[iZone] = new CSolver*** [nInst[iZone]] (); + integration_container[iZone] = new CIntegration** [nInst[iZone]] (); + numerics_container[iZone] = new CNumerics**** [nInst[iZone]] (); + grid_movement[iZone] = new CVolumetricMovement* [nInst[iZone]] (); + + /*--- Allocate transfer and interpolation container --- */ + + interface_container[iZone] = new CInterface*[nZone] (); + interpolator_container[iZone].resize(nZone); + + for (iInst = 0; iInst < nInst[iZone]; iInst++) { + + config_container[iZone]->SetiInst(iInst); + + /*--- Preprocessing of the geometry for all zones. In this routine, the edge- + based data structure is constructed, i.e. node and cell neighbors are + identified and linked, face areas and volumes of the dual mesh cells are + computed, and the multigrid levels are created using an agglomeration procedure. ---*/ + + Geometrical_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], dry_run); + + } } - } - - /*--- Before we proceed with the zone loop we have to compute the wall distances. + + /*--- Before we proceed with the zone loop we have to compute the wall distances. * This computation depends on all zones at once. ---*/ - if (rank == MASTER_NODE) - cout << "Computing wall distances." << endl; - - CGeometry::ComputeWallDistance(config_container, geometry_container); - - for (iZone = 0; iZone < nZone; iZone++) { - - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - - /*--- Definition of the solver class: solver_container[#ZONES][#INSTANCES][#MG_GRIDS][#EQ_SYSTEMS]. - The solver classes are specific to a particular set of governing equations, - and they contain the subroutines with instructions for computing each spatial - term of the PDE, i.e. loops over the edges to compute convective and viscous - fluxes, loops over the nodes to compute source terms, and routines for - imposing various boundary condition type for the PDE. ---*/ - - Solver_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], solver_container[iZone][iInst]); - - /*--- Definition of the numerical method class: - numerics_container[#ZONES][#INSTANCES][#MG_GRIDS][#EQ_SYSTEMS][#EQ_TERMS]. - The numerics class contains the implementation of the numerical methods for - evaluating convective or viscous fluxes between any two nodes in the edge-based - data structure (centered, upwind, galerkin), as well as any source terms - (piecewise constant reconstruction) evaluated in each dual mesh volume. ---*/ - - Numerics_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], - solver_container[iZone][iInst], numerics_container[iZone][iInst]); - - /*--- Definition of the integration class: integration_container[#ZONES][#INSTANCES][#EQ_SYSTEMS]. - The integration class orchestrates the execution of the spatial integration - subroutines contained in the solver class (including multigrid) for computing - the residual at each node, R(U) and then integrates the equations to a - steady state or time-accurately. ---*/ - - Integration_Preprocessing(config_container[iZone], solver_container[iZone][iInst][MESH_0], - integration_container[iZone][iInst]); - - /*--- Instantiate the type of physics iteration to be executed within each zone. For - example, one can execute the same physics across multiple zones (mixing plane), - different physics in different zones (fluid-structure interaction), or couple multiple - systems tightly within a single zone by creating a new iteration class (e.g., RANS). ---*/ - - Iteration_Preprocessing(config_container[iZone], iteration_container[iZone][iInst]); - - /*--- Dynamic mesh processing. ---*/ - - DynamicMesh_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], solver_container[iZone][iInst], - iteration_container[iZone][iInst], grid_movement[iZone][iInst], surface_movement[iZone]); - /*--- Static mesh processing. ---*/ - - StaticMesh_Preprocessing(config_container[iZone], geometry_container[iZone][iInst]); - - } - - } - - /*! --- Compute the wall distance again to correctly compute the derivatives if we are running direct diff mode --- */ - if (driver_config->GetDirectDiff() == D_DESIGN){ - CGeometry::ComputeWallDistance(config_container, geometry_container); - } - - /*--- Definition of the interface and transfer conditions between different zones. ---*/ - - if (nZone > 1) { if (rank == MASTER_NODE) - cout << endl <<"------------------- Multizone Interface Preprocessing -------------------" << endl; - - Interface_Preprocessing(config_container, solver_container, geometry_container, - interface_types, interface_container, interpolator_container); - } - - if (fsi) { + cout << "Computing wall distances." << endl; + + CGeometry::ComputeWallDistance(config_container, geometry_container); + for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - Solver_Restart(solver_container[iZone][iInst], geometry_container[iZone][iInst], - config_container[iZone], true); - } + + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + + /*--- Definition of the solver class: solver_container[#ZONES][#INSTANCES][#MG_GRIDS][#EQ_SYSTEMS]. + The solver classes are specific to a particular set of governing equations, + and they contain the subroutines with instructions for computing each spatial + term of the PDE, i.e. loops over the edges to compute convective and viscous + fluxes, loops over the nodes to compute source terms, and routines for + imposing various boundary condition type for the PDE. ---*/ + + Solver_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], solver_container[iZone][iInst]); + + /*--- Definition of the numerical method class: + numerics_container[#ZONES][#INSTANCES][#MG_GRIDS][#EQ_SYSTEMS][#EQ_TERMS]. + The numerics class contains the implementation of the numerical methods for + evaluating convective or viscous fluxes between any two nodes in the edge-based + data structure (centered, upwind, galerkin), as well as any source terms + (piecewise constant reconstruction) evaluated in each dual mesh volume. ---*/ + + Numerics_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], + solver_container[iZone][iInst], numerics_container[iZone][iInst]); + + /*--- Definition of the integration class: integration_container[#ZONES][#INSTANCES][#EQ_SYSTEMS]. + The integration class orchestrates the execution of the spatial integration + subroutines contained in the solver class (including multigrid) for computing + the residual at each node, R(U) and then integrates the equations to a + steady state or time-accurately. ---*/ + + Integration_Preprocessing(config_container[iZone], solver_container[iZone][iInst][MESH_0], + integration_container[iZone][iInst]); + + /*--- Instantiate the type of physics iteration to be executed within each zone. For + example, one can execute the same physics across multiple zones (mixing plane), + different physics in different zones (fluid-structure interaction), or couple multiple + systems tightly within a single zone by creating a new iteration class (e.g., RANS). ---*/ + + Iteration_Preprocessing(config_container[iZone], iteration_container[iZone][iInst]); + + /*--- Dynamic mesh processing. ---*/ + + DynamicMesh_Preprocessing(config_container[iZone], geometry_container[iZone][iInst], solver_container[iZone][iInst], + iteration_container[iZone][iInst], grid_movement[iZone][iInst], surface_movement[iZone]); + /*--- Static mesh processing. ---*/ + + StaticMesh_Preprocessing(config_container[iZone], geometry_container[iZone][iInst]); + + } + } - } - - if (config_container[ZONE_0]->GetBoolTurbomachinery()){ - if (rank == MASTER_NODE) - cout << endl <<"---------------------- Turbomachinery Preprocessing ---------------------" << endl; - - Turbomachinery_Preprocessing(config_container, geometry_container, solver_container, interface_container); - } - - - PythonInterface_Preprocessing(config_container, geometry_container, solver_container); - - - /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ - - StopTime = SU2_MPI::Wtime(); - - /*--- Compute/print the total time for performance benchmarking. ---*/ - - UsedTime = StopTime-StartTime; - UsedTimePreproc = UsedTime; - UsedTimeCompute = 0.0; - UsedTimeOutput = 0.0; - IterCount = 0; - OutputCount = 0; - MDOFs = 0.0; - MDOFsDomain = 0.0; - Mpoints = 0.0; - MpointsDomain = 0.0; - for (iZone = 0; iZone < nZone; iZone++) { - Mpoints += geometry_container[iZone][INST_0][MESH_0]->GetGlobal_nPoint()/(1.0e6); - MpointsDomain += geometry_container[iZone][INST_0][MESH_0]->GetGlobal_nPointDomain()/(1.0e6); - MDOFs += DOFsPerPoint*geometry_container[iZone][INST_0][MESH_0]->GetGlobal_nPoint()/(1.0e6); - MDOFsDomain += DOFsPerPoint*geometry_container[iZone][INST_0][MESH_0]->GetGlobal_nPointDomain()/(1.0e6); - } - - /*--- Reset timer for compute/output performance benchmarking. ---*/ - - StopTime = SU2_MPI::Wtime(); - - /*--- Compute/print the total time for performance benchmarking. ---*/ - - UsedTime = StopTime-StartTime; - UsedTimePreproc = UsedTime; - - /*--- Reset timer for compute performance benchmarking. ---*/ - - StartTime = SU2_MPI::Wtime(); - + + /*! --- Compute the wall distance again to correctly compute the derivatives if we are running direct diff mode --- */ + if (driver_config->GetDirectDiff() == D_DESIGN){ + CGeometry::ComputeWallDistance(config_container, geometry_container); + } + + /*--- Definition of the interface and transfer conditions between different zones. ---*/ + + if (nZone > 1) { + if (rank == MASTER_NODE) + cout << endl <<"------------------- Multizone Interface Preprocessing -------------------" << endl; + + Interface_Preprocessing(config_container, solver_container, geometry_container, + interface_types, interface_container, interpolator_container); + } + + if (fsi) { + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + Solver_Restart(solver_container[iZone][iInst], geometry_container[iZone][iInst], + config_container[iZone], true); + } + } + } + + if (config_container[ZONE_0]->GetBoolTurbomachinery()){ + if (rank == MASTER_NODE) + cout << endl <<"---------------------- Turbomachinery Preprocessing ---------------------" << endl; + + Turbomachinery_Preprocessing(config_container, geometry_container, solver_container, interface_container); + } + + + PythonInterface_Preprocessing(config_container, geometry_container, solver_container); + + + /*--- Preprocessing time is reported now, but not included in the next compute portion. ---*/ + + StopTime = SU2_MPI::Wtime(); + + /*--- Compute/print the total time for performance benchmarking. ---*/ + + UsedTime = StopTime-StartTime; + UsedTimePreproc = UsedTime; + UsedTimeCompute = 0.0; + UsedTimeOutput = 0.0; + IterCount = 0; + OutputCount = 0; + MDOFs = 0.0; + MDOFsDomain = 0.0; + Mpoints = 0.0; + MpointsDomain = 0.0; + for (iZone = 0; iZone < nZone; iZone++) { + Mpoints += geometry_container[iZone][INST_0][MESH_0]->GetGlobal_nPoint()/(1.0e6); + MpointsDomain += geometry_container[iZone][INST_0][MESH_0]->GetGlobal_nPointDomain()/(1.0e6); + MDOFs += DOFsPerPoint*geometry_container[iZone][INST_0][MESH_0]->GetGlobal_nPoint()/(1.0e6); + MDOFsDomain += DOFsPerPoint*geometry_container[iZone][INST_0][MESH_0]->GetGlobal_nPointDomain()/(1.0e6); + } + + /*--- Reset timer for compute/output performance benchmarking. ---*/ + + StopTime = SU2_MPI::Wtime(); + + /*--- Compute/print the total time for performance benchmarking. ---*/ + + UsedTime = StopTime-StartTime; + UsedTimePreproc = UsedTime; + + /*--- Reset timer for compute performance benchmarking. ---*/ + + StartTime = SU2_MPI::Wtime(); + } void CDriver::SetContainers_Null(){ - - /*--- Create pointers to all of the classes that may be used throughout - the SU2_CFD code. In general, the pointers are instantiated down a - hierarchy over all zones, multigrid levels, equation sets, and equation - terms as described in the comments below. ---*/ - - ConvHist_file = nullptr; - iteration_container = nullptr; - output_container = nullptr; - integration_container = nullptr; - geometry_container = nullptr; - solver_container = nullptr; - numerics_container = nullptr; - config_container = nullptr; - surface_movement = nullptr; - grid_movement = nullptr; - FFDBox = nullptr; - interface_container = nullptr; - interface_types = nullptr; - nInst = nullptr; - - /*--- Definition and of the containers for all possible zones. ---*/ - - iteration_container = new CIteration**[nZone] (); - solver_container = new CSolver****[nZone] (); - integration_container = new CIntegration***[nZone] (); - numerics_container = new CNumerics*****[nZone] (); - config_container = new CConfig*[nZone] (); - geometry_container = new CGeometry***[nZone] (); - surface_movement = new CSurfaceMovement*[nZone] (); - grid_movement = new CVolumetricMovement**[nZone] (); - FFDBox = new CFreeFormDefBox**[nZone] (); - interpolator_container.resize(nZone); - interface_container = new CInterface**[nZone] (); - interface_types = new unsigned short*[nZone] (); - output_container = new COutput*[nZone] (); - nInst = new unsigned short[nZone] (); // TODO: remove (moved to base class) - driver_config = nullptr; - driver_output = nullptr; - - for (iZone = 0; iZone < nZone; iZone++) { - interface_types[iZone] = new unsigned short[nZone]; - nInst[iZone] = 1; - } - - strcpy(runtime_file_name, "runtime.dat"); - + + /*--- Create pointers to all of the classes that may be used throughout + the SU2_CFD code. In general, the pointers are instantiated down a + hierarchy over all zones, multigrid levels, equation sets, and equation + terms as described in the comments below. ---*/ + + ConvHist_file = nullptr; + iteration_container = nullptr; + output_container = nullptr; + integration_container = nullptr; + geometry_container = nullptr; + solver_container = nullptr; + numerics_container = nullptr; + config_container = nullptr; + surface_movement = nullptr; + grid_movement = nullptr; + FFDBox = nullptr; + interface_container = nullptr; + interface_types = nullptr; + nInst = nullptr; + + /*--- Definition and of the containers for all possible zones. ---*/ + + iteration_container = new CIteration**[nZone] (); + solver_container = new CSolver****[nZone] (); + integration_container = new CIntegration***[nZone] (); + numerics_container = new CNumerics*****[nZone] (); + config_container = new CConfig*[nZone] (); + geometry_container = new CGeometry***[nZone] (); + surface_movement = new CSurfaceMovement*[nZone] (); + grid_movement = new CVolumetricMovement**[nZone] (); + FFDBox = new CFreeFormDefBox**[nZone] (); + interpolator_container.resize(nZone); + interface_container = new CInterface**[nZone] (); + interface_types = new unsigned short*[nZone] (); + output_container = new COutput*[nZone] (); + nInst = new unsigned short[nZone] (); // TODO: remove (moved to base class) + driver_config = nullptr; + driver_output = nullptr; + + for (iZone = 0; iZone < nZone; iZone++) { + interface_types[iZone] = new unsigned short[nZone]; + nInst[iZone] = 1; + } + + strcpy(runtime_file_name, "runtime.dat"); + } void CDriver::Postprocessing() { - - const bool wrt_perf = config_container[ZONE_0]->GetWrt_Performance(); - + + const bool wrt_perf = config_container[ZONE_0]->GetWrt_Performance(); + /*--- Output some information to the console. ---*/ - - if (rank == MASTER_NODE) { - - /*--- Print out the number of non-physical points and reconstructions ---*/ - - if (config_container[ZONE_0]->GetNonphysical_Points() > 0) - cout << "Warning: there are " << config_container[ZONE_0]->GetNonphysical_Points() << " non-physical points in the solution." << endl; - if (config_container[ZONE_0]->GetNonphysical_Reconstr() > 0) - cout << "Warning: " << config_container[ZONE_0]->GetNonphysical_Reconstr() << " reconstructed states for upwinding are non-physical." << endl; - } - - if (rank == MASTER_NODE) - cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; - - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - Numerics_Postprocessing(numerics_container[iZone], solver_container[iZone][iInst], - geometry_container[iZone][iInst], config_container[iZone], iInst); - } - delete [] numerics_container[iZone]; - } - delete [] numerics_container; - if (rank == MASTER_NODE) cout << "Deleted CNumerics container." << endl; - - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - Integration_Postprocessing(integration_container[iZone], - geometry_container[iZone][iInst], - config_container[iZone], - iInst); - } - delete [] integration_container[iZone]; - } - delete [] integration_container; - if (rank == MASTER_NODE) cout << "Deleted CIntegration container." << endl; - - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - Solver_Postprocessing(solver_container[iZone], - geometry_container[iZone][iInst], - config_container[iZone], - iInst); - } - delete [] solver_container[iZone]; - } - delete [] solver_container; - if (rank == MASTER_NODE) cout << "Deleted CSolver container." << endl; - - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++) - delete iteration_container[iZone][iInst]; - delete [] iteration_container[iZone]; - } - delete [] iteration_container; - if (rank == MASTER_NODE) cout << "Deleted CIteration container." << endl; - - if (interface_container != nullptr) { + + if (rank == MASTER_NODE) { + + /*--- Print out the number of non-physical points and reconstructions ---*/ + + if (config_container[ZONE_0]->GetNonphysical_Points() > 0) + cout << "Warning: there are " << config_container[ZONE_0]->GetNonphysical_Points() << " non-physical points in the solution." << endl; + if (config_container[ZONE_0]->GetNonphysical_Reconstr() > 0) + cout << "Warning: " << config_container[ZONE_0]->GetNonphysical_Reconstr() << " reconstructed states for upwinding are non-physical." << endl; + } + + if (rank == MASTER_NODE) + cout << endl <<"------------------------- Solver Postprocessing -------------------------" << endl; + for (iZone = 0; iZone < nZone; iZone++) { - if (interface_container[iZone] != nullptr) { - for (unsigned short jZone = 0; jZone < nZone; jZone++) - delete interface_container[iZone][jZone]; - delete [] interface_container[iZone]; - } + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + Numerics_Postprocessing(numerics_container[iZone], solver_container[iZone][iInst], + geometry_container[iZone][iInst], config_container[iZone], iInst); + } + delete [] numerics_container[iZone]; } - delete [] interface_container; - if (rank == MASTER_NODE) cout << "Deleted CInterface container." << endl; - } - - if (interface_types != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) - delete [] interface_types[iZone]; - delete [] interface_types; - } - - for (iZone = 0; iZone < nZone; iZone++) { - if (geometry_container[iZone] != nullptr) { - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - for (unsigned short iMGlevel = 0; iMGlevel < config_container[iZone]->GetnMGLevels()+1; iMGlevel++) - delete geometry_container[iZone][iInst][iMGlevel]; - delete [] geometry_container[iZone][iInst]; - } - delete [] geometry_container[iZone]; - } - } - delete [] geometry_container; - if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; - - for (iZone = 0; iZone < nZone; iZone++) { - delete [] FFDBox[iZone]; - } - delete [] FFDBox; - if (rank == MASTER_NODE) cout << "Deleted CFreeFormDefBox class." << endl; - - for (iZone = 0; iZone < nZone; iZone++) { - delete surface_movement[iZone]; - } - delete [] surface_movement; - if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; - - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++) - delete grid_movement[iZone][iInst]; - delete [] grid_movement[iZone]; - } - delete [] grid_movement; - if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; - - /*--- Output profiling information ---*/ - // Note that for now this is called only by a single thread, but all - // necessary variables have been made thread private for safety (tick/tock)!! - - config_container[ZONE_0]->SetProfilingCSV(); - config_container[ZONE_0]->GEMMProfilingCSV(); - - /*--- Deallocate config container ---*/ - if (config_container!= nullptr) { - for (iZone = 0; iZone < nZone; iZone++) - delete config_container[iZone]; - delete [] config_container; - } - delete driver_config; - if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; - - delete [] nInst; - if (rank == MASTER_NODE) cout << "Deleted nInst container." << endl; - - /*--- Deallocate output container ---*/ - - if (output_container!= nullptr) { - for (iZone = 0; iZone < nZone; iZone++) - delete output_container[iZone]; - delete [] output_container; - } - - delete driver_output; - - if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; - - if (rank == MASTER_NODE) cout << "-------------------------------------------------------------------------" << endl; - - - /*--- Stop the timer and output the final performance summary. ---*/ - - StopTime = SU2_MPI::Wtime(); - - UsedTime = StopTime-StartTime; - UsedTimeCompute += UsedTime; - - if ((rank == MASTER_NODE) && (wrt_perf)) { - su2double TotalTime = UsedTimePreproc + UsedTimeCompute + UsedTimeOutput; - cout.precision(6); - cout << endl << endl <<"-------------------------- Performance Summary --------------------------" << endl; - cout << "Simulation totals:" << endl; - cout << setw(25) << "Wall-clock time (hrs):" << setw(12) << (TotalTime)/(60.0*60.0) << " | "; - cout << setw(20) << "Core-hrs:" << setw(12) << size*TotalTime/(60.0*60.0) << endl; - cout << setw(25) << "Cores:" << setw(12) << size << " | "; - cout << setw(20) << "DOFs/point:" << setw(12) << DOFsPerPoint << endl; - cout << setw(25) << "Points/core:" << setw(12) << 1.0e6*MpointsDomain/size << " | "; - cout << setw(20) << "Ghost points/core:" << setw(12) << 1.0e6*(Mpoints-MpointsDomain)/size << endl; - cout << setw(25) << "Ghost/Owned Point Ratio:" << setw(12) << (Mpoints-MpointsDomain)/MpointsDomain << " | " << endl; - cout << endl; - cout << "Preprocessing phase:" << endl; - cout << setw(25) << "Preproc. Time (s):" << setw(12)<< UsedTimePreproc << " | "; - cout << setw(20) << "Preproc. Time (%):" << setw(12)<< ((UsedTimePreproc * 100.0) / (TotalTime)) << endl; - cout << endl; - cout << "Compute phase:" << endl; - cout << setw(25) << "Compute Time (s):" << setw(12)<< UsedTimeCompute << " | "; - cout << setw(20) << "Compute Time (%):" << setw(12)<< ((UsedTimeCompute * 100.0) / (TotalTime)) << endl; - cout << setw(25) << "Iteration count:" << setw(12)<< IterCount << " | "; - if (IterCount != 0) { - cout << setw(20) << "Avg. s/iter:" << setw(12)<< UsedTimeCompute/IterCount << endl; - cout << setw(25) << "Core-s/iter/Mpoints:" << setw(12)<< size*UsedTimeCompute/IterCount/Mpoints << " | "; - cout << setw(20) << "Mpoints/s:" << setw(12)<< Mpoints*IterCount/UsedTimeCompute << endl; - } else cout << endl; - cout << endl; - cout << "Output phase:" << endl; - cout << setw(25) << "Output Time (s):" << setw(12)<< UsedTimeOutput << " | "; - cout << setw(20) << "Output Time (%):" << setw(12)<< ((UsedTimeOutput * 100.0) / (TotalTime)) << endl; - cout << setw(25) << "Output count:" << setw(12)<< OutputCount << " | "; - if (OutputCount != 0) { - cout << setw(20)<< "Avg. s/output:" << setw(12)<< UsedTimeOutput/OutputCount << endl; - if (BandwidthSum > 0) { - cout << setw(25)<< "Restart Aggr. BW (MB/s):" << setw(12)<< BandwidthSum/OutputCount << " | "; - cout << setw(20)<< "MB/s/core:" << setw(12)<< BandwidthSum/OutputCount/size << endl; - } - } else cout << endl; - cout << "-------------------------------------------------------------------------" << endl; - cout << endl; - } - - /*--- Exit the solver cleanly ---*/ - - if (rank == MASTER_NODE) - cout << endl <<"------------------------- Exit Success (SU2_CFD) ------------------------" << endl << endl; - -} - - -void CDriver::Input_Preprocessing(CConfig **&config, CConfig *&driver_config) { - - char zone_file_name[MAX_STRING_SIZE]; - - /*--- Initialize the configuration of the driver ---*/ - - driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_CFD, false); - - for (iZone = 0; iZone < nZone; iZone++) { - - if (rank == MASTER_NODE){ - cout << endl << "Parsing config file for zone " << iZone << endl; + delete [] numerics_container; + if (rank == MASTER_NODE) cout << "Deleted CNumerics container." << endl; + + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + Integration_Postprocessing(integration_container[iZone], + geometry_container[iZone][iInst], + config_container[iZone], + iInst); + } + delete [] integration_container[iZone]; } - /*--- Definition of the configuration option class for all zones. In this - constructor, the input configuration file is parsed and all options are - read and stored. ---*/ - - if (driver_config->GetnConfigFiles() > 0){ - - strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); - config[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_CFD, iZone, nZone, true); + delete [] integration_container; + if (rank == MASTER_NODE) cout << "Deleted CIntegration container." << endl; + + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + Solver_Postprocessing(solver_container[iZone], + geometry_container[iZone][iInst], + config_container[iZone], + iInst); + } + delete [] solver_container[iZone]; } - else{ - config[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_CFD, iZone, nZone, true); + delete [] solver_container; + if (rank == MASTER_NODE) cout << "Deleted CSolver container." << endl; + + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < nInst[iZone]; iInst++) + delete iteration_container[iZone][iInst]; + delete [] iteration_container[iZone]; + } + delete [] iteration_container; + if (rank == MASTER_NODE) cout << "Deleted CIteration container." << endl; + + if (interface_container != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) { + if (interface_container[iZone] != nullptr) { + for (unsigned short jZone = 0; jZone < nZone; jZone++) + delete interface_container[iZone][jZone]; + delete [] interface_container[iZone]; + } + } + delete [] interface_container; + if (rank == MASTER_NODE) cout << "Deleted CInterface container." << endl; } - - /*--- Set the MPI communicator ---*/ - - config[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); - } - - - /*--- Set the multizone part of the problem. ---*/ - if (driver_config->GetMultizone_Problem()){ + + if (interface_types != nullptr) { + for (iZone = 0; iZone < nZone; iZone++) + delete [] interface_types[iZone]; + delete [] interface_types; + } + for (iZone = 0; iZone < nZone; iZone++) { - /*--- Set the interface markers for multizone ---*/ - config_container[iZone]->SetMultizone(driver_config, config_container); + if (geometry_container[iZone] != nullptr) { + for (iInst = 0; iInst < nInst[iZone]; iInst++){ + for (unsigned short iMGlevel = 0; iMGlevel < config_container[iZone]->GetnMGLevels()+1; iMGlevel++) + delete geometry_container[iZone][iInst][iMGlevel]; + delete [] geometry_container[iZone][iInst]; + } + delete [] geometry_container[iZone]; + } } - } - - /*--- Determine whether or not the FEM solver is used, which decides the type of - * geometry classes that are instantiated. Only adapted for single-zone problems ---*/ - - fem_solver = config_container[ZONE_0]->GetFEMSolver(); - - fsi = config_container[ZONE_0]->GetFSI_Simulation(); -} - -void CDriver::Geometrical_Preprocessing(CConfig* config, CGeometry **&geometry, bool dummy){ - - if (!dummy){ - if (rank == MASTER_NODE) - cout << endl <<"------------------- Geometry Preprocessing ( Zone " << config->GetiZone() <<" ) -------------------" << endl; - - if( fem_solver ) { - switch( config->GetKind_FEM_Flow() ) { - case DG: { - Geometrical_Preprocessing_DGFEM(config, geometry); - break; - } - } + delete [] geometry_container; + if (rank == MASTER_NODE) cout << "Deleted CGeometry container." << endl; + + for (iZone = 0; iZone < nZone; iZone++) { + delete [] FFDBox[iZone]; + } + delete [] FFDBox; + if (rank == MASTER_NODE) cout << "Deleted CFreeFormDefBox class." << endl; + + for (iZone = 0; iZone < nZone; iZone++) { + delete surface_movement[iZone]; } - else { - Geometrical_Preprocessing_FVM(config, geometry); + delete [] surface_movement; + if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; + + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < nInst[iZone]; iInst++) + delete grid_movement[iZone][iInst]; + delete [] grid_movement[iZone]; + } + delete [] grid_movement; + if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; + + /*--- Output profiling information ---*/ + // Note that for now this is called only by a single thread, but all + // necessary variables have been made thread private for safety (tick/tock)!! + + config_container[ZONE_0]->SetProfilingCSV(); + config_container[ZONE_0]->GEMMProfilingCSV(); + + /*--- Deallocate config container ---*/ + if (config_container!= nullptr) { + for (iZone = 0; iZone < nZone; iZone++) + delete config_container[iZone]; + delete [] config_container; + } + delete driver_config; + if (rank == MASTER_NODE) cout << "Deleted CConfig container." << endl; + + delete [] nInst; + if (rank == MASTER_NODE) cout << "Deleted nInst container." << endl; + + /*--- Deallocate output container ---*/ + + if (output_container!= nullptr) { + for (iZone = 0; iZone < nZone; iZone++) + delete output_container[iZone]; + delete [] output_container; + } + + delete driver_output; + + if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; + + if (rank == MASTER_NODE) cout << "-------------------------------------------------------------------------" << endl; + + + /*--- Stop the timer and output the final performance summary. ---*/ + + StopTime = SU2_MPI::Wtime(); + + UsedTime = StopTime-StartTime; + UsedTimeCompute += UsedTime; + + if ((rank == MASTER_NODE) && (wrt_perf)) { + su2double TotalTime = UsedTimePreproc + UsedTimeCompute + UsedTimeOutput; + cout.precision(6); + cout << endl << endl <<"-------------------------- Performance Summary --------------------------" << endl; + cout << "Simulation totals:" << endl; + cout << setw(25) << "Wall-clock time (hrs):" << setw(12) << (TotalTime)/(60.0*60.0) << " | "; + cout << setw(20) << "Core-hrs:" << setw(12) << size*TotalTime/(60.0*60.0) << endl; + cout << setw(25) << "Cores:" << setw(12) << size << " | "; + cout << setw(20) << "DOFs/point:" << setw(12) << DOFsPerPoint << endl; + cout << setw(25) << "Points/core:" << setw(12) << 1.0e6*MpointsDomain/size << " | "; + cout << setw(20) << "Ghost points/core:" << setw(12) << 1.0e6*(Mpoints-MpointsDomain)/size << endl; + cout << setw(25) << "Ghost/Owned Point Ratio:" << setw(12) << (Mpoints-MpointsDomain)/MpointsDomain << " | " << endl; + cout << endl; + cout << "Preprocessing phase:" << endl; + cout << setw(25) << "Preproc. Time (s):" << setw(12)<< UsedTimePreproc << " | "; + cout << setw(20) << "Preproc. Time (%):" << setw(12)<< ((UsedTimePreproc * 100.0) / (TotalTime)) << endl; + cout << endl; + cout << "Compute phase:" << endl; + cout << setw(25) << "Compute Time (s):" << setw(12)<< UsedTimeCompute << " | "; + cout << setw(20) << "Compute Time (%):" << setw(12)<< ((UsedTimeCompute * 100.0) / (TotalTime)) << endl; + cout << setw(25) << "Iteration count:" << setw(12)<< IterCount << " | "; + if (IterCount != 0) { + cout << setw(20) << "Avg. s/iter:" << setw(12)<< UsedTimeCompute/IterCount << endl; + cout << setw(25) << "Core-s/iter/Mpoints:" << setw(12)<< size*UsedTimeCompute/IterCount/Mpoints << " | "; + cout << setw(20) << "Mpoints/s:" << setw(12)<< Mpoints*IterCount/UsedTimeCompute << endl; + } else cout << endl; + cout << endl; + cout << "Output phase:" << endl; + cout << setw(25) << "Output Time (s):" << setw(12)<< UsedTimeOutput << " | "; + cout << setw(20) << "Output Time (%):" << setw(12)<< ((UsedTimeOutput * 100.0) / (TotalTime)) << endl; + cout << setw(25) << "Output count:" << setw(12)<< OutputCount << " | "; + if (OutputCount != 0) { + cout << setw(20)<< "Avg. s/output:" << setw(12)<< UsedTimeOutput/OutputCount << endl; + if (BandwidthSum > 0) { + cout << setw(25)<< "Restart Aggr. BW (MB/s):" << setw(12)<< BandwidthSum/OutputCount << " | "; + cout << setw(20)<< "MB/s/core:" << setw(12)<< BandwidthSum/OutputCount/size << endl; + } + } else cout << endl; + cout << "-------------------------------------------------------------------------" << endl; + cout << endl; } - } else { + + /*--- Exit the solver cleanly ---*/ + if (rank == MASTER_NODE) - cout << endl <<"-------------------------- Using Dummy Geometry -------------------------" << endl; + cout << endl <<"------------------------- Exit Success (SU2_CFD) ------------------------" << endl << endl; + +} - unsigned short iMGlevel; - geometry = new CGeometry*[config->GetnMGLevels()+1] (); +void CDriver::Input_Preprocessing(CConfig **&config, CConfig *&driver_config) { + + char zone_file_name[MAX_STRING_SIZE]; + + /*--- Initialize the configuration of the driver ---*/ + + driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_CFD, false); + + for (iZone = 0; iZone < nZone; iZone++) { + + if (rank == MASTER_NODE){ + cout << endl << "Parsing config file for zone " << iZone << endl; + } + /*--- Definition of the configuration option class for all zones. In this + constructor, the input configuration file is parsed and all options are + read and stored. ---*/ + + if (driver_config->GetnConfigFiles() > 0){ + + strcpy(zone_file_name, driver_config->GetConfigFilename(iZone).c_str()); + config[iZone] = new CConfig(driver_config, zone_file_name, SU2_COMPONENT::SU2_CFD, iZone, nZone, true); + } + else{ + config[iZone] = new CConfig(driver_config, config_file_name, SU2_COMPONENT::SU2_CFD, iZone, nZone, true); + } + + /*--- Set the MPI communicator ---*/ + + config[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); + } + + + /*--- Set the multizone part of the problem. ---*/ + if (driver_config->GetMultizone_Problem()){ + for (iZone = 0; iZone < nZone; iZone++) { + /*--- Set the interface markers for multizone ---*/ + config_container[iZone]->SetMultizone(driver_config, config_container); + } + } + + /*--- Determine whether or not the FEM solver is used, which decides the type of + * geometry classes that are instantiated. Only adapted for single-zone problems ---*/ + + fem_solver = config_container[ZONE_0]->GetFEMSolver(); + + fsi = config_container[ZONE_0]->GetFSI_Simulation(); +} - if (!fem_solver){ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - geometry[iMGlevel] = new CDummyGeometry(config); - } +void CDriver::Geometrical_Preprocessing(CConfig* config, CGeometry **&geometry, bool dummy){ + + if (!dummy){ + if (rank == MASTER_NODE) + cout << endl <<"------------------- Geometry Preprocessing ( Zone " << config->GetiZone() <<" ) -------------------" << endl; + + if( fem_solver ) { + switch( config->GetKind_FEM_Flow() ) { + case DG: { + Geometrical_Preprocessing_DGFEM(config, geometry); + break; + } + } + } + else { + Geometrical_Preprocessing_FVM(config, geometry); + } } else { - geometry[MESH_0] = new CDummyMeshFEM_DG(config); + if (rank == MASTER_NODE) + cout << endl <<"-------------------------- Using Dummy Geometry -------------------------" << endl; + + unsigned short iMGlevel; + + geometry = new CGeometry*[config->GetnMGLevels()+1] (); + + if (!fem_solver){ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + geometry[iMGlevel] = new CDummyGeometry(config); + } + } else { + geometry[MESH_0] = new CDummyMeshFEM_DG(config); + } + + nDim = geometry[MESH_0]->GetnDim(); } - - nDim = geometry[MESH_0]->GetnDim(); - } - - /*--- Computation of positive surface area in the z-plane which is used for + + /*--- Computation of positive surface area in the z-plane which is used for the calculation of force coefficient (non-dimensionalization). ---*/ - - geometry[MESH_0]->SetPositive_ZArea(config); - - /*--- Set the actuator disk boundary conditions, if necessary. ---*/ - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - geometry[iMesh]->MatchActuator_Disk(config); - } - - /*--- If we have any periodic markers in this calculation, we must - match the periodic points found on both sides of the periodic BC. - Note that the current implementation requires a 1-to-1 matching of - periodic points on the pair of periodic faces after the translation - or rotation is taken into account. ---*/ - - if ((config->GetnMarker_Periodic() != 0) && !fem_solver) { + + geometry[MESH_0]->SetPositive_ZArea(config); + + /*--- Set the actuator disk boundary conditions, if necessary. ---*/ + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - - /*--- Note that we loop over pairs of periodic markers individually - so that repeated nodes on adjacent periodic faces are properly - accounted for in multiple places. ---*/ - - for (unsigned short iPeriodic = 1; iPeriodic <= config->GetnMarker_Periodic()/2; iPeriodic++) { - geometry[iMesh]->MatchPeriodic(config, iPeriodic); - } - - /*--- For Streamwise Periodic flow, find a unique reference node on the dedicated inlet marker. ---*/ - if (config->GetKind_Streamwise_Periodic() != ENUM_STREAMWISE_PERIODIC::NONE) - geometry[iMesh]->FindUniqueNode_PeriodicBound(config); - - /*--- Initialize the communication framework for the periodic BCs. ---*/ - geometry[iMesh]->PreprocessPeriodicComms(geometry[iMesh], config); - - } - } - - /*--- If activated by the compile directive, perform a partition analysis. ---*/ -#if PARTITION - if (!dummy){ - if( fem_solver ) Partition_Analysis_FEM(geometry[MESH_0], config); - else Partition_Analysis(geometry[MESH_0], config); - } -#endif - - /*--- Check if Euler & Symmetry markers are straight/plane. This information - is used in the Euler & Symmetry boundary routines. ---*/ - if((config_container[iZone]->GetnMarker_Euler() != 0 || - config_container[iZone]->GetnMarker_SymWall() != 0) && - !fem_solver) { - - if (rank == MASTER_NODE) - cout << "Checking if Euler & Symmetry markers are straight/plane:" << endl; - - for (iMesh = 0; iMesh <= config_container[iZone]->GetnMGLevels(); iMesh++) - geometry_container[iZone][iInst][iMesh]->ComputeSurf_Straightness(config_container[iZone], (iMesh==MESH_0) ); - - } - -} - -void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geometry) { - - unsigned short iZone = config->GetiZone(), iMGlevel; - unsigned short requestedMGlevels = config->GetnMGLevels(); - const bool fea = config->GetStructuralProblem(); - - /*--- Definition of the geometry class to store the primal grid in the partitioning process. - * All ranks process the grid and call ParMETIS for partitioning ---*/ - - CGeometry *geometry_aux = new CPhysicalGeometry(config, iZone, nZone); - - /*--- Set the dimension --- */ - - nDim = geometry_aux->GetnDim(); - - /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - - geometry_aux->SetColorGrid_Parallel(config); - - /*--- Allocate the memory of the current domain, and divide the grid - between the ranks. ---*/ - - geometry = new CGeometry *[config->GetnMGLevels()+1] (); - - /*--- Build the grid data structures using the ParMETIS coloring. ---*/ - - geometry[MESH_0] = new CPhysicalGeometry(geometry_aux, config); - - /*--- Deallocate the memory of geometry_aux and solver_aux ---*/ - - delete geometry_aux; - - /*--- Add the Send/Receive boundaries ---*/ - geometry[MESH_0]->SetSendReceive(config); - - /*--- Add the Send/Receive boundaries ---*/ - geometry[MESH_0]->SetBoundaries(config); - - /*--- Compute elements surrounding points, points surrounding points ---*/ - - if (rank == MASTER_NODE) cout << "Setting point connectivity." << endl; - geometry[MESH_0]->SetPoint_Connectivity(); - - /*--- Renumbering points using Reverse Cuthill McKee ordering ---*/ - - if (rank == MASTER_NODE) cout << "Renumbering points (Reverse Cuthill McKee Ordering)." << endl; - geometry[MESH_0]->SetRCM_Ordering(config); - - /*--- recompute elements surrounding points, points surrounding points ---*/ - - if (rank == MASTER_NODE) cout << "Recomputing point connectivity." << endl; - geometry[MESH_0]->SetPoint_Connectivity(); - - /*--- Compute elements surrounding elements ---*/ - - if (rank == MASTER_NODE) cout << "Setting element connectivity." << endl; - geometry[MESH_0]->SetElement_Connectivity(); - - /*--- Check the orientation before computing geometrical quantities ---*/ - - geometry[MESH_0]->SetBoundVolume(); - if (config->GetReorientElements()) { - if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation." << endl; - geometry[MESH_0]->Check_IntElem_Orientation(config); - geometry[MESH_0]->Check_BoundElem_Orientation(config); - } - - /*--- Create the edge structure ---*/ - - if (rank == MASTER_NODE) cout << "Identifying edges and vertices." << endl; - geometry[MESH_0]->SetEdges(); - geometry[MESH_0]->SetVertex(config); - - /*--- Create the control volume structures ---*/ - - if (rank == MASTER_NODE) cout << "Setting the control volume structure." << endl; - SU2_OMP_PARALLEL { - geometry[MESH_0]->SetControlVolume(config, ALLOCATE); - geometry[MESH_0]->SetBoundControlVolume(config, ALLOCATE); - } - END_SU2_OMP_PARALLEL - - /*--- Visualize a dual control volume if requested ---*/ - - if ((config->GetVisualize_CV() >= 0) && - (config->GetVisualize_CV() < (long)geometry[MESH_0]->GetGlobal_nPointDomain())) - geometry[MESH_0]->VisualizeControlVolume(config); - - /*--- Identify closest normal neighbor ---*/ - - if (rank == MASTER_NODE) cout << "Searching for the closest normal neighbors to the surfaces." << endl; - geometry[MESH_0]->FindNormal_Neighbor(config); - - /*--- Store the global to local mapping. ---*/ - - if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; - geometry[MESH_0]->SetGlobal_to_Local_Point(); - - /*--- Compute the surface curvature ---*/ - - if (!fea) { - if (rank == MASTER_NODE) cout << "Compute the surface curvature." << endl; - geometry[MESH_0]->ComputeSurf_Curvature(config); - } - - /*--- Check for periodicity and disable MG if necessary. ---*/ - - if (rank == MASTER_NODE) cout << "Checking for periodicity." << endl; - geometry[MESH_0]->Check_Periodicity(config); - - /*--- Compute mesh quality statistics on the fine grid. ---*/ - - if (!fea) { - if (rank == MASTER_NODE) - cout << "Computing mesh quality statistics for the dual control volumes." << endl; - geometry[MESH_0]->ComputeMeshQualityStatistics(config); - } - - geometry[MESH_0]->SetMGLevel(MESH_0); - if ((config->GetnMGLevels() != 0) && (rank == MASTER_NODE)) - cout << "Setting the multigrid structure." << endl; - - /*--- Loop over all the new grid ---*/ - - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - - /*--- Create main agglomeration structure ---*/ - - geometry[iMGlevel] = new CMultiGridGeometry(geometry[iMGlevel-1], config, iMGlevel); - - /*--- Compute points surrounding points. ---*/ - - geometry[iMGlevel]->SetPoint_Connectivity(geometry[iMGlevel-1]); - - /*--- Create the edge structure ---*/ - - geometry[iMGlevel]->SetEdges(); - geometry[iMGlevel]->SetVertex(geometry[iMGlevel-1], config); - - /*--- Create the control volume structures ---*/ - - geometry[iMGlevel]->SetControlVolume(geometry[iMGlevel-1], ALLOCATE); - geometry[iMGlevel]->SetBoundControlVolume(geometry[iMGlevel-1], ALLOCATE); - geometry[iMGlevel]->SetCoord(geometry[iMGlevel-1]); - - /*--- Find closest neighbor to a surface point ---*/ - - geometry[iMGlevel]->FindNormal_Neighbor(config); - - /*--- Store our multigrid index. ---*/ - - geometry[iMGlevel]->SetMGLevel(iMGlevel); - - /*--- Protect against the situation that we were not able to complete - the agglomeration for this level, i.e., there weren't enough points. - We need to check if we changed the total number of levels and delete - the incomplete CMultiGridGeometry object. ---*/ - - if (config->GetnMGLevels() != requestedMGlevels) { - delete geometry[iMGlevel]; - geometry[iMGlevel] = nullptr; - break; - } - - } - - if (config->GetWrt_MultiGrid()) geometry[MESH_0]->ColorMGLevels(config->GetnMGLevels(), geometry); - - /*--- For unsteady simulations, initialize the grid volumes - and coordinates for previous solutions. Loop over all zones/grids ---*/ - - if ((config->GetTime_Marching() != TIME_MARCHING::STEADY) && config->GetDynamic_Grid()) { - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - - /*--- Update cell volume ---*/ - geometry[iMGlevel]->nodes->SetVolume_n(); - geometry[iMGlevel]->nodes->SetVolume_nM1(); - - if (config->GetGrid_Movement()) { - /*--- Update point coordinates ---*/ - geometry[iMGlevel]->nodes->SetCoord_n(); - geometry[iMGlevel]->nodes->SetCoord_n1(); - } + geometry[iMesh]->MatchActuator_Disk(config); + } + + /*--- If we have any periodic markers in this calculation, we must + match the periodic points found on both sides of the periodic BC. + Note that the current implementation requires a 1-to-1 matching of + periodic points on the pair of periodic faces after the translation + or rotation is taken into account. ---*/ + + if ((config->GetnMarker_Periodic() != 0) && !fem_solver) { + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + + /*--- Note that we loop over pairs of periodic markers individually + so that repeated nodes on adjacent periodic faces are properly + accounted for in multiple places. ---*/ + + for (unsigned short iPeriodic = 1; iPeriodic <= config->GetnMarker_Periodic()/2; iPeriodic++) { + geometry[iMesh]->MatchPeriodic(config, iPeriodic); + } + + /*--- For Streamwise Periodic flow, find a unique reference node on the dedicated inlet marker. ---*/ + if (config->GetKind_Streamwise_Periodic() != ENUM_STREAMWISE_PERIODIC::NONE) + geometry[iMesh]->FindUniqueNode_PeriodicBound(config); + + /*--- Initialize the communication framework for the periodic BCs. ---*/ + geometry[iMesh]->PreprocessPeriodicComms(geometry[iMesh], config); + + } } - } - - - /*--- Create the data structure for MPI point-to-point communications. ---*/ - - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - geometry[iMGlevel]->PreprocessP2PComms(geometry[iMGlevel], config); - - - /*--- Perform a few preprocessing routines and communications. ---*/ - - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - - /*--- Compute the max length. ---*/ - - if (!fea) { - if ((rank == MASTER_NODE) && (iMGlevel == MESH_0)) - cout << "Finding max control volume width." << endl; - geometry[iMGlevel]->SetMaxLength(config); - } - - /*--- Communicate the number of neighbors. This is needed for - some centered schemes and for multigrid in parallel. ---*/ - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE) && (iMGlevel == MESH_0)) - cout << "Communicating number of neighbors." << endl; - geometry[iMGlevel]->InitiateComms(geometry[iMGlevel], config, NEIGHBORS); - geometry[iMGlevel]->CompleteComms(geometry[iMGlevel], config, NEIGHBORS); - } - -} - -void CDriver::Geometrical_Preprocessing_DGFEM(CConfig* config, CGeometry **&geometry) { - - /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ - /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ - - CGeometry *geometry_aux = new CPhysicalGeometry(config, iZone, nZone); - - /*--- Set the dimension --- */ - - nDim = geometry_aux->GetnDim(); - - /*--- For the FEM solver with time-accurate local time-stepping, use - a dummy solver class to retrieve the initial flow state. ---*/ - - CSolver *solver_aux = new CFEM_DG_EulerSolver(config, nDim, MESH_0); - - /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ - - geometry_aux->SetColorFEMGrid_Parallel(config); - - /*--- Allocate the memory of the current domain, and divide the grid - between the ranks. ---*/ - - geometry = new CGeometry *[config->GetnMGLevels()+1] (); - - geometry[MESH_0] = new CMeshFEM_DG(geometry_aux, config); - - /*--- Deallocate the memory of geometry_aux and solver_aux ---*/ - - delete geometry_aux; - delete solver_aux; - - /*--- Add the Send/Receive boundaries ---*/ - geometry[MESH_0]->SetSendReceive(config); - - /*--- Add the Send/Receive boundaries ---*/ - geometry[MESH_0]->SetBoundaries(config); - - /*--- Carry out a dynamic cast to CMeshFEM_DG, such that it is not needed to - define all virtual functions in the base class CGeometry. ---*/ - CMeshFEM_DG *DGMesh = dynamic_cast(geometry[MESH_0]); - - /*--- Determine the standard elements for the volume elements. ---*/ - if (rank == MASTER_NODE) cout << "Creating standard volume elements." << endl; - DGMesh->CreateStandardVolumeElements(config); - - /*--- Create the face information needed to compute the contour integral - for the elements in the Discontinuous Galerkin formulation. ---*/ - if (rank == MASTER_NODE) cout << "Creating face information." << endl; - DGMesh->CreateFaces(config); - - /*--- Compute the metric terms of the volume elements. ---*/ - if (rank == MASTER_NODE) cout << "Computing metric terms volume elements." << endl; - DGMesh->MetricTermsVolumeElements(config); - - /*--- Compute the metric terms of the surface elements. ---*/ - if (rank == MASTER_NODE) cout << "Computing metric terms surface elements." << endl; - DGMesh->MetricTermsSurfaceElements(config); - - /*--- Compute a length scale of the volume elements. ---*/ - if (rank == MASTER_NODE) cout << "Computing length scale volume elements." << endl; - DGMesh->LengthScaleVolumeElements(); - - /*--- Compute the coordinates of the integration points. ---*/ - if (rank == MASTER_NODE) cout << "Computing coordinates of the integration points." << endl; - DGMesh->CoordinatesIntegrationPoints(); - - /*--- Compute the coordinates of the location of the solution DOFs. This is different - from the grid points when a different polynomial degree is used to represent the - geometry and solution. ---*/ - if (rank == MASTER_NODE) cout << "Computing coordinates of the solution DOFs." << endl; - DGMesh->CoordinatesSolDOFs(); - - /*--- Perform the preprocessing tasks when wall functions are used. ---*/ - if (rank == MASTER_NODE) cout << "Preprocessing for the wall functions. " << endl; - DGMesh->WallFunctionPreprocessing(config); - - /*--- Store the global to local mapping. ---*/ - if (rank == MASTER_NODE) cout << "Storing a mapping from global to local DOF index." << endl; - geometry[MESH_0]->SetGlobal_to_Local_Point(); - - - /*--- Loop to create the coarser grid levels. ---*/ - - for(unsigned short iMGlevel=1; iMGlevel<=config->GetnMGLevels(); iMGlevel++) { - - SU2_MPI::Error("Geometrical_Preprocessing_DGFEM: Coarse grid levels not implemented yet.", - CURRENT_FUNCTION); - } - -} - -void CDriver::Solver_Preprocessing(CConfig* config, CGeometry** geometry, CSolver ***&solver) { - - MAIN_SOLVER kindSolver = config->GetKind_Solver(); - - if (rank == MASTER_NODE) - cout << endl <<"-------------------- Solver Preprocessing ( Zone " << config->GetiZone() <<" ) --------------------" << endl; - - solver = new CSolver**[config->GetnMGLevels()+1] (); - - for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++){ - solver[iMesh] = CSolverFactory::CreateSolverContainer(kindSolver, config, geometry[iMesh], iMesh); - } - - /*--- Count the number of DOFs per solution point. ---*/ - - DOFsPerPoint = 0; - - for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++) - if (solver[MESH_0][iSol]) DOFsPerPoint += solver[MESH_0][iSol]->GetnVar(); - - /*--- Restart solvers, for FSI the geometry cannot be updated because the interpolation classes - * should always use the undeformed mesh (otherwise the results would not be repeatable). ---*/ - - if (!fsi) Solver_Restart(solver, geometry, config, true); - - /*--- Set up any necessary inlet profiles ---*/ - - Inlet_Preprocessing(solver, geometry, config); - -} - -void CDriver::Inlet_Preprocessing(CSolver ***solver, CGeometry **geometry, - CConfig *config) const { - - /*--- Adjust iteration number for unsteady restarts. ---*/ - - const bool adjoint = config->GetDiscrete_Adjoint() || config->GetContinuous_Adjoint(); - - int val_iter = 0; - - if (config->GetTime_Domain()) { - val_iter = adjoint? config->GetUnst_AdjointIter() : config->GetRestart_Iter(); - val_iter -= 1; - if (!adjoint && config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND) - val_iter -= 1; - if (!adjoint && !config->GetRestart()) val_iter = 0; - } - - /*--- Load inlet profile files for any of the active solver containers. - Note that these routines fill the fine grid data structures for the markers - and restrict values down to all coarser MG levels. ---*/ - - if (config->GetInlet_Profile_From_File()) { - - /*--- Use LoadInletProfile() routines for the particular solver. ---*/ - - if (rank == MASTER_NODE) { - cout << endl; - cout << "Reading inlet profile from file: "; - cout << config->GetInlet_FileName() << endl; - } - - if (solver[MESH_0][FLOW_SOL]) { - solver[MESH_0][FLOW_SOL]->LoadInletProfile(geometry, solver, config, val_iter, FLOW_SOL, INLET_FLOW); - } - if (solver[MESH_0][TURB_SOL]) { - solver[MESH_0][TURB_SOL]->LoadInletProfile(geometry, solver, config, val_iter, TURB_SOL, INLET_FLOW); - } - if (solver[MESH_0][SPECIES_SOL]) { - solver[MESH_0][SPECIES_SOL]->LoadInletProfile(geometry, solver, config, val_iter, SPECIES_SOL, INLET_FLOW); - } - - /*--- Exit if profiles were requested for a solver that is not available. ---*/ - - if (!config->GetFluidProblem()) { - SU2_MPI::Error(string("Inlet profile specification via file (C++) has not been \n") + - string("implemented yet for this solver.\n") + - string("Please set SPECIFIED_INLET_PROFILE= NO and try again."), CURRENT_FUNCTION); - } - - } else { - - /*--- Uniform inlets or python-customized inlets ---*/ - - /* --- Initialize quantities for inlet boundary - * This routine does not check if they python wrapper is being used to - * set custom boundary conditions. This is intentional; the - * default values for python custom BCs are initialized with the default - * values specified in the config (avoiding non physical values) --- */ - - for (unsigned short iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - for(unsigned short iMarker=0; iMarker < config->GetnMarker_All(); iMarker++) { - if (solver[iMesh][FLOW_SOL]) solver[iMesh][FLOW_SOL]->SetUniformInlet(config, iMarker); - if (solver[iMesh][TURB_SOL]) solver[iMesh][TURB_SOL]->SetUniformInlet(config, iMarker); - if (solver[iMesh][SPECIES_SOL]) solver[iMesh][SPECIES_SOL]->SetUniformInlet(config, iMarker); - } - } - - } - -} - -void CDriver::Solver_Restart(CSolver ***solver, CGeometry **geometry, - CConfig *config, bool update_geo) { - - /*--- Check for restarts and use the LoadRestart() routines. ---*/ - - const bool restart = config->GetRestart(); - const bool restart_flow = config->GetRestart_Flow(); - - /*--- Adjust iteration number for unsteady restarts. ---*/ - - int val_iter = 0; - - const bool adjoint = (config->GetDiscrete_Adjoint() || config->GetContinuous_Adjoint()); - const bool time_domain = config->GetTime_Domain(); - const bool dt_step_2nd = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND) && - !config->GetStructuralProblem() && !config->GetFEMSolver() && - !adjoint && time_domain; - - if (time_domain) { - if (adjoint) val_iter = config->GetUnst_AdjointIter() - 1; - else val_iter = config->GetRestart_Iter() - 1 - dt_step_2nd; - } - - /*--- Restart direct solvers. ---*/ - - if (restart || restart_flow) { - for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) { - auto sol = solver[MESH_0][iSol]; - if (sol && !sol->GetAdjoint()) { - /*--- Note that the mesh solver always loads the most recent file (and not -2). ---*/ - SU2_OMP_PARALLEL_(if(sol->GetHasHybridParallel())) - sol->LoadRestart(geometry, solver, config, val_iter + (iSol==MESH_SOL && dt_step_2nd), update_geo); - END_SU2_OMP_PARALLEL - } - } - } - - /*--- Restart adjoint solvers. ---*/ - - if (restart) { - if ((config->GetKind_Solver() == MAIN_SOLVER::TEMPLATE_SOLVER) || - (config->GetKind_Solver() == MAIN_SOLVER::ADJ_RANS && !config->GetFrozen_Visc_Cont())) { - SU2_MPI::Error("A restart capability has not been implemented yet for this solver.\n" - "Please set RESTART_SOL= NO and try again.", CURRENT_FUNCTION); - } - - for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) { - auto sol = solver[MESH_0][iSol]; - if (sol && sol->GetAdjoint()) - sol->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - } - -} - -void CDriver::Solver_Postprocessing(CSolver ****solver, CGeometry **geometry, - CConfig *config, unsigned short val_iInst) { - - for (int iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++){ - delete solver[val_iInst][iMGlevel][iSol]; - } - delete [] solver[val_iInst][iMGlevel]; - } - delete [] solver[val_iInst]; - - CSolverFactory::ClearSolverMeta(); - -} - -void CDriver::Integration_Preprocessing(CConfig *config, CSolver **solver, CIntegration **&integration) const { - - if (rank == MASTER_NODE) - cout << endl <<"----------------- Integration Preprocessing ( Zone " << config->GetiZone() <<" ) ------------------" << endl; - - MAIN_SOLVER kindMainSolver = config->GetKind_Solver(); - - integration = CIntegrationFactory::CreateIntegrationContainer(kindMainSolver, solver); - -} - -void CDriver::Integration_Postprocessing(CIntegration ***integration, CGeometry **geometry, CConfig *config, unsigned short val_iInst) { - - for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++){ - delete integration[val_iInst][iSol]; - } - - delete [] integration[val_iInst]; - -} - -template -void CDriver::InstantiateTurbulentNumerics(unsigned short nVar_Turb, int offset, const CConfig *config, - const CSolver* turb_solver, CNumerics ****&numerics) const { - const int conv_term = CONV_TERM + offset; - const int visc_term = VISC_TERM + offset; - - const int source_first_term = SOURCE_FIRST_TERM + offset; - const int source_second_term = SOURCE_SECOND_TERM + offset; - - const int conv_bound_term = CONV_BOUND_TERM + offset; - const int visc_bound_term = VISC_BOUND_TERM + offset; - - bool spalart_allmaras, neg_spalart_allmaras, e_spalart_allmaras, comp_spalart_allmaras, e_comp_spalart_allmaras, menter_sst; - spalart_allmaras = neg_spalart_allmaras = e_spalart_allmaras = comp_spalart_allmaras = e_comp_spalart_allmaras = menter_sst = false; - - /*--- Assign turbulence model booleans ---*/ - - switch (config->GetKind_Turb_Model()) { - case TURB_MODEL::NONE: - SU2_MPI::Error("No turbulence model selected.", CURRENT_FUNCTION); - break; - case TURB_MODEL::SA: spalart_allmaras = true; break; - case TURB_MODEL::SA_NEG: neg_spalart_allmaras = true; break; - case TURB_MODEL::SA_E: e_spalart_allmaras = true; break; - case TURB_MODEL::SA_COMP: comp_spalart_allmaras = true; break; - case TURB_MODEL::SA_E_COMP: e_comp_spalart_allmaras = true; break; - case TURB_MODEL::SST: menter_sst = true; break; - case TURB_MODEL::SST_SUST: menter_sst = true; break; - } - - /*--- If the Menter SST model is used, store the constants of the model and determine the - free stream values of the turbulent kinetic energy and dissipation rate. ---*/ - - const su2double *constants = nullptr; - su2double kine_Inf = 0.0, omega_Inf = 0.0; - - if (menter_sst) { - constants = turb_solver->GetConstants(); - kine_Inf = turb_solver->GetTke_Inf(); - omega_Inf = turb_solver->GetOmega_Inf(); - } - - /*--- Definition of the convective scheme for each equation and mesh level ---*/ - - switch (config->GetKind_ConvNumScheme_Turb()) { - case NO_UPWIND: - SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_TURB option.", CURRENT_FUNCTION); - break; - case SPACE_UPWIND : - for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - if (spalart_allmaras || neg_spalart_allmaras || e_spalart_allmaras || comp_spalart_allmaras || e_comp_spalart_allmaras) { - numerics[iMGlevel][TURB_SOL][conv_term] = new CUpwSca_TurbSA(nDim, nVar_Turb, config); - } - else if (menter_sst) numerics[iMGlevel][TURB_SOL][conv_term] = new CUpwSca_TurbSST(nDim, nVar_Turb, config); - } - break; - default: - SU2_MPI::Error("Invalid convective scheme for the turbulence equations.", CURRENT_FUNCTION); - break; - } - - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - - for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - if (spalart_allmaras || e_spalart_allmaras || comp_spalart_allmaras || e_comp_spalart_allmaras) { - numerics[iMGlevel][TURB_SOL][visc_term] = new CAvgGrad_TurbSA(nDim, nVar_Turb, true, config); - } - else if (neg_spalart_allmaras) - numerics[iMGlevel][TURB_SOL][visc_term] = new CAvgGrad_TurbSA_Neg(nDim, nVar_Turb, true, config); - else if (menter_sst) - numerics[iMGlevel][TURB_SOL][visc_term] = new CAvgGrad_TurbSST(nDim, nVar_Turb, constants, true, config); - } - - /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ - - for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - auto& turb_source_first_term = numerics[iMGlevel][TURB_SOL][source_first_term]; - - if (spalart_allmaras) - turb_source_first_term = new CSourcePieceWise_TurbSA(nDim, nVar_Turb, config); - else if (e_spalart_allmaras) - turb_source_first_term = new CSourcePieceWise_TurbSA_E(nDim, nVar_Turb, config); - else if (comp_spalart_allmaras) - turb_source_first_term = new CSourcePieceWise_TurbSA_COMP(nDim, nVar_Turb, config); - else if (e_comp_spalart_allmaras) - turb_source_first_term = new CSourcePieceWise_TurbSA_E_COMP(nDim, nVar_Turb, config); - else if (neg_spalart_allmaras) - turb_source_first_term = new CSourcePieceWise_TurbSA_Neg(nDim, nVar_Turb, config); - else if (menter_sst) - turb_source_first_term = new CSourcePieceWise_TurbSST(nDim, nVar_Turb, constants, kine_Inf, omega_Inf, - config); - - numerics[iMGlevel][TURB_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Turb, config); - } - - /*--- Definition of the boundary condition method ---*/ - - for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - if (spalart_allmaras || e_spalart_allmaras || comp_spalart_allmaras || e_comp_spalart_allmaras) { - numerics[iMGlevel][TURB_SOL][conv_bound_term] = new CUpwSca_TurbSA(nDim, nVar_Turb, config); - numerics[iMGlevel][TURB_SOL][visc_bound_term] = new CAvgGrad_TurbSA(nDim, nVar_Turb, false, config); - } - else if (neg_spalart_allmaras) { - numerics[iMGlevel][TURB_SOL][conv_bound_term] = new CUpwSca_TurbSA(nDim, nVar_Turb, config); - numerics[iMGlevel][TURB_SOL][visc_bound_term] = new CAvgGrad_TurbSA_Neg(nDim, nVar_Turb, false, config); - } - else if (menter_sst) { - numerics[iMGlevel][TURB_SOL][conv_bound_term] = new CUpwSca_TurbSST(nDim, nVar_Turb, config); - numerics[iMGlevel][TURB_SOL][visc_bound_term] = new CAvgGrad_TurbSST(nDim, nVar_Turb, constants, false, - config); - } - } -} -/*--- Explicit instantiation of the template above, needed because it is defined in a cpp file, instead of hpp. ---*/ -template void CDriver::InstantiateTurbulentNumerics>( - unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - -template void CDriver::InstantiateTurbulentNumerics>( - unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - -template void CDriver::InstantiateTurbulentNumerics>( - unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - -template -void CDriver::InstantiateSpeciesNumerics(unsigned short nVar_Species, int offset, const CConfig *config, - const CSolver* species_solver, CNumerics ****&numerics) const { - const int conv_term = CONV_TERM + offset; - const int visc_term = VISC_TERM + offset; - - const int source_first_term = SOURCE_FIRST_TERM + offset; - const int source_second_term = SOURCE_SECOND_TERM + offset; - - const int conv_bound_term = CONV_BOUND_TERM + offset; - const int visc_bound_term = VISC_BOUND_TERM + offset; - - /*--- Definition of the convective scheme for each equation and mesh level. Also for boundary conditions. ---*/ - - switch (config->GetKind_ConvNumScheme_Species()) { - case NONE : - break; - case SPACE_UPWIND : - for (auto iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][SPECIES_SOL][conv_term] = new CUpwSca_Species(nDim, nVar_Species, config); - numerics[iMGlevel][SPECIES_SOL][conv_bound_term] = new CUpwSca_Species(nDim, nVar_Species, config); - } - break; - default : - SU2_MPI::Error("Invalid convective scheme for the species transport equations. Use SCALAR_UPWIND.", CURRENT_FUNCTION); - break; - } - - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - - for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][SPECIES_SOL][visc_term] = new CAvgGrad_Species(nDim, nVar_Species, true, config); - numerics[iMGlevel][SPECIES_SOL][visc_bound_term] = new CAvgGrad_Species(nDim, nVar_Species, false, config); - } - - /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ - - for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - if (config->GetAxisymmetric() == YES) { - numerics[iMGlevel][SPECIES_SOL][source_first_term] = new CSourceAxisymmetric_Species(nDim, nVar_Species, config); - } - else { - numerics[iMGlevel][SPECIES_SOL][source_first_term] = new CSourceNothing(nDim, nVar_Species, config); - } - numerics[iMGlevel][SPECIES_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Species, config); - } -} -/*--- Explicit instantiation of the template above, needed because it is defined in a cpp file, instead of hpp. ---*/ -template void CDriver::InstantiateSpeciesNumerics>( - unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - -template void CDriver::InstantiateSpeciesNumerics>( - unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - -template void CDriver::InstantiateSpeciesNumerics>( - unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - -void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSolver ***solver, CNumerics ****&numerics) const { - - if (rank == MASTER_NODE) - cout << endl <<"------------------- Numerics Preprocessing ( Zone " << config->GetiZone() <<" ) -------------------" << endl; - - unsigned short iMGlevel, iSol, - - nVar_Template = 0, - nVar_Flow = 0, - nVar_NEMO = 0, - nPrimVar_NEMO = 0, - nPrimVarGrad_NEMO = 0, - nVar_Trans = 0, - nVar_Turb = 0, - nVar_Species = 0, - nVar_Adj_Flow = 0, - nVar_Adj_Turb = 0, - nVar_FEM = 0, - nVar_Rad = 0, - nVar_Heat = 0; - - numerics = new CNumerics***[config->GetnMGLevels()+1] (); - - bool compressible = false; - bool incompressible = false; - bool ideal_gas = (config->GetKind_FluidModel() == STANDARD_AIR) || (config->GetKind_FluidModel() == IDEAL_GAS); - bool roe_low_dissipation = (config->GetKind_RoeLowDiss() != NO_ROELOWDISS); - - /*--- Initialize some useful booleans ---*/ - bool euler, ns, NEMO_euler, NEMO_ns, turbulent, adj_euler, adj_ns, adj_turb, fem_euler, fem_ns; - bool fem, heat, transition, template_solver; - - euler = ns = NEMO_euler = NEMO_ns = turbulent = adj_euler = adj_ns = adj_turb = fem_euler = fem_ns = false; - fem = heat = transition = template_solver = false; - bool species = false; - - /*--- Assign booleans ---*/ - switch (config->GetKind_Solver()) { - case MAIN_SOLVER::TEMPLATE_SOLVER: - template_solver = true; break; - - case MAIN_SOLVER::EULER: - case MAIN_SOLVER::DISC_ADJ_EULER: - euler = compressible = true; break; - - case MAIN_SOLVER::NAVIER_STOKES: - case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: - ns = compressible = true; - species = (config->GetKind_Species_Model() != SPECIES_MODEL::NONE); break; - - case MAIN_SOLVER::NEMO_EULER: - NEMO_euler = compressible = true; break; - - case MAIN_SOLVER::NEMO_NAVIER_STOKES: - NEMO_ns = compressible = true; break; - - case MAIN_SOLVER::RANS: - case MAIN_SOLVER::DISC_ADJ_RANS: - ns = compressible = turbulent = true; - transition = (config->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM); - species = config->GetKind_Species_Model() != SPECIES_MODEL::NONE; break; - - case MAIN_SOLVER::INC_EULER: - case MAIN_SOLVER::DISC_ADJ_INC_EULER: - euler = incompressible = true; break; - - case MAIN_SOLVER::INC_NAVIER_STOKES: - case MAIN_SOLVER::DISC_ADJ_INC_NAVIER_STOKES: - ns = incompressible = true; - heat = config->GetWeakly_Coupled_Heat(); - species = (config->GetKind_Species_Model() != SPECIES_MODEL::NONE); break; - - case MAIN_SOLVER::INC_RANS: - case MAIN_SOLVER::DISC_ADJ_INC_RANS: - ns = incompressible = turbulent = true; - heat = config->GetWeakly_Coupled_Heat(); - transition = (config->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM); - species = (config->GetKind_Species_Model() != SPECIES_MODEL::NONE); break; - - case MAIN_SOLVER::FEM_EULER: - case MAIN_SOLVER::DISC_ADJ_FEM_EULER: - fem_euler = compressible = true; break; - - case MAIN_SOLVER::FEM_NAVIER_STOKES: - case MAIN_SOLVER::DISC_ADJ_FEM_NS: - fem_ns = compressible = true; break; - - case MAIN_SOLVER::FEM_RANS: - case MAIN_SOLVER::DISC_ADJ_FEM_RANS: - fem_ns = compressible = true; break; - - case MAIN_SOLVER::FEM_LES: - fem_ns = compressible = true; break; - - case MAIN_SOLVER::HEAT_EQUATION: - case MAIN_SOLVER::DISC_ADJ_HEAT: - heat = true; break; - - case MAIN_SOLVER::FEM_ELASTICITY: - case MAIN_SOLVER::DISC_ADJ_FEM: - fem = true; break; - - case MAIN_SOLVER::ADJ_EULER: - adj_euler = euler = compressible = true; break; - - case MAIN_SOLVER::ADJ_NAVIER_STOKES: - adj_ns = ns = compressible = true; - turbulent = (config->GetKind_Turb_Model() != TURB_MODEL::NONE); break; - - case MAIN_SOLVER::ADJ_RANS: - adj_ns = ns = compressible = turbulent = true; - adj_turb = !config->GetFrozen_Visc_Cont(); break; - - default: - break; - - } - - /*--- Number of variables for the template ---*/ - - if (template_solver) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); - - /*--- Number of variables for direct problem ---*/ - - if (euler) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); - if (ns) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); - if (NEMO_euler) nVar_NEMO = solver[MESH_0][FLOW_SOL]->GetnVar(); - if (NEMO_ns) nVar_NEMO = solver[MESH_0][FLOW_SOL]->GetnVar(); - if (turbulent) nVar_Turb = solver[MESH_0][TURB_SOL]->GetnVar(); - if (transition) nVar_Trans = solver[MESH_0][TRANS_SOL]->GetnVar(); - if (species) nVar_Species = solver[MESH_0][SPECIES_SOL]->GetnVar(); - - if (fem_euler) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); - if (fem_ns) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); - - if (fem) nVar_FEM = solver[MESH_0][FEA_SOL]->GetnVar(); - if (heat) nVar_Heat = solver[MESH_0][HEAT_SOL]->GetnVar(); - - if (config->AddRadiation()) nVar_Rad = solver[MESH_0][RAD_SOL]->GetnVar(); - - /*--- Number of variables for adjoint problem ---*/ - - if (adj_euler) nVar_Adj_Flow = solver[MESH_0][ADJFLOW_SOL]->GetnVar(); - if (adj_ns) nVar_Adj_Flow = solver[MESH_0][ADJFLOW_SOL]->GetnVar(); - if (adj_turb) nVar_Adj_Turb = solver[MESH_0][ADJTURB_SOL]->GetnVar(); - - /*--- Additional Variables required for NEMO solver ---*/ - - if (NEMO_euler || NEMO_ns) nPrimVar_NEMO = solver[MESH_0][FLOW_SOL]->GetnPrimVar(); - if (NEMO_euler || NEMO_ns) nPrimVarGrad_NEMO = solver[MESH_0][FLOW_SOL]->GetnPrimVarGrad(); - - /*--- Definition of the Class for the numerical method: - numerics_container[INSTANCE_LEVEL][MESH_LEVEL][EQUATION][EQ_TERM] ---*/ - - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel] = new CNumerics** [MAX_SOLS]; - for (iSol = 0; iSol < MAX_SOLS; iSol++) - numerics[iMGlevel][iSol] = new CNumerics* [MAX_TERMS*omp_get_max_threads()](); - } - - /*--- Instantiate one numerics object per thread for each required term. ---*/ - - for (int thread = 0; thread < omp_get_max_threads(); ++thread) - { - const int offset = thread * MAX_TERMS; - - const int conv_term = CONV_TERM + offset; - const int visc_term = VISC_TERM + offset; - - const int source_first_term = SOURCE_FIRST_TERM + offset; - const int source_second_term = SOURCE_SECOND_TERM + offset; - - const int conv_bound_term = CONV_BOUND_TERM + offset; - const int visc_bound_term = VISC_BOUND_TERM + offset; - - const int fea_term = FEA_TERM + offset; - - /*--- Solver definition for the template problem ---*/ - if (template_solver) { - - /*--- Definition of the convective scheme for each equation and mesh level ---*/ - switch (config->GetKind_ConvNumScheme_Template()) { - case SPACE_CENTERED : case SPACE_UPWIND : - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][TEMPLATE_SOL][conv_term] = new CConvective_Template(nDim, nVar_Template, config); - break; - default: - SU2_MPI::Error("Convective scheme not implemented (template_solver).", CURRENT_FUNCTION); - break; - } - - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][TEMPLATE_SOL][visc_term] = new CViscous_Template(nDim, nVar_Template, config); - - /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][TEMPLATE_SOL][source_first_term] = new CSource_Template(nDim, nVar_Template, config); - - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][TEMPLATE_SOL][conv_bound_term] = new CConvective_Template(nDim, nVar_Template, config); - } - - } - - /*--- Solver definition for the Potential, Euler, Navier-Stokes problems ---*/ - if ((euler) || (ns)) { - - /*--- Definition of the convective scheme for each equation and mesh level ---*/ - switch (config->GetKind_ConvNumScheme_Flow()) { - case NO_CONVECTIVE : - SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_FLOW option.", CURRENT_FUNCTION); - break; - - case SPACE_CENTERED : - if (compressible) { - /*--- "conv_term" is not instantiated as all compressible centered schemes are vectorized. ---*/ - - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwRoe_Flow(nDim, nVar_Flow, config, false); - - } - if (incompressible) { - /*--- Incompressible flow, use preconditioning method ---*/ - switch (config->GetKind_Centered_Flow()) { - case LAX : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentLaxInc_Flow(nDim, nVar_Flow, config); break; - case JST : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentJSTInc_Flow(nDim, nVar_Flow, config); break; - default: - SU2_MPI::Error("Invalid centered scheme or not implemented.\n Currently, only JST and LAX-FRIEDRICH are available for incompressible flows.", CURRENT_FUNCTION); - break; - } - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][conv_term] = new CCentLaxInc_Flow(nDim, nVar_Flow, config); - - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwFDSInc_Flow(nDim, nVar_Flow, config); - - } - break; - case SPACE_UPWIND : - if (compressible) { - /*--- Compressible flow ---*/ - switch (config->GetKind_Upwind_Flow()) { - case ROE: - if (ideal_gas) { - - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwRoe_Flow(nDim, nVar_Flow, config, roe_low_dissipation); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwRoe_Flow(nDim, nVar_Flow, config, false); - } - } else { - - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwGeneralRoe_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwGeneralRoe_Flow(nDim, nVar_Flow, config); - } - } - break; - - case AUSM: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSM_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSM_Flow(nDim, nVar_Flow, config); - } - break; - - case AUSMPLUSUP: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSMPLUSUP_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSMPLUSUP_Flow(nDim, nVar_Flow, config); - } - break; - - case AUSMPLUSUP2: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSMPLUSUP2_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSMPLUSUP2_Flow(nDim, nVar_Flow, config); - } - break; - - case TURKEL: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwTurkel_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwTurkel_Flow(nDim, nVar_Flow, config); - } - break; - - case L2ROE: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwL2Roe_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwL2Roe_Flow(nDim, nVar_Flow, config); - } - break; - case LMROE: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwLMRoe_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwLMRoe_Flow(nDim, nVar_Flow, config); - } - break; - - case SLAU: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwSLAU_Flow(nDim, nVar_Flow, config, roe_low_dissipation); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwSLAU_Flow(nDim, nVar_Flow, config, false); - } - break; - - case SLAU2: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwSLAU2_Flow(nDim, nVar_Flow, config, roe_low_dissipation); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwSLAU2_Flow(nDim, nVar_Flow, config, false); - } - break; - - case HLLC: - if (ideal_gas) { - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwHLLC_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwHLLC_Flow(nDim, nVar_Flow, config); - } - } - else { - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwGeneralHLLC_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwGeneralHLLC_Flow(nDim, nVar_Flow, config); - } - } - break; - - case MSW: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwMSW_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwMSW_Flow(nDim, nVar_Flow, config); - } - break; - - case CUSP: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwCUSP_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwCUSP_Flow(nDim, nVar_Flow, config); - } - break; - - default: - SU2_MPI::Error("Invalid upwind scheme or not implemented.", CURRENT_FUNCTION); - break; - } - - } - if (incompressible) { - /*--- Incompressible flow, use artificial compressibility method ---*/ - switch (config->GetKind_Upwind_Flow()) { - case FDS: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwFDSInc_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwFDSInc_Flow(nDim, nVar_Flow, config); - } - break; - default: - SU2_MPI::Error("Invalid upwind scheme or not implemented.\n Currently, only FDS is available for incompressible flows.", CURRENT_FUNCTION); - break; - } - } - break; - - default: - SU2_MPI::Error("Invalid convective scheme for the Euler / Navier-Stokes equations.", CURRENT_FUNCTION); - break; - } - - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - if (compressible) { - if (ideal_gas) { - - /*--- Compressible flow Ideal gas ---*/ - numerics[MESH_0][FLOW_SOL][visc_term] = new CAvgGrad_Flow(nDim, nVar_Flow, true, config); - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][visc_term] = new CAvgGrad_Flow(nDim, nVar_Flow, false, config); - - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][visc_bound_term] = new CAvgGrad_Flow(nDim, nVar_Flow, false, config); - - } else { - - /*--- Compressible flow Real gas ---*/ - numerics[MESH_0][FLOW_SOL][visc_term] = new CGeneralAvgGrad_Flow(nDim, nVar_Flow, true, config); - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][visc_term] = new CGeneralAvgGrad_Flow(nDim, nVar_Flow, false, config); - - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][visc_bound_term] = new CGeneralAvgGrad_Flow(nDim, nVar_Flow, false, config); - - } - } - if (incompressible) { - /*--- Incompressible flow, use preconditioning method ---*/ - numerics[MESH_0][FLOW_SOL][visc_term] = new CAvgGradInc_Flow(nDim, nVar_Flow, true, config); - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][visc_term] = new CAvgGradInc_Flow(nDim, nVar_Flow, false, config); - - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][visc_bound_term] = new CAvgGradInc_Flow(nDim, nVar_Flow, false, config); - } - - /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - - if (config->GetBody_Force() == YES) { - if (incompressible) - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceIncBodyForce(nDim, nVar_Flow, config); - else - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceBodyForce(nDim, nVar_Flow, config); - } - else if (incompressible && (config->GetKind_Streamwise_Periodic() != ENUM_STREAMWISE_PERIODIC::NONE)) { - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceIncStreamwise_Periodic(nDim, nVar_Flow, config); - } - else if (incompressible && (config->GetKind_DensityModel() == INC_DENSITYMODEL::BOUSSINESQ)) { - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceBoussinesq(nDim, nVar_Flow, config); - } - else if (config->GetRotating_Frame() == YES) { - if (incompressible) - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceIncRotatingFrame_Flow(nDim, nVar_Flow, config); - else - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceRotatingFrame_Flow(nDim, nVar_Flow, config); - } - else if (config->GetAxisymmetric() == YES) { - if (incompressible) - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceIncAxisymmetric_Flow(nDim, nVar_Flow, config); - else if (ideal_gas) - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceAxisymmetric_Flow(nDim, nVar_Flow, config); - else - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceGeneralAxisymmetric_Flow(nDim, nVar_Flow, config); - } - else if (config->GetGravityForce() == YES) { - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceGravity(nDim, nVar_Flow, config); - } - else if (config->GetWind_Gust() == YES) { - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceWindGust(nDim, nVar_Flow, config); - } - else { - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceNothing(nDim, nVar_Flow, config); - } - - /*--- At the moment it is necessary to have the RHT equation in order to have a volumetric heat source. ---*/ - if (config->AddRadiation()) - numerics[iMGlevel][FLOW_SOL][source_second_term] = new CSourceRadiation(nDim, nVar_Flow, config); - else if ((incompressible && (config->GetKind_Streamwise_Periodic() != ENUM_STREAMWISE_PERIODIC::NONE)) && - (config->GetEnergy_Equation() && !config->GetStreamwise_Periodic_Temperature())) - numerics[iMGlevel][FLOW_SOL][source_second_term] = new CSourceIncStreamwisePeriodic_Outlet(nDim, nVar_Flow, config); - else - numerics[iMGlevel][FLOW_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Flow, config); - } - - } - - /*--- Solver definition for the Potential, Euler, Navier-Stokes NEMO problems ---*/ - - if (NEMO_euler || NEMO_ns) { - - /*--- Definition of the convective scheme for each equation and mesh level ---*/ - switch (config->GetKind_ConvNumScheme_Flow()) { - case NO_CONVECTIVE : - SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_FLOW option.", CURRENT_FUNCTION); - break; - - case SPACE_CENTERED : - if (compressible) { - /*--- Compressible flow ---*/ - switch (config->GetKind_Centered_Flow()) { - case LAX : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentLax_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); break; - default: - SU2_MPI::Error("Invalid centered scheme or not implemented.", CURRENT_FUNCTION); - break; - } - - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][conv_term] = new CCentLax_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwRoe_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - } - break; - case SPACE_UPWIND : - if (compressible) { - /*--- Compressible flow ---*/ - switch (config->GetKind_Upwind_Flow()) { - case ROE: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwRoe_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwRoe_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - } - break; - - case AUSM: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSM_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSM_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - } - break; - - case AUSMPLUSUP2: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSMPLUSUP2_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSMPLUSUP2_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - } - break; - - case MSW: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwMSW_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwMSW_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - } - break; - - case AUSMPWPLUS: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSMPWplus_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSMPWplus_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - } - break; - - default: - SU2_MPI::Error("Invalid upwind scheme or not implemented.", CURRENT_FUNCTION); - break; - } - - } - break; - - default: - SU2_MPI::Error("Invalid convective scheme for the NEMO Euler / Navier-Stokes equations.", CURRENT_FUNCTION); - break; + + /*--- If activated by the compile directive, perform a partition analysis. ---*/ +#if PARTITION + if (!dummy){ + if( fem_solver ) Partition_Analysis_FEM(geometry[MESH_0], config); + else Partition_Analysis(geometry[MESH_0], config); } - - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - if (compressible) { - - numerics[MESH_0][FLOW_SOL][visc_term] = new CAvgGradCorrected_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][visc_term] = new CAvgGrad_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][FLOW_SOL][visc_bound_term] = new CAvgGrad_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); +#endif + + /*--- Check if Euler & Symmetry markers are straight/plane. This information + is used in the Euler & Symmetry boundary routines. ---*/ + if((config_container[iZone]->GetnMarker_Euler() != 0 || + config_container[iZone]->GetnMarker_SymWall() != 0) && + !fem_solver) { + + if (rank == MASTER_NODE) + cout << "Checking if Euler & Symmetry markers are straight/plane:" << endl; + + for (iMesh = 0; iMesh <= config_container[iZone]->GetnMGLevels(); iMesh++) + geometry_container[iZone][iInst][iMesh]->ComputeSurf_Straightness(config_container[iZone], (iMesh==MESH_0) ); + } + +} - /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ +void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geometry) { + + unsigned short iZone = config->GetiZone(), iMGlevel; + unsigned short requestedMGlevels = config->GetnMGLevels(); + const bool fea = config->GetStructuralProblem(); + + /*--- Definition of the geometry class to store the primal grid in the partitioning process. + * All ranks process the grid and call ParMETIS for partitioning ---*/ + + CGeometry *geometry_aux = new CPhysicalGeometry(config, iZone, nZone); + + /*--- Set the dimension --- */ + + nDim = geometry_aux->GetnDim(); + + /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ + + geometry_aux->SetColorGrid_Parallel(config); + + /*--- Allocate the memory of the current domain, and divide the grid + between the ranks. ---*/ + + geometry = new CGeometry *[config->GetnMGLevels()+1] (); + + /*--- Build the grid data structures using the ParMETIS coloring. ---*/ + + geometry[MESH_0] = new CPhysicalGeometry(geometry_aux, config); + + /*--- Deallocate the memory of geometry_aux and solver_aux ---*/ + + delete geometry_aux; + + /*--- Add the Send/Receive boundaries ---*/ + geometry[MESH_0]->SetSendReceive(config); + + /*--- Add the Send/Receive boundaries ---*/ + geometry[MESH_0]->SetBoundaries(config); + + /*--- Compute elements surrounding points, points surrounding points ---*/ + + if (rank == MASTER_NODE) cout << "Setting point connectivity." << endl; + geometry[MESH_0]->SetPoint_Connectivity(); + + /*--- Renumbering points using Reverse Cuthill McKee ordering ---*/ + + if (rank == MASTER_NODE) cout << "Renumbering points (Reverse Cuthill McKee Ordering)." << endl; + geometry[MESH_0]->SetRCM_Ordering(config); + + /*--- recompute elements surrounding points, points surrounding points ---*/ + + if (rank == MASTER_NODE) cout << "Recomputing point connectivity." << endl; + geometry[MESH_0]->SetPoint_Connectivity(); + + /*--- Compute elements surrounding elements ---*/ + + if (rank == MASTER_NODE) cout << "Setting element connectivity." << endl; + geometry[MESH_0]->SetElement_Connectivity(); + + /*--- Check the orientation before computing geometrical quantities ---*/ + + geometry[MESH_0]->SetBoundVolume(); + if (config->GetReorientElements()) { + if (rank == MASTER_NODE) cout << "Checking the numerical grid orientation." << endl; + geometry[MESH_0]->Check_IntElem_Orientation(config); + geometry[MESH_0]->Check_BoundElem_Orientation(config); + } + + /*--- Create the edge structure ---*/ + + if (rank == MASTER_NODE) cout << "Identifying edges and vertices." << endl; + geometry[MESH_0]->SetEdges(); + geometry[MESH_0]->SetVertex(config); + + /*--- Create the control volume structures ---*/ + + if (rank == MASTER_NODE) cout << "Setting the control volume structure." << endl; + SU2_OMP_PARALLEL { + geometry[MESH_0]->SetControlVolume(config, ALLOCATE); + geometry[MESH_0]->SetBoundControlVolume(config, ALLOCATE); + } + END_SU2_OMP_PARALLEL + + /*--- Visualize a dual control volume if requested ---*/ + + if ((config->GetVisualize_CV() >= 0) && + (config->GetVisualize_CV() < (long)geometry[MESH_0]->GetGlobal_nPointDomain())) + geometry[MESH_0]->VisualizeControlVolume(config); + + /*--- Identify closest normal neighbor ---*/ + + if (rank == MASTER_NODE) cout << "Searching for the closest normal neighbors to the surfaces." << endl; + geometry[MESH_0]->FindNormal_Neighbor(config); + + /*--- Store the global to local mapping. ---*/ + + if (rank == MASTER_NODE) cout << "Storing a mapping from global to local point index." << endl; + geometry[MESH_0]->SetGlobal_to_Local_Point(); + + /*--- Compute the surface curvature ---*/ + + if (!fea) { + if (rank == MASTER_NODE) cout << "Compute the surface curvature." << endl; + geometry[MESH_0]->ComputeSurf_Curvature(config); + } + + /*--- Check for periodicity and disable MG if necessary. ---*/ + + if (rank == MASTER_NODE) cout << "Checking for periodicity." << endl; + geometry[MESH_0]->Check_Periodicity(config); + + /*--- Compute mesh quality statistics on the fine grid. ---*/ + + if (!fea) { + if (rank == MASTER_NODE) + cout << "Computing mesh quality statistics for the dual control volumes." << endl; + geometry[MESH_0]->ComputeMeshQualityStatistics(config); + } + + geometry[MESH_0]->SetMGLevel(MESH_0); + if ((config->GetnMGLevels() != 0) && (rank == MASTER_NODE)) + cout << "Setting the multigrid structure." << endl; + + /*--- Loop over all the new grid ---*/ + + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + + /*--- Create main agglomeration structure ---*/ + + geometry[iMGlevel] = new CMultiGridGeometry(geometry[iMGlevel-1], config, iMGlevel); + + /*--- Compute points surrounding points. ---*/ + + geometry[iMGlevel]->SetPoint_Connectivity(geometry[iMGlevel-1]); + + /*--- Create the edge structure ---*/ + + geometry[iMGlevel]->SetEdges(); + geometry[iMGlevel]->SetVertex(geometry[iMGlevel-1], config); + + /*--- Create the control volume structures ---*/ + + geometry[iMGlevel]->SetControlVolume(geometry[iMGlevel-1], ALLOCATE); + geometry[iMGlevel]->SetBoundControlVolume(geometry[iMGlevel-1], ALLOCATE); + geometry[iMGlevel]->SetCoord(geometry[iMGlevel-1]); + + /*--- Find closest neighbor to a surface point ---*/ + + geometry[iMGlevel]->FindNormal_Neighbor(config); + + /*--- Store our multigrid index. ---*/ + + geometry[iMGlevel]->SetMGLevel(iMGlevel); + + /*--- Protect against the situation that we were not able to complete + the agglomeration for this level, i.e., there weren't enough points. + We need to check if we changed the total number of levels and delete + the incomplete CMultiGridGeometry object. ---*/ + + if (config->GetnMGLevels() != requestedMGlevels) { + delete geometry[iMGlevel]; + geometry[iMGlevel] = nullptr; + break; + } + + } + + if (config->GetWrt_MultiGrid()) geometry[MESH_0]->ColorMGLevels(config->GetnMGLevels(), geometry); + + /*--- For unsteady simulations, initialize the grid volumes + and coordinates for previous solutions. Loop over all zones/grids ---*/ + + if ((config->GetTime_Marching() != TIME_MARCHING::STEADY) && config->GetDynamic_Grid()) { + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + + /*--- Update cell volume ---*/ + geometry[iMGlevel]->nodes->SetVolume_n(); + geometry[iMGlevel]->nodes->SetVolume_nM1(); + + if (config->GetGrid_Movement()) { + /*--- Update point coordinates ---*/ + geometry[iMGlevel]->nodes->SetCoord_n(); + geometry[iMGlevel]->nodes->SetCoord_n1(); + } + } + } + + + /*--- Create the data structure for MPI point-to-point communications. ---*/ + + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + geometry[iMGlevel]->PreprocessP2PComms(geometry[iMGlevel], config); + + + /*--- Perform a few preprocessing routines and communications. ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - - numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSource_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); - numerics[iMGlevel][FLOW_SOL][source_second_term] = new CSourceNothing(nDim, nVar_NEMO, config); + + /*--- Compute the max length. ---*/ + + if (!fea) { + if ((rank == MASTER_NODE) && (iMGlevel == MESH_0)) + cout << "Finding max control volume width." << endl; + geometry[iMGlevel]->SetMaxLength(config); + } + + /*--- Communicate the number of neighbors. This is needed for + some centered schemes and for multigrid in parallel. ---*/ + + if ((rank == MASTER_NODE) && (size > SINGLE_NODE) && (iMGlevel == MESH_0)) + cout << "Communicating number of neighbors." << endl; + geometry[iMGlevel]->InitiateComms(geometry[iMGlevel], config, NEIGHBORS); + geometry[iMGlevel]->CompleteComms(geometry[iMGlevel], config, NEIGHBORS); } - } + +} - /*--- Riemann solver definition for the Euler, Navier-Stokes problems for the FEM discretization. ---*/ - if ((fem_euler) || (fem_ns)) { +void CDriver::Geometrical_Preprocessing_DGFEM(CConfig* config, CGeometry **&geometry) { + + /*--- Definition of the geometry class to store the primal grid in the partitioning process. ---*/ + /*--- All ranks process the grid and call ParMETIS for partitioning ---*/ + + CGeometry *geometry_aux = new CPhysicalGeometry(config, iZone, nZone); + + /*--- Set the dimension --- */ + + nDim = geometry_aux->GetnDim(); + + /*--- For the FEM solver with time-accurate local time-stepping, use + a dummy solver class to retrieve the initial flow state. ---*/ + + CSolver *solver_aux = new CFEM_DG_EulerSolver(config, nDim, MESH_0); + + /*--- Color the initial grid and set the send-receive domains (ParMETIS) ---*/ + + geometry_aux->SetColorFEMGrid_Parallel(config); + + /*--- Allocate the memory of the current domain, and divide the grid + between the ranks. ---*/ + + geometry = new CGeometry *[config->GetnMGLevels()+1] (); + + geometry[MESH_0] = new CMeshFEM_DG(geometry_aux, config); + + /*--- Deallocate the memory of geometry_aux and solver_aux ---*/ + + delete geometry_aux; + delete solver_aux; + + /*--- Add the Send/Receive boundaries ---*/ + geometry[MESH_0]->SetSendReceive(config); + + /*--- Add the Send/Receive boundaries ---*/ + geometry[MESH_0]->SetBoundaries(config); + + /*--- Carry out a dynamic cast to CMeshFEM_DG, such that it is not needed to + define all virtual functions in the base class CGeometry. ---*/ + CMeshFEM_DG *DGMesh = dynamic_cast(geometry[MESH_0]); + + /*--- Determine the standard elements for the volume elements. ---*/ + if (rank == MASTER_NODE) cout << "Creating standard volume elements." << endl; + DGMesh->CreateStandardVolumeElements(config); + + /*--- Create the face information needed to compute the contour integral + for the elements in the Discontinuous Galerkin formulation. ---*/ + if (rank == MASTER_NODE) cout << "Creating face information." << endl; + DGMesh->CreateFaces(config); + + /*--- Compute the metric terms of the volume elements. ---*/ + if (rank == MASTER_NODE) cout << "Computing metric terms volume elements." << endl; + DGMesh->MetricTermsVolumeElements(config); + + /*--- Compute the metric terms of the surface elements. ---*/ + if (rank == MASTER_NODE) cout << "Computing metric terms surface elements." << endl; + DGMesh->MetricTermsSurfaceElements(config); + + /*--- Compute a length scale of the volume elements. ---*/ + if (rank == MASTER_NODE) cout << "Computing length scale volume elements." << endl; + DGMesh->LengthScaleVolumeElements(); + + /*--- Compute the coordinates of the integration points. ---*/ + if (rank == MASTER_NODE) cout << "Computing coordinates of the integration points." << endl; + DGMesh->CoordinatesIntegrationPoints(); + + /*--- Compute the coordinates of the location of the solution DOFs. This is different + from the grid points when a different polynomial degree is used to represent the + geometry and solution. ---*/ + if (rank == MASTER_NODE) cout << "Computing coordinates of the solution DOFs." << endl; + DGMesh->CoordinatesSolDOFs(); + + /*--- Perform the preprocessing tasks when wall functions are used. ---*/ + if (rank == MASTER_NODE) cout << "Preprocessing for the wall functions. " << endl; + DGMesh->WallFunctionPreprocessing(config); + + /*--- Store the global to local mapping. ---*/ + if (rank == MASTER_NODE) cout << "Storing a mapping from global to local DOF index." << endl; + geometry[MESH_0]->SetGlobal_to_Local_Point(); + + + /*--- Loop to create the coarser grid levels. ---*/ + + for(unsigned short iMGlevel=1; iMGlevel<=config->GetnMGLevels(); iMGlevel++) { + + SU2_MPI::Error("Geometrical_Preprocessing_DGFEM: Coarse grid levels not implemented yet.", + CURRENT_FUNCTION); + } + +} - switch (config->GetRiemann_Solver_FEM()) { - case ROE: - case LAX_FRIEDRICH: - /* Hard coded optimized implementation is used in the DG solver. No need to allocate the - corresponding entry in numerics. */ - break; +void CDriver::Solver_Preprocessing(CConfig* config, CGeometry** geometry, CSolver ***&solver) { + + MAIN_SOLVER kindSolver = config->GetKind_Solver(); + + if (rank == MASTER_NODE) + cout << endl <<"-------------------- Solver Preprocessing ( Zone " << config->GetiZone() <<" ) --------------------" << endl; + + solver = new CSolver**[config->GetnMGLevels()+1] (); + + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++){ + solver[iMesh] = CSolverFactory::CreateSolverContainer(kindSolver, config, geometry[iMesh], iMesh); + } + + /*--- Count the number of DOFs per solution point. ---*/ + + DOFsPerPoint = 0; + + for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++) + if (solver[MESH_0][iSol]) DOFsPerPoint += solver[MESH_0][iSol]->GetnVar(); + + /*--- Restart solvers, for FSI the geometry cannot be updated because the interpolation classes + * should always use the undeformed mesh (otherwise the results would not be repeatable). ---*/ + + if (!fsi) Solver_Restart(solver, geometry, config, true); + + /*--- Set up any necessary inlet profiles ---*/ + + Inlet_Preprocessing(solver, geometry, config); + +} - case AUSM: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSM_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSM_Flow(nDim, nVar_Flow, config); +void CDriver::Inlet_Preprocessing(CSolver ***solver, CGeometry **geometry, + CConfig *config) const { + + /*--- Adjust iteration number for unsteady restarts. ---*/ + + const bool adjoint = config->GetDiscrete_Adjoint() || config->GetContinuous_Adjoint(); + + int val_iter = 0; + + if (config->GetTime_Domain()) { + val_iter = adjoint? config->GetUnst_AdjointIter() : config->GetRestart_Iter(); + val_iter -= 1; + if (!adjoint && config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND) + val_iter -= 1; + if (!adjoint && !config->GetRestart()) val_iter = 0; + } + + /*--- Load inlet profile files for any of the active solver containers. + Note that these routines fill the fine grid data structures for the markers + and restrict values down to all coarser MG levels. ---*/ + + if (config->GetInlet_Profile_From_File()) { + + /*--- Use LoadInletProfile() routines for the particular solver. ---*/ + + if (rank == MASTER_NODE) { + cout << endl; + cout << "Reading inlet profile from file: "; + cout << config->GetInlet_FileName() << endl; } - break; - - case TURKEL: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwTurkel_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwTurkel_Flow(nDim, nVar_Flow, config); + + if (solver[MESH_0][FLOW_SOL]) { + solver[MESH_0][FLOW_SOL]->LoadInletProfile(geometry, solver, config, val_iter, FLOW_SOL, INLET_FLOW); } - break; - - case HLLC: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwHLLC_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwHLLC_Flow(nDim, nVar_Flow, config); - } - break; - - case MSW: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwMSW_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwMSW_Flow(nDim, nVar_Flow, config); + if (solver[MESH_0][TURB_SOL]) { + solver[MESH_0][TURB_SOL]->LoadInletProfile(geometry, solver, config, val_iter, TURB_SOL, INLET_FLOW); } - break; - - case CUSP: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwCUSP_Flow(nDim, nVar_Flow, config); - numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwCUSP_Flow(nDim, nVar_Flow, config); + if (solver[MESH_0][SPECIES_SOL]) { + solver[MESH_0][SPECIES_SOL]->LoadInletProfile(geometry, solver, config, val_iter, SPECIES_SOL, INLET_FLOW); } - break; - - default: - SU2_MPI::Error("Riemann solver not implemented.", CURRENT_FUNCTION); - break; - } - - } - - /*--- Solver definition for the turbulent model problem ---*/ - - if (turbulent) { - if (incompressible) - InstantiateTurbulentNumerics >(nVar_Turb, offset, config, - solver[MESH_0][TURB_SOL], numerics); - else if (NEMO_ns) - InstantiateTurbulentNumerics >(nVar_Turb, offset, config, - solver[MESH_0][TURB_SOL], numerics); - else - InstantiateTurbulentNumerics >(nVar_Turb, offset, config, - solver[MESH_0][TURB_SOL], numerics); - } - - /*--- Solver definition for the transition model problem ---*/ - if (transition) { - - /*--- Definition of the convective scheme for each equation and mesh level ---*/ - switch (config->GetKind_ConvNumScheme_Turb()) { - case NO_UPWIND: - SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_TURB option.", CURRENT_FUNCTION); - break; - case SPACE_UPWIND: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][TRANS_SOL][conv_term] = new CUpwSca_TransLM(nDim, nVar_Trans, config); + + /*--- Exit if profiles were requested for a solver that is not available. ---*/ + + if (!config->GetFluidProblem()) { + SU2_MPI::Error(string("Inlet profile specification via file (C++) has not been \n") + + string("implemented yet for this solver.\n") + + string("Please set SPECIFIED_INLET_PROFILE= NO and try again."), CURRENT_FUNCTION); + } + + } else { + + /*--- Uniform inlets or python-customized inlets ---*/ + + /* --- Initialize quantities for inlet boundary + * This routine does not check if they python wrapper is being used to + * set custom boundary conditions. This is intentional; the + * default values for python custom BCs are initialized with the default + * values specified in the config (avoiding non physical values) --- */ + + for (unsigned short iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { + for(unsigned short iMarker=0; iMarker < config->GetnMarker_All(); iMarker++) { + if (solver[iMesh][FLOW_SOL]) solver[iMesh][FLOW_SOL]->SetUniformInlet(config, iMarker); + if (solver[iMesh][TURB_SOL]) solver[iMesh][TURB_SOL]->SetUniformInlet(config, iMarker); + if (solver[iMesh][SPECIES_SOL]) solver[iMesh][SPECIES_SOL]->SetUniformInlet(config, iMarker); + } } - break; - default: - SU2_MPI::Error("Invalid convective scheme for the transition equations.", CURRENT_FUNCTION); - break; + } + +} - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][TRANS_SOL][visc_term] = new CAvgGradCorrected_TransLM(nDim, nVar_Trans, config); +void CDriver::Solver_Restart(CSolver ***solver, CGeometry **geometry, + CConfig *config, bool update_geo) { + + /*--- Check for restarts and use the LoadRestart() routines. ---*/ + + const bool restart = config->GetRestart(); + const bool restart_flow = config->GetRestart_Flow(); + + /*--- Adjust iteration number for unsteady restarts. ---*/ + + int val_iter = 0; + + const bool adjoint = (config->GetDiscrete_Adjoint() || config->GetContinuous_Adjoint()); + const bool time_domain = config->GetTime_Domain(); + const bool dt_step_2nd = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND) && + !config->GetStructuralProblem() && !config->GetFEMSolver() && + !adjoint && time_domain; + + if (time_domain) { + if (adjoint) val_iter = config->GetUnst_AdjointIter() - 1; + else val_iter = config->GetRestart_Iter() - 1 - dt_step_2nd; + } + + /*--- Restart direct solvers. ---*/ + + if (restart || restart_flow) { + for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) { + auto sol = solver[MESH_0][iSol]; + if (sol && !sol->GetAdjoint()) { + /*--- Note that the mesh solver always loads the most recent file (and not -2). ---*/ + SU2_OMP_PARALLEL_(if(sol->GetHasHybridParallel())) + sol->LoadRestart(geometry, solver, config, val_iter + (iSol==MESH_SOL && dt_step_2nd), update_geo); + END_SU2_OMP_PARALLEL + } + } } - - /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][TRANS_SOL][source_first_term] = new CSourcePieceWise_TransLM(nDim, nVar_Trans, config); - numerics[iMGlevel][TRANS_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Trans, config); + + /*--- Restart adjoint solvers. ---*/ + + if (restart) { + if ((config->GetKind_Solver() == MAIN_SOLVER::TEMPLATE_SOLVER) || + (config->GetKind_Solver() == MAIN_SOLVER::ADJ_RANS && !config->GetFrozen_Visc_Cont())) { + SU2_MPI::Error("A restart capability has not been implemented yet for this solver.\n" + "Please set RESTART_SOL= NO and try again.", CURRENT_FUNCTION); + } + + for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) { + auto sol = solver[MESH_0][iSol]; + if (sol && sol->GetAdjoint()) + sol->LoadRestart(geometry, solver, config, val_iter, update_geo); + } } + +} - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][TRANS_SOL][conv_bound_term] = new CUpwLin_TransLM(nDim, nVar_Trans, config); +void CDriver::Solver_Postprocessing(CSolver ****solver, CGeometry **geometry, + CConfig *config, unsigned short val_iInst) { + + for (int iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++){ + delete solver[val_iInst][iMGlevel][iSol]; + } + delete [] solver[val_iInst][iMGlevel]; } - } - - /*--- Solver definition for the species transport problem ---*/ - - if (species) { - if (incompressible) - InstantiateSpeciesNumerics >(nVar_Species, offset, config, - solver[MESH_0][SPECIES_SOL], numerics); - else if (compressible) - InstantiateSpeciesNumerics >(nVar_Species, offset, config, - solver[MESH_0][SPECIES_SOL], numerics); - else - SU2_MPI::Error("Species transport only available for standard compressible and incompressible flow.", CURRENT_FUNCTION); - } - - /*--- Solver definition of the finite volume heat solver ---*/ - if (heat) { - - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + delete [] solver[val_iInst]; + + CSolverFactory::ClearSolverMeta(); + +} - numerics[iMGlevel][HEAT_SOL][visc_term] = new CAvgGrad_Heat(nDim, nVar_Heat, config, true); - numerics[iMGlevel][HEAT_SOL][visc_bound_term] = new CAvgGrad_Heat(nDim, nVar_Heat, config, false); +void CDriver::Integration_Preprocessing(CConfig *config, CSolver **solver, CIntegration **&integration) const { + + if (rank == MASTER_NODE) + cout << endl <<"----------------- Integration Preprocessing ( Zone " << config->GetiZone() <<" ) ------------------" << endl; + + MAIN_SOLVER kindMainSolver = config->GetKind_Solver(); + + integration = CIntegrationFactory::CreateIntegrationContainer(kindMainSolver, solver); + +} - switch (config->GetKind_ConvNumScheme_Heat()) { +void CDriver::Integration_Postprocessing(CIntegration ***integration, CGeometry **geometry, CConfig *config, unsigned short val_iInst) { + + for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++){ + delete integration[val_iInst][iSol]; + } + + delete [] integration[val_iInst]; + +} +template +void CDriver::InstantiateTurbulentNumerics(unsigned short nVar_Turb, int offset, const CConfig *config, + const CSolver* turb_solver, CNumerics ****&numerics) const { + const int conv_term = CONV_TERM + offset; + const int visc_term = VISC_TERM + offset; + + const int source_first_term = SOURCE_FIRST_TERM + offset; + const int source_second_term = SOURCE_SECOND_TERM + offset; + + const int conv_bound_term = CONV_BOUND_TERM + offset; + const int visc_bound_term = VISC_BOUND_TERM + offset; + + bool spalart_allmaras, neg_spalart_allmaras, e_spalart_allmaras, comp_spalart_allmaras, e_comp_spalart_allmaras, menter_sst; + spalart_allmaras = neg_spalart_allmaras = e_spalart_allmaras = comp_spalart_allmaras = e_comp_spalart_allmaras = menter_sst = false; + + /*--- Assign turbulence model booleans ---*/ + + switch (config->GetKind_Turb_Model()) { + case TURB_MODEL::NONE: + SU2_MPI::Error("No turbulence model selected.", CURRENT_FUNCTION); + break; + case TURB_MODEL::SA: spalart_allmaras = true; break; + case TURB_MODEL::SA_NEG: neg_spalart_allmaras = true; break; + case TURB_MODEL::SA_E: e_spalart_allmaras = true; break; + case TURB_MODEL::SA_COMP: comp_spalart_allmaras = true; break; + case TURB_MODEL::SA_E_COMP: e_comp_spalart_allmaras = true; break; + case TURB_MODEL::SST: menter_sst = true; break; + case TURB_MODEL::SST_SUST: menter_sst = true; break; + } + + /*--- If the Menter SST model is used, store the constants of the model and determine the + free stream values of the turbulent kinetic energy and dissipation rate. ---*/ + + const su2double *constants = nullptr; + su2double kine_Inf = 0.0, omega_Inf = 0.0; + + if (menter_sst) { + constants = turb_solver->GetConstants(); + kine_Inf = turb_solver->GetTke_Inf(); + omega_Inf = turb_solver->GetOmega_Inf(); + } + + /*--- Definition of the convective scheme for each equation and mesh level ---*/ + + switch (config->GetKind_ConvNumScheme_Turb()) { + case NO_UPWIND: + SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_TURB option.", CURRENT_FUNCTION); + break; case SPACE_UPWIND : - numerics[iMGlevel][HEAT_SOL][conv_term] = new CUpwSca_Heat(nDim, nVar_Heat, config); - numerics[iMGlevel][HEAT_SOL][conv_bound_term] = new CUpwSca_Heat(nDim, nVar_Heat, config); - break; - - case SPACE_CENTERED : - numerics[iMGlevel][HEAT_SOL][conv_term] = new CCentSca_Heat(nDim, nVar_Heat, config); - numerics[iMGlevel][HEAT_SOL][conv_bound_term] = new CUpwSca_Heat(nDim, nVar_Heat, config); - break; - + for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + if (spalart_allmaras || neg_spalart_allmaras || e_spalart_allmaras || comp_spalart_allmaras || e_comp_spalart_allmaras) { + numerics[iMGlevel][TURB_SOL][conv_term] = new CUpwSca_TurbSA(nDim, nVar_Turb, config); + } + else if (menter_sst) numerics[iMGlevel][TURB_SOL][conv_term] = new CUpwSca_TurbSST(nDim, nVar_Turb, config); + } + break; default: - SU2_MPI::Error("Invalid convective scheme for the heat transfer equations.", CURRENT_FUNCTION); - break; - } + SU2_MPI::Error("Invalid convective scheme for the turbulence equations.", CURRENT_FUNCTION); + break; } - } - - /*--- Solver definition for the radiation model problem ---*/ - - if (config->AddRadiation()) { + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - numerics[MESH_0][RAD_SOL][VISC_TERM] = new CAvgGradCorrected_P1(nDim, nVar_Rad, config); - + + for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + if (spalart_allmaras || e_spalart_allmaras || comp_spalart_allmaras || e_comp_spalart_allmaras) { + numerics[iMGlevel][TURB_SOL][visc_term] = new CAvgGrad_TurbSA(nDim, nVar_Turb, true, config); + } + else if (neg_spalart_allmaras) + numerics[iMGlevel][TURB_SOL][visc_term] = new CAvgGrad_TurbSA_Neg(nDim, nVar_Turb, true, config); + else if (menter_sst) + numerics[iMGlevel][TURB_SOL][visc_term] = new CAvgGrad_TurbSST(nDim, nVar_Turb, constants, true, config); + } + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ - numerics[MESH_0][RAD_SOL][SOURCE_FIRST_TERM] = new CSourceP1(nDim, nVar_Rad, config); - + + for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + auto& turb_source_first_term = numerics[iMGlevel][TURB_SOL][source_first_term]; + + if (spalart_allmaras) + turb_source_first_term = new CSourcePieceWise_TurbSA(nDim, nVar_Turb, config); + else if (e_spalart_allmaras) + turb_source_first_term = new CSourcePieceWise_TurbSA_E(nDim, nVar_Turb, config); + else if (comp_spalart_allmaras) + turb_source_first_term = new CSourcePieceWise_TurbSA_COMP(nDim, nVar_Turb, config); + else if (e_comp_spalart_allmaras) + turb_source_first_term = new CSourcePieceWise_TurbSA_E_COMP(nDim, nVar_Turb, config); + else if (neg_spalart_allmaras) + turb_source_first_term = new CSourcePieceWise_TurbSA_Neg(nDim, nVar_Turb, config); + else if (menter_sst) + turb_source_first_term = new CSourcePieceWise_TurbSST(nDim, nVar_Turb, constants, kine_Inf, omega_Inf, + config); + + numerics[iMGlevel][TURB_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Turb, config); + } + /*--- Definition of the boundary condition method ---*/ - numerics[MESH_0][RAD_SOL][VISC_BOUND_TERM] = new CAvgGradCorrected_P1(nDim, nVar_Rad, config); - } - - /*--- Solver definition for the flow adjoint problem ---*/ - - if (adj_euler || adj_ns) { - - if (incompressible) - SU2_MPI::Error("Convective schemes not implemented for incompressible continuous adjoint.", CURRENT_FUNCTION); - - /*--- Definition of the convective scheme for each equation and mesh level ---*/ - - switch (config->GetKind_ConvNumScheme_AdjFlow()) { - case NO_CONVECTIVE: - SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_ADJFLOW option.", CURRENT_FUNCTION); - break; - - case SPACE_CENTERED : - - if (compressible) { - - /*--- Compressible flow ---*/ - - switch (config->GetKind_Centered_AdjFlow()) { - case LAX : numerics[MESH_0][ADJFLOW_SOL][conv_term] = new CCentLax_AdjFlow(nDim, nVar_Adj_Flow, config); break; - case JST : numerics[MESH_0][ADJFLOW_SOL][conv_term] = new CCentJST_AdjFlow(nDim, nVar_Adj_Flow, config); break; - default: - SU2_MPI::Error("Centered scheme not implemented.", CURRENT_FUNCTION); - break; - } - - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][ADJFLOW_SOL][conv_term] = new CCentLax_AdjFlow(nDim, nVar_Adj_Flow, config); - - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][ADJFLOW_SOL][conv_bound_term] = new CUpwRoe_AdjFlow(nDim, nVar_Adj_Flow, config); - + + for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + if (spalart_allmaras || e_spalart_allmaras || comp_spalart_allmaras || e_comp_spalart_allmaras) { + numerics[iMGlevel][TURB_SOL][conv_bound_term] = new CUpwSca_TurbSA(nDim, nVar_Turb, config); + numerics[iMGlevel][TURB_SOL][visc_bound_term] = new CAvgGrad_TurbSA(nDim, nVar_Turb, false, config); } - break; - - case SPACE_UPWIND : - - if (compressible) { - - /*--- Compressible flow ---*/ - - switch (config->GetKind_Upwind_AdjFlow()) { - case ROE: - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][ADJFLOW_SOL][conv_term] = new CUpwRoe_AdjFlow(nDim, nVar_Adj_Flow, config); - numerics[iMGlevel][ADJFLOW_SOL][conv_bound_term] = new CUpwRoe_AdjFlow(nDim, nVar_Adj_Flow, config); - } - break; - default: - SU2_MPI::Error("Upwind scheme not implemented.", CURRENT_FUNCTION); - break; - } + else if (neg_spalart_allmaras) { + numerics[iMGlevel][TURB_SOL][conv_bound_term] = new CUpwSca_TurbSA(nDim, nVar_Turb, config); + numerics[iMGlevel][TURB_SOL][visc_bound_term] = new CAvgGrad_TurbSA_Neg(nDim, nVar_Turb, false, config); + } + else if (menter_sst) { + numerics[iMGlevel][TURB_SOL][conv_bound_term] = new CUpwSca_TurbSST(nDim, nVar_Turb, config); + numerics[iMGlevel][TURB_SOL][visc_bound_term] = new CAvgGrad_TurbSST(nDim, nVar_Turb, constants, false, + config); } - break; - - default: - SU2_MPI::Error("Invalid convective scheme for the continuous adjoint Euler / Navier-Stokes equations.", CURRENT_FUNCTION); - break; } +} +/*--- Explicit instantiation of the template above, needed because it is defined in a cpp file, instead of hpp. ---*/ +template void CDriver::InstantiateTurbulentNumerics>( + unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - - if (compressible) { - - /*--- Compressible flow ---*/ - - numerics[MESH_0][ADJFLOW_SOL][visc_term] = new CAvgGradCorrected_AdjFlow(nDim, nVar_Adj_Flow, config); - numerics[MESH_0][ADJFLOW_SOL][visc_bound_term] = new CAvgGrad_AdjFlow(nDim, nVar_Adj_Flow, config); +template void CDriver::InstantiateTurbulentNumerics>( + unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][ADJFLOW_SOL][visc_term] = new CAvgGrad_AdjFlow(nDim, nVar_Adj_Flow, config); - numerics[iMGlevel][ADJFLOW_SOL][visc_bound_term] = new CAvgGrad_AdjFlow(nDim, nVar_Adj_Flow, config); - } +template void CDriver::InstantiateTurbulentNumerics>( + unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; +template +void CDriver::InstantiateSpeciesNumerics(unsigned short nVar_Species, int offset, const CConfig *config, + const CSolver* species_solver, CNumerics ****&numerics) const { + const int conv_term = CONV_TERM + offset; + const int visc_term = VISC_TERM + offset; + + const int source_first_term = SOURCE_FIRST_TERM + offset; + const int source_second_term = SOURCE_SECOND_TERM + offset; + + const int conv_bound_term = CONV_BOUND_TERM + offset; + const int visc_bound_term = VISC_BOUND_TERM + offset; + + /*--- Definition of the convective scheme for each equation and mesh level. Also for boundary conditions. ---*/ + + switch (config->GetKind_ConvNumScheme_Species()) { + case NONE : + break; + case SPACE_UPWIND : + for (auto iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][SPECIES_SOL][conv_term] = new CUpwSca_Species(nDim, nVar_Species, config); + numerics[iMGlevel][SPECIES_SOL][conv_bound_term] = new CUpwSca_Species(nDim, nVar_Species, config); + } + break; + default : + SU2_MPI::Error("Invalid convective scheme for the species transport equations. Use SCALAR_UPWIND.", CURRENT_FUNCTION); + break; } - + + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + + for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][SPECIES_SOL][visc_term] = new CAvgGrad_Species(nDim, nVar_Species, true, config); + numerics[iMGlevel][SPECIES_SOL][visc_bound_term] = new CAvgGrad_Species(nDim, nVar_Species, false, config); + } + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ - - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - - /*--- Note that RANS is incompatible with Axisymmetric or Rotational (Fix it!) ---*/ - - if (compressible) { - - if (adj_ns) { - - numerics[iMGlevel][ADJFLOW_SOL][source_first_term] = new CSourceViscous_AdjFlow(nDim, nVar_Adj_Flow, config); - - if (config->GetRotating_Frame() == YES) - numerics[iMGlevel][ADJFLOW_SOL][source_second_term] = new CSourceRotatingFrame_AdjFlow(nDim, nVar_Adj_Flow, config); - else - numerics[iMGlevel][ADJFLOW_SOL][source_second_term] = new CSourceConservative_AdjFlow(nDim, nVar_Adj_Flow, config); - + + for (auto iMGlevel = 0u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + if (config->GetAxisymmetric() == YES) { + numerics[iMGlevel][SPECIES_SOL][source_first_term] = new CSourceAxisymmetric_Species(nDim, nVar_Species, config); } - else { - - if (config->GetRotating_Frame() == YES) - numerics[iMGlevel][ADJFLOW_SOL][source_first_term] = new CSourceRotatingFrame_AdjFlow(nDim, nVar_Adj_Flow, config); - else if (config->GetAxisymmetric() == YES) - numerics[iMGlevel][ADJFLOW_SOL][source_first_term] = new CSourceAxisymmetric_AdjFlow(nDim, nVar_Adj_Flow, config); - else - numerics[iMGlevel][ADJFLOW_SOL][source_first_term] = new CSourceNothing(nDim, nVar_Adj_Flow, config); - - numerics[iMGlevel][ADJFLOW_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Adj_Flow, config); - + numerics[iMGlevel][SPECIES_SOL][source_first_term] = new CSourceNothing(nDim, nVar_Species, config); } - - } - - } - - } - - /*--- Solver definition for the turbulent adjoint problem ---*/ - if (adj_turb) { - - if (config->GetKind_Turb_Model() != TURB_MODEL::SA) - SU2_MPI::Error("Only the SA turbulence model can be used with the continuous adjoint solver.", CURRENT_FUNCTION); - - /*--- Definition of the convective scheme for each equation and mesh level ---*/ - switch (config->GetKind_ConvNumScheme_AdjTurb()) { - case NO_CONVECTIVE: - SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_ADJTURB option.", CURRENT_FUNCTION); - break; - case SPACE_UPWIND : - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][ADJTURB_SOL][conv_term] = new CUpwSca_AdjTurb(nDim, nVar_Adj_Turb, config); - break; - default: - SU2_MPI::Error("Convective scheme not implemented (adjoint turbulence).", CURRENT_FUNCTION); - break; - } - - /*--- Definition of the viscous scheme for each equation and mesh level ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][ADJTURB_SOL][visc_term] = new CAvgGradCorrected_AdjTurb(nDim, nVar_Adj_Turb, config); - - /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - numerics[iMGlevel][ADJTURB_SOL][source_first_term] = new CSourcePieceWise_AdjTurb(nDim, nVar_Adj_Turb, config); - numerics[iMGlevel][ADJTURB_SOL][source_second_term] = new CSourceConservative_AdjTurb(nDim, nVar_Adj_Turb, config); + numerics[iMGlevel][SPECIES_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Species, config); } +} +/*--- Explicit instantiation of the template above, needed because it is defined in a cpp file, instead of hpp. ---*/ +template void CDriver::InstantiateSpeciesNumerics>( + unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - /*--- Definition of the boundary condition method ---*/ - for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) - numerics[iMGlevel][ADJTURB_SOL][conv_bound_term] = new CUpwLin_AdjTurb(nDim, nVar_Adj_Turb, config); - - } +template void CDriver::InstantiateSpeciesNumerics>( + unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - /*--- Numerics definition for FEM-like problems. ---*/ +template void CDriver::InstantiateSpeciesNumerics>( + unsigned short, int, const CConfig*, const CSolver*, CNumerics****&) const; - if (fem) { - /*--- Initialize the container for FEA_TERM. This will be the only one for most of the cases. ---*/ - switch (config->GetGeometricConditions()) { - case STRUCT_DEFORMATION::SMALL: - switch (config->GetMaterialModel()) { - case STRUCT_MODEL::LINEAR_ELASTIC: - numerics[MESH_0][FEA_SOL][fea_term] = new CFEALinearElasticity(nDim, nVar_FEM, config); - break; - default: - SU2_MPI::Error("Material model does not correspond to geometric conditions.", CURRENT_FUNCTION); +void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSolver ***solver, CNumerics ****&numerics) const { + + if (rank == MASTER_NODE) + cout << endl <<"------------------- Numerics Preprocessing ( Zone " << config->GetiZone() <<" ) -------------------" << endl; + + unsigned short iMGlevel, iSol, + + nVar_Template = 0, + nVar_Flow = 0, + nVar_NEMO = 0, + nPrimVar_NEMO = 0, + nPrimVarGrad_NEMO = 0, + nVar_Trans = 0, + nVar_Turb = 0, + nVar_Species = 0, + nVar_Adj_Flow = 0, + nVar_Adj_Turb = 0, + nVar_FEM = 0, + nVar_Rad = 0, + nVar_Heat = 0; + + numerics = new CNumerics***[config->GetnMGLevels()+1] (); + + bool compressible = false; + bool incompressible = false; + bool ideal_gas = (config->GetKind_FluidModel() == STANDARD_AIR) || (config->GetKind_FluidModel() == IDEAL_GAS); + bool roe_low_dissipation = (config->GetKind_RoeLowDiss() != NO_ROELOWDISS); + + /*--- Initialize some useful booleans ---*/ + bool euler, ns, NEMO_euler, NEMO_ns, turbulent, adj_euler, adj_ns, adj_turb, fem_euler, fem_ns; + bool fem, heat, transition, template_solver; + + euler = ns = NEMO_euler = NEMO_ns = turbulent = adj_euler = adj_ns = adj_turb = fem_euler = fem_ns = false; + fem = heat = transition = template_solver = false; + bool species = false; + + /*--- Assign booleans ---*/ + switch (config->GetKind_Solver()) { + case MAIN_SOLVER::TEMPLATE_SOLVER: + template_solver = true; break; + + case MAIN_SOLVER::EULER: + case MAIN_SOLVER::DISC_ADJ_EULER: + euler = compressible = true; break; + + case MAIN_SOLVER::NAVIER_STOKES: + case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: + ns = compressible = true; + species = (config->GetKind_Species_Model() != SPECIES_MODEL::NONE); break; + + case MAIN_SOLVER::NEMO_EULER: + NEMO_euler = compressible = true; break; + + case MAIN_SOLVER::NEMO_NAVIER_STOKES: + NEMO_ns = compressible = true; break; + + case MAIN_SOLVER::RANS: + case MAIN_SOLVER::DISC_ADJ_RANS: + ns = compressible = turbulent = true; + transition = (config->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM); + species = config->GetKind_Species_Model() != SPECIES_MODEL::NONE; break; + + case MAIN_SOLVER::INC_EULER: + case MAIN_SOLVER::DISC_ADJ_INC_EULER: + euler = incompressible = true; break; + + case MAIN_SOLVER::INC_NAVIER_STOKES: + case MAIN_SOLVER::DISC_ADJ_INC_NAVIER_STOKES: + ns = incompressible = true; + heat = config->GetWeakly_Coupled_Heat(); + species = (config->GetKind_Species_Model() != SPECIES_MODEL::NONE); break; + + case MAIN_SOLVER::INC_RANS: + case MAIN_SOLVER::DISC_ADJ_INC_RANS: + ns = incompressible = turbulent = true; + heat = config->GetWeakly_Coupled_Heat(); + transition = (config->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM); + species = (config->GetKind_Species_Model() != SPECIES_MODEL::NONE); break; + + case MAIN_SOLVER::FEM_EULER: + case MAIN_SOLVER::DISC_ADJ_FEM_EULER: + fem_euler = compressible = true; break; + + case MAIN_SOLVER::FEM_NAVIER_STOKES: + case MAIN_SOLVER::DISC_ADJ_FEM_NS: + fem_ns = compressible = true; break; + + case MAIN_SOLVER::FEM_RANS: + case MAIN_SOLVER::DISC_ADJ_FEM_RANS: + fem_ns = compressible = true; break; + + case MAIN_SOLVER::FEM_LES: + fem_ns = compressible = true; break; + + case MAIN_SOLVER::HEAT_EQUATION: + case MAIN_SOLVER::DISC_ADJ_HEAT: + heat = true; break; + + case MAIN_SOLVER::FEM_ELASTICITY: + case MAIN_SOLVER::DISC_ADJ_FEM: + fem = true; break; + + case MAIN_SOLVER::ADJ_EULER: + adj_euler = euler = compressible = true; break; + + case MAIN_SOLVER::ADJ_NAVIER_STOKES: + adj_ns = ns = compressible = true; + turbulent = (config->GetKind_Turb_Model() != TURB_MODEL::NONE); break; + + case MAIN_SOLVER::ADJ_RANS: + adj_ns = ns = compressible = turbulent = true; + adj_turb = !config->GetFrozen_Visc_Cont(); break; + + default: break; + + } + + /*--- Number of variables for the template ---*/ + + if (template_solver) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); + + /*--- Number of variables for direct problem ---*/ + + if (euler) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); + if (ns) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); + if (NEMO_euler) nVar_NEMO = solver[MESH_0][FLOW_SOL]->GetnVar(); + if (NEMO_ns) nVar_NEMO = solver[MESH_0][FLOW_SOL]->GetnVar(); + if (turbulent) nVar_Turb = solver[MESH_0][TURB_SOL]->GetnVar(); + if (transition) nVar_Trans = solver[MESH_0][TRANS_SOL]->GetnVar(); + if (species) nVar_Species = solver[MESH_0][SPECIES_SOL]->GetnVar(); + + if (fem_euler) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); + if (fem_ns) nVar_Flow = solver[MESH_0][FLOW_SOL]->GetnVar(); + + if (fem) nVar_FEM = solver[MESH_0][FEA_SOL]->GetnVar(); + if (heat) nVar_Heat = solver[MESH_0][HEAT_SOL]->GetnVar(); + + if (config->AddRadiation()) nVar_Rad = solver[MESH_0][RAD_SOL]->GetnVar(); + + /*--- Number of variables for adjoint problem ---*/ + + if (adj_euler) nVar_Adj_Flow = solver[MESH_0][ADJFLOW_SOL]->GetnVar(); + if (adj_ns) nVar_Adj_Flow = solver[MESH_0][ADJFLOW_SOL]->GetnVar(); + if (adj_turb) nVar_Adj_Turb = solver[MESH_0][ADJTURB_SOL]->GetnVar(); + + /*--- Additional Variables required for NEMO solver ---*/ + + if (NEMO_euler || NEMO_ns) nPrimVar_NEMO = solver[MESH_0][FLOW_SOL]->GetnPrimVar(); + if (NEMO_euler || NEMO_ns) nPrimVarGrad_NEMO = solver[MESH_0][FLOW_SOL]->GetnPrimVarGrad(); + + /*--- Definition of the Class for the numerical method: + numerics_container[INSTANCE_LEVEL][MESH_LEVEL][EQUATION][EQ_TERM] ---*/ + + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel] = new CNumerics** [MAX_SOLS]; + for (iSol = 0; iSol < MAX_SOLS; iSol++) + numerics[iMGlevel][iSol] = new CNumerics* [MAX_TERMS*omp_get_max_threads()](); + } + + /*--- Instantiate one numerics object per thread for each required term. ---*/ + + for (int thread = 0; thread < omp_get_max_threads(); ++thread) + { + const int offset = thread * MAX_TERMS; + + const int conv_term = CONV_TERM + offset; + const int visc_term = VISC_TERM + offset; + + const int source_first_term = SOURCE_FIRST_TERM + offset; + const int source_second_term = SOURCE_SECOND_TERM + offset; + + const int conv_bound_term = CONV_BOUND_TERM + offset; + const int visc_bound_term = VISC_BOUND_TERM + offset; + + const int fea_term = FEA_TERM + offset; + + /*--- Solver definition for the template problem ---*/ + if (template_solver) { + + /*--- Definition of the convective scheme for each equation and mesh level ---*/ + switch (config->GetKind_ConvNumScheme_Template()) { + case SPACE_CENTERED : case SPACE_UPWIND : + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][TEMPLATE_SOL][conv_term] = new CConvective_Template(nDim, nVar_Template, config); + break; + default: + SU2_MPI::Error("Convective scheme not implemented (template_solver).", CURRENT_FUNCTION); + break; + } + + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][TEMPLATE_SOL][visc_term] = new CViscous_Template(nDim, nVar_Template, config); + + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][TEMPLATE_SOL][source_first_term] = new CSource_Template(nDim, nVar_Template, config); + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][TEMPLATE_SOL][conv_bound_term] = new CConvective_Template(nDim, nVar_Template, config); + } + } - break; - case STRUCT_DEFORMATION::LARGE: - switch (config->GetMaterialModel()) { - case STRUCT_MODEL::LINEAR_ELASTIC: - SU2_MPI::Error("Material model does not correspond to geometric conditions.", CURRENT_FUNCTION); - break; - case STRUCT_MODEL::NEO_HOOKEAN: - if (config->GetMaterialCompressibility() == STRUCT_COMPRESS::COMPRESSIBLE) { - numerics[MESH_0][FEA_SOL][fea_term] = new CFEM_NeoHookean_Comp(nDim, nVar_FEM, config); - } else { - SU2_MPI::Error("Material model not implemented.", CURRENT_FUNCTION); + + /*--- Solver definition for the Potential, Euler, Navier-Stokes problems ---*/ + if ((euler) || (ns)) { + + /*--- Definition of the convective scheme for each equation and mesh level ---*/ + switch (config->GetKind_ConvNumScheme_Flow()) { + case NO_CONVECTIVE : + SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_FLOW option.", CURRENT_FUNCTION); + break; + + case SPACE_CENTERED : + if (compressible) { + /*--- "conv_term" is not instantiated as all compressible centered schemes are vectorized. ---*/ + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwRoe_Flow(nDim, nVar_Flow, config, false); + + } + if (incompressible) { + /*--- Incompressible flow, use preconditioning method ---*/ + switch (config->GetKind_Centered_Flow()) { + case LAX : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentLaxInc_Flow(nDim, nVar_Flow, config); break; + case JST : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentJSTInc_Flow(nDim, nVar_Flow, config); break; + default: + SU2_MPI::Error("Invalid centered scheme or not implemented.\n Currently, only JST and LAX-FRIEDRICH are available for incompressible flows.", CURRENT_FUNCTION); + break; + } + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][conv_term] = new CCentLaxInc_Flow(nDim, nVar_Flow, config); + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwFDSInc_Flow(nDim, nVar_Flow, config); + + } + break; + case SPACE_UPWIND : + if (compressible) { + /*--- Compressible flow ---*/ + switch (config->GetKind_Upwind_Flow()) { + case ROE: + if (ideal_gas) { + + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwRoe_Flow(nDim, nVar_Flow, config, roe_low_dissipation); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwRoe_Flow(nDim, nVar_Flow, config, false); + } + } else { + + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwGeneralRoe_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwGeneralRoe_Flow(nDim, nVar_Flow, config); + } + } + break; + + case AUSM: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSM_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSM_Flow(nDim, nVar_Flow, config); + } + break; + + case AUSMPLUSUP: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSMPLUSUP_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSMPLUSUP_Flow(nDim, nVar_Flow, config); + } + break; + + case AUSMPLUSUP2: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSMPLUSUP2_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSMPLUSUP2_Flow(nDim, nVar_Flow, config); + } + break; + + case TURKEL: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwTurkel_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwTurkel_Flow(nDim, nVar_Flow, config); + } + break; + + case L2ROE: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwL2Roe_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwL2Roe_Flow(nDim, nVar_Flow, config); + } + break; + case LMROE: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwLMRoe_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwLMRoe_Flow(nDim, nVar_Flow, config); + } + break; + + case SLAU: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwSLAU_Flow(nDim, nVar_Flow, config, roe_low_dissipation); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwSLAU_Flow(nDim, nVar_Flow, config, false); + } + break; + + case SLAU2: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwSLAU2_Flow(nDim, nVar_Flow, config, roe_low_dissipation); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwSLAU2_Flow(nDim, nVar_Flow, config, false); + } + break; + + case HLLC: + if (ideal_gas) { + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwHLLC_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwHLLC_Flow(nDim, nVar_Flow, config); + } + } + else { + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwGeneralHLLC_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwGeneralHLLC_Flow(nDim, nVar_Flow, config); + } + } + break; + + case MSW: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwMSW_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwMSW_Flow(nDim, nVar_Flow, config); + } + break; + + case CUSP: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwCUSP_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwCUSP_Flow(nDim, nVar_Flow, config); + } + break; + + default: + SU2_MPI::Error("Invalid upwind scheme or not implemented.", CURRENT_FUNCTION); + break; + } + + } + if (incompressible) { + /*--- Incompressible flow, use artificial compressibility method ---*/ + switch (config->GetKind_Upwind_Flow()) { + case FDS: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwFDSInc_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwFDSInc_Flow(nDim, nVar_Flow, config); + } + break; + default: + SU2_MPI::Error("Invalid upwind scheme or not implemented.\n Currently, only FDS is available for incompressible flows.", CURRENT_FUNCTION); + break; + } + } + break; + + default: + SU2_MPI::Error("Invalid convective scheme for the Euler / Navier-Stokes equations.", CURRENT_FUNCTION); + break; } - break; - case STRUCT_MODEL::KNOWLES: - if (config->GetMaterialCompressibility() == STRUCT_COMPRESS::NEARLY_INCOMP) { - numerics[MESH_0][FEA_SOL][fea_term] = new CFEM_Knowles_NearInc(nDim, nVar_FEM, config); - } else { - SU2_MPI::Error("Material model not implemented.", CURRENT_FUNCTION); + + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + if (compressible) { + if (ideal_gas) { + + /*--- Compressible flow Ideal gas ---*/ + numerics[MESH_0][FLOW_SOL][visc_term] = new CAvgGrad_Flow(nDim, nVar_Flow, true, config); + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][visc_term] = new CAvgGrad_Flow(nDim, nVar_Flow, false, config); + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][visc_bound_term] = new CAvgGrad_Flow(nDim, nVar_Flow, false, config); + + } else { + + /*--- Compressible flow Real gas ---*/ + numerics[MESH_0][FLOW_SOL][visc_term] = new CGeneralAvgGrad_Flow(nDim, nVar_Flow, true, config); + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][visc_term] = new CGeneralAvgGrad_Flow(nDim, nVar_Flow, false, config); + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][visc_bound_term] = new CGeneralAvgGrad_Flow(nDim, nVar_Flow, false, config); + + } } - break; - case STRUCT_MODEL::IDEAL_DE: - if (config->GetMaterialCompressibility() == STRUCT_COMPRESS::NEARLY_INCOMP) { - numerics[MESH_0][FEA_SOL][fea_term] = new CFEM_IdealDE(nDim, nVar_FEM, config); - } else { - SU2_MPI::Error("Material model not implemented.", CURRENT_FUNCTION); + if (incompressible) { + /*--- Incompressible flow, use preconditioning method ---*/ + numerics[MESH_0][FLOW_SOL][visc_term] = new CAvgGradInc_Flow(nDim, nVar_Flow, true, config); + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][visc_term] = new CAvgGradInc_Flow(nDim, nVar_Flow, false, config); + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][visc_bound_term] = new CAvgGradInc_Flow(nDim, nVar_Flow, false, config); } - break; + + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + + if (config->GetBody_Force() == YES) { + if (incompressible) + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceIncBodyForce(nDim, nVar_Flow, config); + else + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceBodyForce(nDim, nVar_Flow, config); + } + else if (incompressible && (config->GetKind_Streamwise_Periodic() != ENUM_STREAMWISE_PERIODIC::NONE)) { + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceIncStreamwise_Periodic(nDim, nVar_Flow, config); + } + else if (incompressible && (config->GetKind_DensityModel() == INC_DENSITYMODEL::BOUSSINESQ)) { + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceBoussinesq(nDim, nVar_Flow, config); + } + else if (config->GetRotating_Frame() == YES) { + if (incompressible) + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceIncRotatingFrame_Flow(nDim, nVar_Flow, config); + else + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceRotatingFrame_Flow(nDim, nVar_Flow, config); + } + else if (config->GetAxisymmetric() == YES) { + if (incompressible) + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceIncAxisymmetric_Flow(nDim, nVar_Flow, config); + else if (ideal_gas) + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceAxisymmetric_Flow(nDim, nVar_Flow, config); + else + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceGeneralAxisymmetric_Flow(nDim, nVar_Flow, config); + } + else if (config->GetGravityForce() == YES) { + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceGravity(nDim, nVar_Flow, config); + } + else if (config->GetWind_Gust() == YES) { + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceWindGust(nDim, nVar_Flow, config); + } + else { + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSourceNothing(nDim, nVar_Flow, config); + } + + /*--- At the moment it is necessary to have the RHT equation in order to have a volumetric heat source. ---*/ + if (config->AddRadiation()) + numerics[iMGlevel][FLOW_SOL][source_second_term] = new CSourceRadiation(nDim, nVar_Flow, config); + else if ((incompressible && (config->GetKind_Streamwise_Periodic() != ENUM_STREAMWISE_PERIODIC::NONE)) && + (config->GetEnergy_Equation() && !config->GetStreamwise_Periodic_Temperature())) + numerics[iMGlevel][FLOW_SOL][source_second_term] = new CSourceIncStreamwisePeriodic_Outlet(nDim, nVar_Flow, config); + else + numerics[iMGlevel][FLOW_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Flow, config); + } + } - break; - } - - /*--- The following definitions only make sense if we have a non-linear solution. ---*/ - if (config->GetGeometricConditions() == STRUCT_DEFORMATION::LARGE) { - - /*--- This allocates a container for electromechanical effects. ---*/ - - bool de_effects = config->GetDE_Effects(); - if (de_effects) - numerics[MESH_0][FEA_SOL][DE_TERM+offset] = new CFEM_DielectricElastomer(nDim, nVar_FEM, config); - - ifstream properties_file; - - string filename = config->GetFEA_FileName(); - if (nZone > 1) - filename = config->GetMultizone_FileName(filename, iZone, ".dat"); - - properties_file.open(filename.data(), ios::in); - - /*--- In case there is a properties file, containers are allocated for a number of material models. ---*/ - - if (!(properties_file.fail())) { - numerics[MESH_0][FEA_SOL][MAT_NHCOMP+offset] = new CFEM_NeoHookean_Comp(nDim, nVar_FEM, config); - numerics[MESH_0][FEA_SOL][MAT_IDEALDE+offset] = new CFEM_IdealDE(nDim, nVar_FEM, config); - numerics[MESH_0][FEA_SOL][MAT_KNOWLES+offset] = new CFEM_Knowles_NearInc(nDim, nVar_FEM, config); - } - } - } - - /*--- Instantiate the numerics for the mesh solver. ---*/ - if (config->GetDeform_Mesh()) - numerics[MESH_0][MESH_SOL][fea_term] = new CFEAMeshElasticity(nDim, nDim, geometry[MESH_0]->GetnElem(), config); - - } // end "per-thread" allocation loop - + + /*--- Solver definition for the Potential, Euler, Navier-Stokes NEMO problems ---*/ + + if (NEMO_euler || NEMO_ns) { + + /*--- Definition of the convective scheme for each equation and mesh level ---*/ + switch (config->GetKind_ConvNumScheme_Flow()) { + case NO_CONVECTIVE : + SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_FLOW option.", CURRENT_FUNCTION); + break; + + case SPACE_CENTERED : + if (compressible) { + /*--- Compressible flow ---*/ + switch (config->GetKind_Centered_Flow()) { + case LAX : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentLax_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); break; + default: + SU2_MPI::Error("Invalid centered scheme or not implemented.", CURRENT_FUNCTION); + break; + } + + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][conv_term] = new CCentLax_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwRoe_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + } + break; + case SPACE_UPWIND : + if (compressible) { + /*--- Compressible flow ---*/ + switch (config->GetKind_Upwind_Flow()) { + case ROE: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwRoe_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwRoe_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + } + break; + + case AUSM: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSM_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSM_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + } + break; + + case AUSMPLUSUP2: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSMPLUSUP2_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSMPLUSUP2_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + } + break; + + case MSW: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwMSW_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwMSW_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + } + break; + + case AUSMPWPLUS: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSMPWplus_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSMPWplus_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + } + break; + + default: + SU2_MPI::Error("Invalid upwind scheme or not implemented.", CURRENT_FUNCTION); + break; + } + + } + break; + + default: + SU2_MPI::Error("Invalid convective scheme for the NEMO Euler / Navier-Stokes equations.", CURRENT_FUNCTION); + break; + } + + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + if (compressible) { + + numerics[MESH_0][FLOW_SOL][visc_term] = new CAvgGradCorrected_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][visc_term] = new CAvgGrad_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][FLOW_SOL][visc_bound_term] = new CAvgGrad_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + } + + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + + numerics[iMGlevel][FLOW_SOL][source_first_term] = new CSource_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); + numerics[iMGlevel][FLOW_SOL][source_second_term] = new CSourceNothing(nDim, nVar_NEMO, config); + } + } + + /*--- Riemann solver definition for the Euler, Navier-Stokes problems for the FEM discretization. ---*/ + if ((fem_euler) || (fem_ns)) { + + switch (config->GetRiemann_Solver_FEM()) { + case ROE: + case LAX_FRIEDRICH: + /* Hard coded optimized implementation is used in the DG solver. No need to allocate the + corresponding entry in numerics. */ + break; + + case AUSM: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwAUSM_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwAUSM_Flow(nDim, nVar_Flow, config); + } + break; + + case TURKEL: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwTurkel_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwTurkel_Flow(nDim, nVar_Flow, config); + } + break; + + case HLLC: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwHLLC_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwHLLC_Flow(nDim, nVar_Flow, config); + } + break; + + case MSW: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwMSW_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwMSW_Flow(nDim, nVar_Flow, config); + } + break; + + case CUSP: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][FLOW_SOL][conv_term] = new CUpwCUSP_Flow(nDim, nVar_Flow, config); + numerics[iMGlevel][FLOW_SOL][conv_bound_term] = new CUpwCUSP_Flow(nDim, nVar_Flow, config); + } + break; + + default: + SU2_MPI::Error("Riemann solver not implemented.", CURRENT_FUNCTION); + break; + } + + } + + /*--- Solver definition for the turbulent model problem ---*/ + + if (turbulent) { + if (incompressible) + InstantiateTurbulentNumerics >(nVar_Turb, offset, config, + solver[MESH_0][TURB_SOL], numerics); + else if (NEMO_ns) + InstantiateTurbulentNumerics >(nVar_Turb, offset, config, + solver[MESH_0][TURB_SOL], numerics); + else + InstantiateTurbulentNumerics >(nVar_Turb, offset, config, + solver[MESH_0][TURB_SOL], numerics); + } + + /*--- Solver definition for the transition model problem ---*/ + if (transition) { + + /*--- Definition of the convective scheme for each equation and mesh level ---*/ + switch (config->GetKind_ConvNumScheme_Turb()) { + case NO_UPWIND: + SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_TURB option.", CURRENT_FUNCTION); + break; + case SPACE_UPWIND: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][TRANS_SOL][conv_term] = new CUpwSca_TransLM(nDim, nVar_Trans, config); + } + break; + default: + SU2_MPI::Error("Invalid convective scheme for the transition equations.", CURRENT_FUNCTION); + break; + } + + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][TRANS_SOL][visc_term] = new CAvgGradCorrected_TransLM(nDim, nVar_Trans, config); + } + + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][TRANS_SOL][source_first_term] = new CSourcePieceWise_TransLM(nDim, nVar_Trans, config); + numerics[iMGlevel][TRANS_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Trans, config); + } + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][TRANS_SOL][conv_bound_term] = new CUpwLin_TransLM(nDim, nVar_Trans, config); + } + } + + /*--- Solver definition for the species transport problem ---*/ + + if (species) { + if (incompressible) + InstantiateSpeciesNumerics >(nVar_Species, offset, config, + solver[MESH_0][SPECIES_SOL], numerics); + else if (compressible) + InstantiateSpeciesNumerics >(nVar_Species, offset, config, + solver[MESH_0][SPECIES_SOL], numerics); + else + SU2_MPI::Error("Species transport only available for standard compressible and incompressible flow.", CURRENT_FUNCTION); + } + + /*--- Solver definition of the finite volume heat solver ---*/ + if (heat) { + + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + + numerics[iMGlevel][HEAT_SOL][visc_term] = new CAvgGrad_Heat(nDim, nVar_Heat, config, true); + numerics[iMGlevel][HEAT_SOL][visc_bound_term] = new CAvgGrad_Heat(nDim, nVar_Heat, config, false); + + switch (config->GetKind_ConvNumScheme_Heat()) { + + case SPACE_UPWIND : + numerics[iMGlevel][HEAT_SOL][conv_term] = new CUpwSca_Heat(nDim, nVar_Heat, config); + numerics[iMGlevel][HEAT_SOL][conv_bound_term] = new CUpwSca_Heat(nDim, nVar_Heat, config); + break; + + case SPACE_CENTERED : + numerics[iMGlevel][HEAT_SOL][conv_term] = new CCentSca_Heat(nDim, nVar_Heat, config); + numerics[iMGlevel][HEAT_SOL][conv_bound_term] = new CUpwSca_Heat(nDim, nVar_Heat, config); + break; + + default: + SU2_MPI::Error("Invalid convective scheme for the heat transfer equations.", CURRENT_FUNCTION); + break; + } + } + } + + /*--- Solver definition for the radiation model problem ---*/ + + if (config->AddRadiation()) { + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + numerics[MESH_0][RAD_SOL][VISC_TERM] = new CAvgGradCorrected_P1(nDim, nVar_Rad, config); + + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ + numerics[MESH_0][RAD_SOL][SOURCE_FIRST_TERM] = new CSourceP1(nDim, nVar_Rad, config); + + /*--- Definition of the boundary condition method ---*/ + numerics[MESH_0][RAD_SOL][VISC_BOUND_TERM] = new CAvgGradCorrected_P1(nDim, nVar_Rad, config); + } + + /*--- Solver definition for the flow adjoint problem ---*/ + + if (adj_euler || adj_ns) { + + if (incompressible) + SU2_MPI::Error("Convective schemes not implemented for incompressible continuous adjoint.", CURRENT_FUNCTION); + + /*--- Definition of the convective scheme for each equation and mesh level ---*/ + + switch (config->GetKind_ConvNumScheme_AdjFlow()) { + case NO_CONVECTIVE: + SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_ADJFLOW option.", CURRENT_FUNCTION); + break; + + case SPACE_CENTERED : + + if (compressible) { + + /*--- Compressible flow ---*/ + + switch (config->GetKind_Centered_AdjFlow()) { + case LAX : numerics[MESH_0][ADJFLOW_SOL][conv_term] = new CCentLax_AdjFlow(nDim, nVar_Adj_Flow, config); break; + case JST : numerics[MESH_0][ADJFLOW_SOL][conv_term] = new CCentJST_AdjFlow(nDim, nVar_Adj_Flow, config); break; + default: + SU2_MPI::Error("Centered scheme not implemented.", CURRENT_FUNCTION); + break; + } + + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][ADJFLOW_SOL][conv_term] = new CCentLax_AdjFlow(nDim, nVar_Adj_Flow, config); + + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][ADJFLOW_SOL][conv_bound_term] = new CUpwRoe_AdjFlow(nDim, nVar_Adj_Flow, config); + + } + break; + + case SPACE_UPWIND : + + if (compressible) { + + /*--- Compressible flow ---*/ + + switch (config->GetKind_Upwind_AdjFlow()) { + case ROE: + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][ADJFLOW_SOL][conv_term] = new CUpwRoe_AdjFlow(nDim, nVar_Adj_Flow, config); + numerics[iMGlevel][ADJFLOW_SOL][conv_bound_term] = new CUpwRoe_AdjFlow(nDim, nVar_Adj_Flow, config); + } + break; + default: + SU2_MPI::Error("Upwind scheme not implemented.", CURRENT_FUNCTION); + break; + } + } + break; + + default: + SU2_MPI::Error("Invalid convective scheme for the continuous adjoint Euler / Navier-Stokes equations.", CURRENT_FUNCTION); + break; + } + + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + + if (compressible) { + + /*--- Compressible flow ---*/ + + numerics[MESH_0][ADJFLOW_SOL][visc_term] = new CAvgGradCorrected_AdjFlow(nDim, nVar_Adj_Flow, config); + numerics[MESH_0][ADJFLOW_SOL][visc_bound_term] = new CAvgGrad_AdjFlow(nDim, nVar_Adj_Flow, config); + + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][ADJFLOW_SOL][visc_term] = new CAvgGrad_AdjFlow(nDim, nVar_Adj_Flow, config); + numerics[iMGlevel][ADJFLOW_SOL][visc_bound_term] = new CAvgGrad_AdjFlow(nDim, nVar_Adj_Flow, config); + } + + } + + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ + + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + + /*--- Note that RANS is incompatible with Axisymmetric or Rotational (Fix it!) ---*/ + + if (compressible) { + + if (adj_ns) { + + numerics[iMGlevel][ADJFLOW_SOL][source_first_term] = new CSourceViscous_AdjFlow(nDim, nVar_Adj_Flow, config); + + if (config->GetRotating_Frame() == YES) + numerics[iMGlevel][ADJFLOW_SOL][source_second_term] = new CSourceRotatingFrame_AdjFlow(nDim, nVar_Adj_Flow, config); + else + numerics[iMGlevel][ADJFLOW_SOL][source_second_term] = new CSourceConservative_AdjFlow(nDim, nVar_Adj_Flow, config); + + } + + else { + + if (config->GetRotating_Frame() == YES) + numerics[iMGlevel][ADJFLOW_SOL][source_first_term] = new CSourceRotatingFrame_AdjFlow(nDim, nVar_Adj_Flow, config); + else if (config->GetAxisymmetric() == YES) + numerics[iMGlevel][ADJFLOW_SOL][source_first_term] = new CSourceAxisymmetric_AdjFlow(nDim, nVar_Adj_Flow, config); + else + numerics[iMGlevel][ADJFLOW_SOL][source_first_term] = new CSourceNothing(nDim, nVar_Adj_Flow, config); + + numerics[iMGlevel][ADJFLOW_SOL][source_second_term] = new CSourceNothing(nDim, nVar_Adj_Flow, config); + + } + + } + + } + + } + + /*--- Solver definition for the turbulent adjoint problem ---*/ + if (adj_turb) { + + if (config->GetKind_Turb_Model() != TURB_MODEL::SA) + SU2_MPI::Error("Only the SA turbulence model can be used with the continuous adjoint solver.", CURRENT_FUNCTION); + + /*--- Definition of the convective scheme for each equation and mesh level ---*/ + switch (config->GetKind_ConvNumScheme_AdjTurb()) { + case NO_CONVECTIVE: + SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_ADJTURB option.", CURRENT_FUNCTION); + break; + case SPACE_UPWIND : + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][ADJTURB_SOL][conv_term] = new CUpwSca_AdjTurb(nDim, nVar_Adj_Turb, config); + break; + default: + SU2_MPI::Error("Convective scheme not implemented (adjoint turbulence).", CURRENT_FUNCTION); + break; + } + + /*--- Definition of the viscous scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][ADJTURB_SOL][visc_term] = new CAvgGradCorrected_AdjTurb(nDim, nVar_Adj_Turb, config); + + /*--- Definition of the source term integration scheme for each equation and mesh level ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + numerics[iMGlevel][ADJTURB_SOL][source_first_term] = new CSourcePieceWise_AdjTurb(nDim, nVar_Adj_Turb, config); + numerics[iMGlevel][ADJTURB_SOL][source_second_term] = new CSourceConservative_AdjTurb(nDim, nVar_Adj_Turb, config); + } + + /*--- Definition of the boundary condition method ---*/ + for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + numerics[iMGlevel][ADJTURB_SOL][conv_bound_term] = new CUpwLin_AdjTurb(nDim, nVar_Adj_Turb, config); + + } + + /*--- Numerics definition for FEM-like problems. ---*/ + + if (fem) { + /*--- Initialize the container for FEA_TERM. This will be the only one for most of the cases. ---*/ + switch (config->GetGeometricConditions()) { + case STRUCT_DEFORMATION::SMALL: + switch (config->GetMaterialModel()) { + case STRUCT_MODEL::LINEAR_ELASTIC: + numerics[MESH_0][FEA_SOL][fea_term] = new CFEALinearElasticity(nDim, nVar_FEM, config); + break; + default: + SU2_MPI::Error("Material model does not correspond to geometric conditions.", CURRENT_FUNCTION); + break; + } + break; + case STRUCT_DEFORMATION::LARGE: + switch (config->GetMaterialModel()) { + case STRUCT_MODEL::LINEAR_ELASTIC: + SU2_MPI::Error("Material model does not correspond to geometric conditions.", CURRENT_FUNCTION); + break; + case STRUCT_MODEL::NEO_HOOKEAN: + if (config->GetMaterialCompressibility() == STRUCT_COMPRESS::COMPRESSIBLE) { + numerics[MESH_0][FEA_SOL][fea_term] = new CFEM_NeoHookean_Comp(nDim, nVar_FEM, config); + } else { + SU2_MPI::Error("Material model not implemented.", CURRENT_FUNCTION); + } + break; + case STRUCT_MODEL::KNOWLES: + if (config->GetMaterialCompressibility() == STRUCT_COMPRESS::NEARLY_INCOMP) { + numerics[MESH_0][FEA_SOL][fea_term] = new CFEM_Knowles_NearInc(nDim, nVar_FEM, config); + } else { + SU2_MPI::Error("Material model not implemented.", CURRENT_FUNCTION); + } + break; + case STRUCT_MODEL::IDEAL_DE: + if (config->GetMaterialCompressibility() == STRUCT_COMPRESS::NEARLY_INCOMP) { + numerics[MESH_0][FEA_SOL][fea_term] = new CFEM_IdealDE(nDim, nVar_FEM, config); + } else { + SU2_MPI::Error("Material model not implemented.", CURRENT_FUNCTION); + } + break; + } + break; + } + + /*--- The following definitions only make sense if we have a non-linear solution. ---*/ + if (config->GetGeometricConditions() == STRUCT_DEFORMATION::LARGE) { + + /*--- This allocates a container for electromechanical effects. ---*/ + + bool de_effects = config->GetDE_Effects(); + if (de_effects) + numerics[MESH_0][FEA_SOL][DE_TERM+offset] = new CFEM_DielectricElastomer(nDim, nVar_FEM, config); + + ifstream properties_file; + + string filename = config->GetFEA_FileName(); + if (nZone > 1) + filename = config->GetMultizone_FileName(filename, iZone, ".dat"); + + properties_file.open(filename.data(), ios::in); + + /*--- In case there is a properties file, containers are allocated for a number of material models. ---*/ + + if (!(properties_file.fail())) { + numerics[MESH_0][FEA_SOL][MAT_NHCOMP+offset] = new CFEM_NeoHookean_Comp(nDim, nVar_FEM, config); + numerics[MESH_0][FEA_SOL][MAT_IDEALDE+offset] = new CFEM_IdealDE(nDim, nVar_FEM, config); + numerics[MESH_0][FEA_SOL][MAT_KNOWLES+offset] = new CFEM_Knowles_NearInc(nDim, nVar_FEM, config); + } + } + } + + /*--- Instantiate the numerics for the mesh solver. ---*/ + if (config->GetDeform_Mesh()) + numerics[MESH_0][MESH_SOL][fea_term] = new CFEAMeshElasticity(nDim, nDim, geometry[MESH_0]->GetnElem(), config); + + } // end "per-thread" allocation loop + } void CDriver::Numerics_Postprocessing(CNumerics *****numerics, CSolver***, CGeometry**, CConfig *config, unsigned short val_iInst) { - - for (unsigned short iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - - for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++) { - - for (unsigned int iTerm = 0; iTerm < MAX_TERMS*omp_get_max_threads(); iTerm++) { - - delete numerics[val_iInst][iMGlevel][iSol][iTerm]; - } - delete [] numerics[val_iInst][iMGlevel][iSol]; + + for (unsigned short iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { + + for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++) { + + for (unsigned int iTerm = 0; iTerm < MAX_TERMS*omp_get_max_threads(); iTerm++) { + + delete numerics[val_iInst][iMGlevel][iSol][iTerm]; + } + delete [] numerics[val_iInst][iMGlevel][iSol]; + } + delete[] numerics[val_iInst][iMGlevel]; } - delete[] numerics[val_iInst][iMGlevel]; - } - delete[] numerics[val_iInst]; - + delete[] numerics[val_iInst]; + } void CDriver::Iteration_Preprocessing(CConfig* config, CIteration *&iteration) const { - - if (rank == MASTER_NODE) - cout << endl <<"------------------- Iteration Preprocessing ( Zone " << config->GetiZone() <<" ) ------------------" << endl; - - iteration = CIterationFactory::CreateIteration(config->GetKind_Solver(), config); - + + if (rank == MASTER_NODE) + cout << endl <<"------------------- Iteration Preprocessing ( Zone " << config->GetiZone() <<" ) ------------------" << endl; + + iteration = CIterationFactory::CreateIteration(config->GetKind_Solver(), config); + } void CDriver::DynamicMesh_Preprocessing(CConfig *config, CGeometry **geometry, CSolver ***solver, CIteration* iteration, CVolumetricMovement *&grid_movement, CSurfaceMovement *&surface_movement) const{ - - /*--- Instantiate the geometry movement classes for the solution of unsteady - flows on dynamic meshes, including rigid mesh transformations, dynamically - deforming meshes, and preprocessing of harmonic balance. ---*/ - - if (!fem_solver && (config->GetGrid_Movement() || (config->GetDirectDiff() == D_DESIGN))) { - if (rank == MASTER_NODE) - cout << "Setting dynamic mesh structure for zone "<< iZone + 1<<"." << endl; - grid_movement = new CVolumetricMovement(geometry[MESH_0], config); - - surface_movement = new CSurfaceMovement(); - surface_movement->CopyBoundary(geometry[MESH_0], config); - if (config->GetTime_Marching() == TIME_MARCHING::HARMONIC_BALANCE){ - if (rank == MASTER_NODE) cout << endl << "Instance "<< iInst + 1 <<":" << endl; - iteration->SetGrid_Movement(geometry, surface_movement, grid_movement, solver, config, 0, iInst); + + /*--- Instantiate the geometry movement classes for the solution of unsteady + flows on dynamic meshes, including rigid mesh transformations, dynamically + deforming meshes, and preprocessing of harmonic balance. ---*/ + + if (!fem_solver && (config->GetGrid_Movement() || (config->GetDirectDiff() == D_DESIGN))) { + if (rank == MASTER_NODE) + cout << "Setting dynamic mesh structure for zone "<< iZone + 1<<"." << endl; + grid_movement = new CVolumetricMovement(geometry[MESH_0], config); + + surface_movement = new CSurfaceMovement(); + surface_movement->CopyBoundary(geometry[MESH_0], config); + if (config->GetTime_Marching() == TIME_MARCHING::HARMONIC_BALANCE){ + if (rank == MASTER_NODE) cout << endl << "Instance "<< iInst + 1 <<":" << endl; + iteration->SetGrid_Movement(geometry, surface_movement, grid_movement, solver, config, 0, iInst); + } } - } - - if (config->GetDirectDiff() == D_DESIGN) { - if (rank == MASTER_NODE) - cout << "Setting surface/volume derivatives." << endl; - - /*--- Set the surface derivatives, i.e. the derivative of the surface mesh nodes with respect to the design variables ---*/ - - surface_movement->SetSurface_Derivative(geometry[MESH_0],config); - - /*--- Call the volume deformation routine with derivative mode enabled. - This computes the derivative of the volume mesh with respect to the surface nodes ---*/ - - grid_movement->SetVolume_Deformation(geometry[MESH_0],config, true, true); - - /*--- Update the multi-grid structure to propagate the derivative information to the coarser levels ---*/ - - CGeometry::UpdateGeometry(geometry,config); - - } - + + if (config->GetDirectDiff() == D_DESIGN) { + if (rank == MASTER_NODE) + cout << "Setting surface/volume derivatives." << endl; + + /*--- Set the surface derivatives, i.e. the derivative of the surface mesh nodes with respect to the design variables ---*/ + + surface_movement->SetSurface_Derivative(geometry[MESH_0],config); + + /*--- Call the volume deformation routine with derivative mode enabled. + This computes the derivative of the volume mesh with respect to the surface nodes ---*/ + + grid_movement->SetVolume_Deformation(geometry[MESH_0],config, true, true); + + /*--- Update the multi-grid structure to propagate the derivative information to the coarser levels ---*/ + + CGeometry::UpdateGeometry(geometry,config); + + } + } void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGeometry**** geometry, unsigned short** interface_types, CInterface ***interface, vector > >& interpolation) { - - /*--- Setup interpolation and transfer for all possible donor/target pairs. ---*/ - - for (auto target = 0u; target < nZone; target++) { - - for (auto donor = 0u; donor < nZone; donor++) { - - /*--- Aliases to make code less verbose. ---*/ - auto& interface_type = interface_types[donor][target]; - - if (donor == target) { - interface_type = ZONES_ARE_EQUAL; - continue; - } - interface_type = NO_TRANSFER; - - /*--- If there is a common interface setup the interpolation and transfer. ---*/ - - if (!CInterpolator::CheckZonesInterface(config[donor], config[target])) { - interface_type = NO_COMMON_INTERFACE; - } - else { - /*--- Begin the creation of the communication pattern among zones. ---*/ - - if (rank == MASTER_NODE) cout << "From zone " << donor << " to zone " << target << ":" << endl; - - /*--- Setup the interpolation. ---*/ - - interpolation[donor][target] = unique_ptr(CInterpolatorFactory::CreateInterpolator( - geometry, config, interpolation[target][donor].get(), donor, target)); - - /*--- The type of variables transferred depends on the donor/target physics. ---*/ - - const bool heat_target = config[target]->GetHeatProblem(); - const bool fluid_target = config[target]->GetFluidProblem(); - const bool structural_target = config[target]->GetStructuralProblem(); - - const bool heat_donor = config[donor]->GetHeatProblem(); - const bool fluid_donor = config[donor]->GetFluidProblem(); - const bool structural_donor = config[donor]->GetStructuralProblem(); - - /*--- Initialize the appropriate transfer strategy. ---*/ - - if (rank == MASTER_NODE) cout << " Transferring "; - - if (fluid_donor && structural_target) { - interface_type = FLOW_TRACTION; - auto nConst = 2; - bool conservative = config[target]->GetConservativeInterpolation(); - if(!config[ZONE_0]->GetDiscrete_Adjoint()) { - interface[donor][target] = new CFlowTractionInterface(nDim, nConst, config[donor], conservative); - } else { - interface[donor][target] = new CDiscAdjFlowTractionInterface(nDim, nConst, config[donor], conservative); - } - if (rank == MASTER_NODE) cout << "fluid " << (conservative? "forces." : "tractions.") << endl; - } - else if (structural_donor && (fluid_target || heat_target)) { - if (solver_container[target][INST_0][MESH_0][MESH_SOL] == nullptr) { - SU2_MPI::Error("Mesh deformation was not correctly specified for the fluid/heat zone.\n" - "Use DEFORM_MESH=YES, and setup MARKER_DEFORM_MESH=(...)", CURRENT_FUNCTION); - } - interface_type = BOUNDARY_DISPLACEMENTS; - if (!config[donor]->GetTime_Domain()) interface[donor][target] = new CDisplacementsInterface(nDim, 0); - else interface[donor][target] = new CDisplacementsInterface(2*nDim, 0); - if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver." << endl; - } - else if (fluid_donor && fluid_target) { - interface_type = SLIDING_INTERFACE; - auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnPrimVar(); - interface[donor][target] = new CSlidingInterface(nVar, 0); - if (rank == MASTER_NODE) cout << "sliding interface." << endl; - } - else if (heat_donor || heat_target) { - if (heat_donor && heat_target) - SU2_MPI::Error("Conjugate heat transfer between solids is not implemented.", CURRENT_FUNCTION); - - const auto fluidZone = heat_target? donor : target; - - if (config[fluidZone]->GetEnergy_Equation() || (config[fluidZone]->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE)) - interface_type = heat_target? CONJUGATE_HEAT_FS : CONJUGATE_HEAT_SF; - else if (config[fluidZone]->GetWeakly_Coupled_Heat()) - interface_type = heat_target? CONJUGATE_HEAT_WEAKLY_FS : CONJUGATE_HEAT_WEAKLY_SF; - else + + /*--- Setup interpolation and transfer for all possible donor/target pairs. ---*/ + + for (auto target = 0u; target < nZone; target++) { + + for (auto donor = 0u; donor < nZone; donor++) { + + /*--- Aliases to make code less verbose. ---*/ + auto& interface_type = interface_types[donor][target]; + + if (donor == target) { + interface_type = ZONES_ARE_EQUAL; + continue; + } interface_type = NO_TRANSFER; - - if (interface_type != NO_TRANSFER) { - auto nVar = 4; - interface[donor][target] = new CConjugateHeatInterface(nVar, 0); - if (rank == MASTER_NODE) cout << "conjugate heat variables." << endl; - } - else { - if (rank == MASTER_NODE) cout << "NO heat variables." << endl; - } - } - else { - if (solver[donor][INST_0][MESH_0][FLOW_SOL] == nullptr) - SU2_MPI::Error("Could not determine the number of variables for transfer.", CURRENT_FUNCTION); - - auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - interface_type = CONSERVATIVE_VARIABLES; - interface[donor][target] = new CConservativeVarsInterface(nVar, 0); - if (rank == MASTER_NODE) cout << "generic conservative variables." << endl; - } - } - - /*--- Mixing plane for turbo machinery applications. ---*/ - - if (config[donor]->GetBoolMixingPlaneInterface()) { - interface_type = MIXING_PLANE; - auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - interface[donor][target] = new CMixingPlaneInterface(nVar, 0); - if (rank == MASTER_NODE) { - cout << "Set mixing-plane interface from donor zone " - << donor << " to target zone " << target << "." << endl; + + /*--- If there is a common interface setup the interpolation and transfer. ---*/ + + if (!CInterpolator::CheckZonesInterface(config[donor], config[target])) { + interface_type = NO_COMMON_INTERFACE; + } + else { + /*--- Begin the creation of the communication pattern among zones. ---*/ + + if (rank == MASTER_NODE) cout << "From zone " << donor << " to zone " << target << ":" << endl; + + /*--- Setup the interpolation. ---*/ + + interpolation[donor][target] = unique_ptr(CInterpolatorFactory::CreateInterpolator( + geometry, config, interpolation[target][donor].get(), donor, target)); + + /*--- The type of variables transferred depends on the donor/target physics. ---*/ + + const bool heat_target = config[target]->GetHeatProblem(); + const bool fluid_target = config[target]->GetFluidProblem(); + const bool structural_target = config[target]->GetStructuralProblem(); + + const bool heat_donor = config[donor]->GetHeatProblem(); + const bool fluid_donor = config[donor]->GetFluidProblem(); + const bool structural_donor = config[donor]->GetStructuralProblem(); + + /*--- Initialize the appropriate transfer strategy. ---*/ + + if (rank == MASTER_NODE) cout << " Transferring "; + + if (fluid_donor && structural_target) { + interface_type = FLOW_TRACTION; + auto nConst = 2; + bool conservative = config[target]->GetConservativeInterpolation(); + if(!config[ZONE_0]->GetDiscrete_Adjoint()) { + interface[donor][target] = new CFlowTractionInterface(nDim, nConst, config[donor], conservative); + } else { + interface[donor][target] = new CDiscAdjFlowTractionInterface(nDim, nConst, config[donor], conservative); + } + if (rank == MASTER_NODE) cout << "fluid " << (conservative? "forces." : "tractions.") << endl; + } + else if (structural_donor && (fluid_target || heat_target)) { + if (solver_container[target][INST_0][MESH_0][MESH_SOL] == nullptr) { + SU2_MPI::Error("Mesh deformation was not correctly specified for the fluid/heat zone.\n" + "Use DEFORM_MESH=YES, and setup MARKER_DEFORM_MESH=(...)", CURRENT_FUNCTION); + } + interface_type = BOUNDARY_DISPLACEMENTS; + if (!config[donor]->GetTime_Domain()) interface[donor][target] = new CDisplacementsInterface(nDim, 0); + else interface[donor][target] = new CDisplacementsInterface(2*nDim, 0); + if (rank == MASTER_NODE) cout << "boundary displacements from the structural solver." << endl; + } + else if (fluid_donor && fluid_target) { + interface_type = SLIDING_INTERFACE; + auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnPrimVar(); + interface[donor][target] = new CSlidingInterface(nVar, 0); + if (rank == MASTER_NODE) cout << "sliding interface." << endl; + } + else if (heat_donor || heat_target) { + if (heat_donor && heat_target) + SU2_MPI::Error("Conjugate heat transfer between solids is not implemented.", CURRENT_FUNCTION); + + const auto fluidZone = heat_target? donor : target; + + if (config[fluidZone]->GetEnergy_Equation() || (config[fluidZone]->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE)) + interface_type = heat_target? CONJUGATE_HEAT_FS : CONJUGATE_HEAT_SF; + else if (config[fluidZone]->GetWeakly_Coupled_Heat()) + interface_type = heat_target? CONJUGATE_HEAT_WEAKLY_FS : CONJUGATE_HEAT_WEAKLY_SF; + else + interface_type = NO_TRANSFER; + + if (interface_type != NO_TRANSFER) { + auto nVar = 4; + interface[donor][target] = new CConjugateHeatInterface(nVar, 0); + if (rank == MASTER_NODE) cout << "conjugate heat variables." << endl; + } + else { + if (rank == MASTER_NODE) cout << "NO heat variables." << endl; + } + } + else { + if (solver[donor][INST_0][MESH_0][FLOW_SOL] == nullptr) + SU2_MPI::Error("Could not determine the number of variables for transfer.", CURRENT_FUNCTION); + + auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnVar(); + interface_type = CONSERVATIVE_VARIABLES; + interface[donor][target] = new CConservativeVarsInterface(nVar, 0); + if (rank == MASTER_NODE) cout << "generic conservative variables." << endl; + } + } + + /*--- Mixing plane for turbo machinery applications. ---*/ + + if (config[donor]->GetBoolMixingPlaneInterface()) { + interface_type = MIXING_PLANE; + auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnVar(); + interface[donor][target] = new CMixingPlaneInterface(nVar, 0); + if (rank == MASTER_NODE) { + cout << "Set mixing-plane interface from donor zone " + << donor << " to target zone " << target << "." << endl; + } + } + } - } - + } - - } - + } void CDriver::StaticMesh_Preprocessing(const CConfig *config, CGeometry** geometry){ - - unsigned short iMGlevel, iMGfine; - unsigned short Kind_Grid_Movement; - - unsigned short iZone = config->GetiZone(); - - Kind_Grid_Movement = config->GetKind_GridMovement(); - - if (!fem_solver) { - - switch (Kind_Grid_Movement) { - - case ROTATING_FRAME: - - /*--- Steadily rotating frame: set the grid velocities just once - before the first iteration flow solver. ---*/ - - if (rank == MASTER_NODE) { - cout << endl << " Setting rotating frame grid velocities"; - cout << " for zone " << iZone << "." << endl; + + unsigned short iMGlevel, iMGfine; + unsigned short Kind_Grid_Movement; + + unsigned short iZone = config->GetiZone(); + + Kind_Grid_Movement = config->GetKind_GridMovement(); + + if (!fem_solver) { + + switch (Kind_Grid_Movement) { + + case ROTATING_FRAME: + + /*--- Steadily rotating frame: set the grid velocities just once + before the first iteration flow solver. ---*/ + + 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 <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++){ + geometry[iMGlevel]->SetRotationalVelocity(config, true); + geometry[iMGlevel]->SetShroudVelocity(config); + } + + 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 (rank == MASTER_NODE) + cout << endl << " Setting translational grid velocities." << endl; + + /*--- Set the translational velocity on all grid levels. ---*/ + + for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++) + geometry_container[iZone][INST_0][iMGlevel]->SetTranslationalVelocity(config, true); + + break; + + default: + break; } - - /*--- Set the grid velocities on all multigrid levels for a steadily - rotating reference frame. ---*/ - - for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++){ - geometry[iMGlevel]->SetRotationalVelocity(config, true); - geometry[iMGlevel]->SetShroudVelocity(config); + + if (config->GetnMarker_Moving() > 0) { + + /*--- Fixed wall velocities: set the grid velocities only one time + before the first iteration flow solver. ---*/ + if (rank == MASTER_NODE) + cout << endl << " Setting the moving wall velocities." << endl; + + geometry[MESH_0]->SetWallVelocity(config, true); + + /*--- Update the grid velocities on the coarser multigrid levels after + setting the moving wall velocities for the finest mesh. ---*/ + for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++){ + iMGfine = iMGlevel-1; + geometry[iMGlevel]->SetRestricted_GridVelocity(geometry[iMGfine]); + } } - - 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 (rank == MASTER_NODE) - cout << endl << " Setting translational grid velocities." << endl; - - /*--- Set the translational velocity on all grid levels. ---*/ - - for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++) - geometry_container[iZone][INST_0][iMGlevel]->SetTranslationalVelocity(config, true); - - break; - - default: - break; - } - - if (config->GetnMarker_Moving() > 0) { - - /*--- Fixed wall velocities: set the grid velocities only one time - before the first iteration flow solver. ---*/ - if (rank == MASTER_NODE) - cout << endl << " Setting the moving wall velocities." << endl; - - geometry[MESH_0]->SetWallVelocity(config, true); - - /*--- Update the grid velocities on the coarser multigrid levels after - setting the moving wall velocities for the finest mesh. ---*/ - for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++){ - iMGfine = iMGlevel-1; - geometry[iMGlevel]->SetRestricted_GridVelocity(geometry[iMGfine]); - } - } - } else { - - /*--- Carry out a dynamic cast to CMeshFEM_DG, such that it is not needed to + } else { + + /*--- Carry out a dynamic cast to CMeshFEM_DG, such that it is not needed to define all virtual functions in the base class CGeometry. ---*/ - CMeshFEM_DG *DGMesh = dynamic_cast(geometry[MESH_0]); - - /*--- Initialize the static mesh movement, if necessary. ---*/ - const unsigned short Kind_Grid_Movement = config->GetKind_GridMovement(); - const bool initStaticMovement = (config->GetGrid_Movement() && - (Kind_Grid_Movement == MOVING_WALL || - Kind_Grid_Movement == ROTATING_FRAME || - Kind_Grid_Movement == STEADY_TRANSLATION)); - - if(initStaticMovement){ - if (rank == MASTER_NODE) cout << "Initialize Static Mesh Movement" << endl; - DGMesh->InitStaticMeshMovement(config, Kind_Grid_Movement, iZone); + CMeshFEM_DG *DGMesh = dynamic_cast(geometry[MESH_0]); + + /*--- Initialize the static mesh movement, if necessary. ---*/ + const unsigned short Kind_Grid_Movement = config->GetKind_GridMovement(); + const bool initStaticMovement = (config->GetGrid_Movement() && + (Kind_Grid_Movement == MOVING_WALL || + Kind_Grid_Movement == ROTATING_FRAME || + Kind_Grid_Movement == STEADY_TRANSLATION)); + + if(initStaticMovement){ + if (rank == MASTER_NODE) cout << "Initialize Static Mesh Movement" << endl; + DGMesh->InitStaticMeshMovement(config, Kind_Grid_Movement, iZone); + } } - } - + } void CDriver::Output_Preprocessing(CConfig **config, CConfig *driver_config, COutput **&output, COutput *&driver_output){ - - /*--- Definition of the output class (one for each zone). The output class - manages the writing of all restart, volume solution, surface solution, - surface comma-separated value, and convergence history files (both in serial - and in parallel). ---*/ - - for (iZone = 0; iZone < nZone; iZone++){ - - if (rank == MASTER_NODE) - cout << endl <<"-------------------- Output Preprocessing ( Zone " << iZone <<" ) --------------------" << endl; - - MAIN_SOLVER kindSolver = config[iZone]->GetKind_Solver(); - - output[iZone] = COutputFactory::CreateOutput(kindSolver, config[iZone], nDim); - - /*--- If dry-run is used, do not open/overwrite history file. ---*/ - output[iZone]->PreprocessHistoryOutput(config[iZone], !dry_run); - - output[iZone]->PreprocessVolumeOutput(config[iZone]); - - } - - if (driver_config->GetMultizone_Problem()){ - if (rank == MASTER_NODE) - cout << endl <<"------------------- Output Preprocessing ( Multizone ) ------------------" << endl; - - driver_output = COutputFactory::CreateMultizoneOutput(driver_config, config, nDim); - - driver_output->PreprocessMultizoneHistoryOutput(output, config, driver_config, !dry_run); - } - - /*--- Check for an unsteady restart. Update ExtIter if necessary. ---*/ - if (config_container[ZONE_0]->GetTime_Domain() && config_container[ZONE_0]->GetRestart()) - TimeIter = config_container[ZONE_0]->GetRestart_Iter(); - + + /*--- Definition of the output class (one for each zone). The output class + manages the writing of all restart, volume solution, surface solution, + surface comma-separated value, and convergence history files (both in serial + and in parallel). ---*/ + + for (iZone = 0; iZone < nZone; iZone++){ + + if (rank == MASTER_NODE) + cout << endl <<"-------------------- Output Preprocessing ( Zone " << iZone <<" ) --------------------" << endl; + + MAIN_SOLVER kindSolver = config[iZone]->GetKind_Solver(); + + output[iZone] = COutputFactory::CreateOutput(kindSolver, config[iZone], nDim); + + /*--- If dry-run is used, do not open/overwrite history file. ---*/ + output[iZone]->PreprocessHistoryOutput(config[iZone], !dry_run); + + output[iZone]->PreprocessVolumeOutput(config[iZone]); + + } + + if (driver_config->GetMultizone_Problem()){ + if (rank == MASTER_NODE) + cout << endl <<"------------------- Output Preprocessing ( Multizone ) ------------------" << endl; + + driver_output = COutputFactory::CreateMultizoneOutput(driver_config, config, nDim); + + driver_output->PreprocessMultizoneHistoryOutput(output, config, driver_config, !dry_run); + } + + /*--- Check for an unsteady restart. Update ExtIter if necessary. ---*/ + if (config_container[ZONE_0]->GetTime_Domain() && config_container[ZONE_0]->GetRestart()) + TimeIter = config_container[ZONE_0]->GetRestart_Iter(); + } void CDriver::Turbomachinery_Preprocessing(CConfig** config, CGeometry**** geometry, CSolver***** solver, CInterface*** interface){ - - unsigned short donorZone,targetZone, nMarkerInt, iMarkerInt; - unsigned short nSpanMax = 0; - bool restart = (config[ZONE_0]->GetRestart() || config[ZONE_0]->GetRestart_Flow()); - mixingplane = config[ZONE_0]->GetBoolMixingPlaneInterface(); - bool discrete_adjoint = config[ZONE_0]->GetDiscrete_Adjoint(); - su2double areaIn, areaOut, nBlades, flowAngleIn, flowAngleOut; - - /*--- Create turbovertex structure ---*/ - if (rank == MASTER_NODE) cout<GetBoolTurbomachinery()){ - geometry[iZone][INST_0][MESH_0]->ComputeNSpan(config[iZone], iZone, INFLOW, true); - geometry[iZone][INST_0][MESH_0]->ComputeNSpan(config[iZone], iZone, OUTFLOW, true); - if (rank == MASTER_NODE) cout <<"Number of span-wise sections in Zone "<< iZone<<": "<< config[iZone]->GetnSpanWiseSections() <<"."<< endl; - if (config[iZone]->GetnSpanWiseSections() > nSpanMax){ - nSpanMax = config[iZone]->GetnSpanWiseSections(); - } - - config[ZONE_0]->SetnSpan_iZones(config[iZone]->GetnSpanWiseSections(), iZone); - - geometry[iZone][INST_0][MESH_0]->SetTurboVertex(config[iZone], iZone, INFLOW, true); - geometry[iZone][INST_0][MESH_0]->SetTurboVertex(config[iZone], iZone, OUTFLOW, true); - } - } - - /*--- Set maximum number of Span among all zones ---*/ - for (iZone = 0; iZone < nZone; iZone++) { - if (config[iZone]->GetBoolTurbomachinery()){ - config[iZone]->SetnSpanMaxAllZones(nSpanMax); - } - } - if (rank == MASTER_NODE) cout<<"Max number of span-wise sections among all zones: "<< nSpanMax<<"."<< endl; - - - if (rank == MASTER_NODE) cout<<"Initialize solver containers for average and performance quantities." << endl; - for (iZone = 0; iZone < nZone; iZone++) { - solver[iZone][INST_0][MESH_0][FLOW_SOL]->InitTurboContainers(geometry[iZone][INST_0][MESH_0],config[iZone]); - } - -//TODO(turbo) make it general for turbo HB - if (rank == MASTER_NODE) cout<<"Compute inflow and outflow average geometric quantities." << endl; - for (iZone = 0; iZone < nZone; iZone++) { - geometry[iZone][INST_0][MESH_0]->SetAvgTurboValue(config[iZone], iZone, INFLOW, true); - geometry[iZone][INST_0][MESH_0]->SetAvgTurboValue(config[iZone],iZone, OUTFLOW, true); - geometry[iZone][INST_0][MESH_0]->GatherInOutAverageValues(config[iZone], true); - } - - - if(mixingplane){ - if (rank == MASTER_NODE) cout << "Set span-wise sections between zones on Mixing-Plane interface." << endl; - for (donorZone = 0; donorZone < nZone; donorZone++) { - for (targetZone = 0; targetZone < nZone; targetZone++) { - if (targetZone != donorZone){ - interface[donorZone][targetZone]->SetSpanWiseLevels(config[donorZone], config[targetZone]); - } - } - } - } - - if (rank == MASTER_NODE) cout << "Transfer average geometric quantities to zone 0." << endl; - for (iZone = 1; iZone < nZone; iZone++) { - interface[iZone][ZONE_0]->GatherAverageTurboGeoValues(geometry[iZone][INST_0][MESH_0],geometry[ZONE_0][INST_0][MESH_0], iZone); - } - - /*--- Transfer number of blade to ZONE_0 to correctly compute turbo performance---*/ - for (iZone = 1; iZone < nZone; iZone++) { - nBlades = config[iZone]->GetnBlades(iZone); - config[ZONE_0]->SetnBlades(iZone, nBlades); - } - - if (rank == MASTER_NODE){ + + unsigned short donorZone,targetZone, nMarkerInt, iMarkerInt; + unsigned short nSpanMax = 0; + bool restart = (config[ZONE_0]->GetRestart() || config[ZONE_0]->GetRestart_Flow()); + mixingplane = config[ZONE_0]->GetBoolMixingPlaneInterface(); + bool discrete_adjoint = config[ZONE_0]->GetDiscrete_Adjoint(); + su2double areaIn, areaOut, nBlades, flowAngleIn, flowAngleOut; + + /*--- Create turbovertex structure ---*/ + if (rank == MASTER_NODE) cout<GetSpanAreaIn(iZone, config[iZone]->GetnSpanWiseSections()); - areaOut = geometry[iZone][INST_0][MESH_0]->GetSpanAreaOut(iZone, config[iZone]->GetnSpanWiseSections()); - nBlades = config[iZone]->GetnBlades(iZone); - cout << "Inlet area for Row "<< iZone + 1<< ": " << areaIn*10000.0 <<" cm^2." <GetnMarker_MixingPlaneInterface()/2; - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++){ - for (targetZone = 0; targetZone < nZone; targetZone++) { - if (targetZone != donorZone){ - interface[donorZone][targetZone]->PreprocessAverage(geometry[donorZone][INST_0][MESH_0], geometry[targetZone][INST_0][MESH_0], - config[donorZone], config[targetZone], - iMarkerInt); - } + if (config[iZone]->GetBoolTurbomachinery()){ + geometry[iZone][INST_0][MESH_0]->ComputeNSpan(config[iZone], iZone, INFLOW, true); + geometry[iZone][INST_0][MESH_0]->ComputeNSpan(config[iZone], iZone, OUTFLOW, true); + if (rank == MASTER_NODE) cout <<"Number of span-wise sections in Zone "<< iZone<<": "<< config[iZone]->GetnSpanWiseSections() <<"."<< endl; + if (config[iZone]->GetnSpanWiseSections() > nSpanMax){ + nSpanMax = config[iZone]->GetnSpanWiseSections(); + } + + config[ZONE_0]->SetnSpan_iZones(config[iZone]->GetnSpanWiseSections(), iZone); + + geometry[iZone][INST_0][MESH_0]->SetTurboVertex(config[iZone], iZone, INFLOW, true); + geometry[iZone][INST_0][MESH_0]->SetTurboVertex(config[iZone], iZone, OUTFLOW, true); } - } } - } - - if(!restart && !discrete_adjoint){ - if (rank == MASTER_NODE) cout<<"Initialize turbomachinery solution quantities." << endl; - for(iZone = 0; iZone < nZone; iZone++) { - solver[iZone][INST_0][MESH_0][FLOW_SOL]->SetFreeStream_TurboSolution(config[iZone]); + + /*--- Set maximum number of Span among all zones ---*/ + for (iZone = 0; iZone < nZone; iZone++) { + if (config[iZone]->GetBoolTurbomachinery()){ + config[iZone]->SetnSpanMaxAllZones(nSpanMax); + } } - } - - if (rank == MASTER_NODE) cout<<"Initialize inflow and outflow average solution quantities." << endl; - for(iZone = 0; iZone < nZone; iZone++) { - solver[iZone][INST_0][MESH_0][FLOW_SOL]->PreprocessAverage(solver[iZone][INST_0][MESH_0], geometry[iZone][INST_0][MESH_0],config[iZone],INFLOW); - solver[iZone][INST_0][MESH_0][FLOW_SOL]->PreprocessAverage(solver[iZone][INST_0][MESH_0], geometry[iZone][INST_0][MESH_0],config[iZone],OUTFLOW); - solver[iZone][INST_0][MESH_0][FLOW_SOL]->TurboAverageProcess(solver[iZone][INST_0][MESH_0], geometry[iZone][INST_0][MESH_0],config[iZone],INFLOW); - solver[iZone][INST_0][MESH_0][FLOW_SOL]->TurboAverageProcess(solver[iZone][INST_0][MESH_0], geometry[iZone][INST_0][MESH_0],config[iZone],OUTFLOW); - solver[iZone][INST_0][MESH_0][FLOW_SOL]->GatherInOutAverageValues(config[iZone], geometry[iZone][INST_0][MESH_0]); - if (rank == MASTER_NODE){ - flowAngleIn = solver[iZone][INST_0][MESH_0][FLOW_SOL]->GetTurboVelocityIn(iZone, config[iZone]->GetnSpanWiseSections())[1]; - flowAngleIn /= solver[iZone][INST_0][MESH_0][FLOW_SOL]->GetTurboVelocityIn(iZone, config[iZone]->GetnSpanWiseSections())[0]; - flowAngleIn = atan(flowAngleIn)*180.0/PI_NUMBER; - cout << "Inlet flow angle for Row "<< iZone + 1<< ": "<< flowAngleIn <<"°." <GetTurboVelocityOut(iZone, config[iZone]->GetnSpanWiseSections())[1]; - flowAngleOut /= solver[iZone][INST_0][MESH_0][FLOW_SOL]->GetTurboVelocityOut(iZone, config[iZone]->GetnSpanWiseSections())[0]; - flowAngleOut = atan(flowAngleOut)*180.0/PI_NUMBER; - cout << "Outlet flow angle for Row "<< iZone + 1<< ": "<< flowAngleOut <<"°." <InitTurboContainers(geometry[iZone][INST_0][MESH_0],config[iZone]); } - } - -} - -CDriver::~CDriver(void) {} - -void CDriver::Print_DirectResidual(RECORDING kind_recording) { - - if (!(rank == MASTER_NODE && kind_recording == RECORDING::SOLUTION_VARIABLES)) return; - - const bool multizone = config_container[ZONE_0]->GetMultizone_Problem(); - - /*--- Helper lambda func to return lenghty [iVar][iZone] string. ---*/ - auto iVar_iZone2string = [&](unsigned short ivar, unsigned short izone) { - if (multizone) - return "[" + std::to_string(ivar) + "][" + std::to_string(izone) + "]"; - else - return "[" + std::to_string(ivar) + "]"; - }; - - /*--- Print residuals in the first iteration ---*/ - - const unsigned short fieldWidth = 15; - PrintingToolbox::CTablePrinter RMSTable(&std::cout); - RMSTable.SetPrecision(config_container[ZONE_0]->GetOutput_Precision()); - - /*--- The CTablePrinter requires two sweeps: - *--- 0. Add the colum names (addVals=0=false) plus CTablePrinter.PrintHeader() - *--- 1. Add the RMS-residual values (addVals=1=true) plus CTablePrinter.PrintFooter() ---*/ - for (int addVals = 0; addVals < 2; addVals++) { - - for (unsigned short iZone = 0; iZone < nZone; iZone++) { - - auto solvers = solver_container[iZone][INST_0][MESH_0]; - auto configs = config_container[iZone]; - - /*--- Note: the FEM-Flow solvers are availalbe for disc. adjoint runs only for SingleZone. ---*/ - if (configs->GetFluidProblem() || configs->GetFEMSolver()) { - - for (unsigned short iVar = 0; iVar < solvers[FLOW_SOL]->GetnVar(); iVar++) { - if (!addVals) - RMSTable.AddColumn("rms_Flow" + iVar_iZone2string(iVar, iZone), fieldWidth); - else - RMSTable << log10(solvers[FLOW_SOL]->GetRes_RMS(iVar)); - } - - if (configs->GetKind_Turb_Model() != TURB_MODEL::NONE && !configs->GetFrozen_Visc_Disc()) { - for (unsigned short iVar = 0; iVar < solvers[TURB_SOL]->GetnVar(); iVar++) { - if (!addVals) - RMSTable.AddColumn("rms_Turb" + iVar_iZone2string(iVar, iZone), fieldWidth); - else - RMSTable << log10(solvers[TURB_SOL]->GetRes_RMS(iVar)); - } - } - - if (configs->GetKind_Species_Model() != SPECIES_MODEL::NONE) { - for (unsigned short iVar = 0; iVar < solvers[SPECIES_SOL]->GetnVar(); iVar++) { - if (!addVals) - RMSTable.AddColumn("rms_Spec" + iVar_iZone2string(iVar, iZone), fieldWidth); - else - RMSTable << log10(solvers[SPECIES_SOL]->GetRes_RMS(iVar)); - } + + //TODO(turbo) make it general for turbo HB + if (rank == MASTER_NODE) cout<<"Compute inflow and outflow average geometric quantities." << endl; + for (iZone = 0; iZone < nZone; iZone++) { + geometry[iZone][INST_0][MESH_0]->SetAvgTurboValue(config[iZone], iZone, INFLOW, true); + geometry[iZone][INST_0][MESH_0]->SetAvgTurboValue(config[iZone],iZone, OUTFLOW, true); + geometry[iZone][INST_0][MESH_0]->GatherInOutAverageValues(config[iZone], true); + } + + + if(mixingplane){ + if (rank == MASTER_NODE) cout << "Set span-wise sections between zones on Mixing-Plane interface." << endl; + for (donorZone = 0; donorZone < nZone; donorZone++) { + for (targetZone = 0; targetZone < nZone; targetZone++) { + if (targetZone != donorZone){ + interface[donorZone][targetZone]->SetSpanWiseLevels(config[donorZone], config[targetZone]); + } + } } - - if (!multizone && configs->GetWeakly_Coupled_Heat()){ - if (!addVals) RMSTable.AddColumn("rms_Heat" + iVar_iZone2string(0, iZone), fieldWidth); - else RMSTable << log10(solvers[HEAT_SOL]->GetRes_RMS(0)); + } + + if (rank == MASTER_NODE) cout << "Transfer average geometric quantities to zone 0." << endl; + for (iZone = 1; iZone < nZone; iZone++) { + interface[iZone][ZONE_0]->GatherAverageTurboGeoValues(geometry[iZone][INST_0][MESH_0],geometry[ZONE_0][INST_0][MESH_0], iZone); + } + + /*--- Transfer number of blade to ZONE_0 to correctly compute turbo performance---*/ + for (iZone = 1; iZone < nZone; iZone++) { + nBlades = config[iZone]->GetnBlades(iZone); + config[ZONE_0]->SetnBlades(iZone, nBlades); + } + + if (rank == MASTER_NODE){ + for (iZone = 0; iZone < nZone; iZone++) { + areaIn = geometry[iZone][INST_0][MESH_0]->GetSpanAreaIn(iZone, config[iZone]->GetnSpanWiseSections()); + areaOut = geometry[iZone][INST_0][MESH_0]->GetSpanAreaOut(iZone, config[iZone]->GetnSpanWiseSections()); + nBlades = config[iZone]->GetnBlades(iZone); + cout << "Inlet area for Row "<< iZone + 1<< ": " << areaIn*10000.0 <<" cm^2." <AddRadiation()) { - if (!addVals) RMSTable.AddColumn("rms_Rad" + iVar_iZone2string(0, iZone), fieldWidth); - else RMSTable << log10(solvers[RAD_SOL]->GetRes_RMS(0)); + } + + + if(mixingplane){ + if (rank == MASTER_NODE) cout<<"Preprocessing of the Mixing-Plane Interface." << endl; + for (donorZone = 0; donorZone < nZone; donorZone++) { + nMarkerInt = config_container[donorZone]->GetnMarker_MixingPlaneInterface()/2; + for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++){ + for (targetZone = 0; targetZone < nZone; targetZone++) { + if (targetZone != donorZone){ + interface[donorZone][targetZone]->PreprocessAverage(geometry[donorZone][INST_0][MESH_0], geometry[targetZone][INST_0][MESH_0], + config[donorZone], config[targetZone], + iMarkerInt); + } + } + } } - - } - else if (configs->GetStructuralProblem()) { - - if (configs->GetGeometricConditions() == STRUCT_DEFORMATION::LARGE){ - if (!addVals) { - RMSTable.AddColumn("UTOL-A", fieldWidth); - RMSTable.AddColumn("RTOL-A", fieldWidth); - RMSTable.AddColumn("ETOL-A", fieldWidth); - } - else { - RMSTable << log10(solvers[FEA_SOL]->GetRes_FEM(0)) - << log10(solvers[FEA_SOL]->GetRes_FEM(1)) - << log10(solvers[FEA_SOL]->GetRes_FEM(2)); - } + } + + if(!restart && !discrete_adjoint){ + if (rank == MASTER_NODE) cout<<"Initialize turbomachinery solution quantities." << endl; + for(iZone = 0; iZone < nZone; iZone++) { + solver[iZone][INST_0][MESH_0][FLOW_SOL]->SetFreeStream_TurboSolution(config[iZone]); } - else{ - if (!addVals) { - RMSTable.AddColumn("log10[RMS Ux]", fieldWidth); - RMSTable.AddColumn("log10[RMS Uy]", fieldWidth); - if (nDim == 3) RMSTable.AddColumn("log10[RMS Uz]", fieldWidth); - } - else { - RMSTable << log10(solvers[FEA_SOL]->GetRes_FEM(0)) - << log10(solvers[FEA_SOL]->GetRes_FEM(1)); - if (nDim == 3) RMSTable << log10(solvers[FEA_SOL]->GetRes_FEM(2)); - } + } + + if (rank == MASTER_NODE) cout<<"Initialize inflow and outflow average solution quantities." << endl; + for(iZone = 0; iZone < nZone; iZone++) { + solver[iZone][INST_0][MESH_0][FLOW_SOL]->PreprocessAverage(solver[iZone][INST_0][MESH_0], geometry[iZone][INST_0][MESH_0],config[iZone],INFLOW); + solver[iZone][INST_0][MESH_0][FLOW_SOL]->PreprocessAverage(solver[iZone][INST_0][MESH_0], geometry[iZone][INST_0][MESH_0],config[iZone],OUTFLOW); + solver[iZone][INST_0][MESH_0][FLOW_SOL]->TurboAverageProcess(solver[iZone][INST_0][MESH_0], geometry[iZone][INST_0][MESH_0],config[iZone],INFLOW); + solver[iZone][INST_0][MESH_0][FLOW_SOL]->TurboAverageProcess(solver[iZone][INST_0][MESH_0], geometry[iZone][INST_0][MESH_0],config[iZone],OUTFLOW); + solver[iZone][INST_0][MESH_0][FLOW_SOL]->GatherInOutAverageValues(config[iZone], geometry[iZone][INST_0][MESH_0]); + if (rank == MASTER_NODE){ + flowAngleIn = solver[iZone][INST_0][MESH_0][FLOW_SOL]->GetTurboVelocityIn(iZone, config[iZone]->GetnSpanWiseSections())[1]; + flowAngleIn /= solver[iZone][INST_0][MESH_0][FLOW_SOL]->GetTurboVelocityIn(iZone, config[iZone]->GetnSpanWiseSections())[0]; + flowAngleIn = atan(flowAngleIn)*180.0/PI_NUMBER; + cout << "Inlet flow angle for Row "<< iZone + 1<< ": "<< flowAngleIn <<"°." <GetTurboVelocityOut(iZone, config[iZone]->GetnSpanWiseSections())[1]; + flowAngleOut /= solver[iZone][INST_0][MESH_0][FLOW_SOL]->GetTurboVelocityOut(iZone, config[iZone]->GetnSpanWiseSections())[0]; + flowAngleOut = atan(flowAngleOut)*180.0/PI_NUMBER; + cout << "Outlet flow angle for Row "<< iZone + 1<< ": "<< flowAngleOut <<"°." <GetHeatProblem()) { - - if (!addVals) RMSTable.AddColumn("rms_Heat" + iVar_iZone2string(0, iZone), fieldWidth); - else RMSTable << log10(solvers[HEAT_SOL]->GetRes_RMS(0)); - } else { - SU2_MPI::Error("Invalid KindSolver for CDiscAdj-MultiZone/SingleZone-Driver.", CURRENT_FUNCTION); - } - } // loop iZone - - if (!addVals) RMSTable.PrintHeader(); - else RMSTable.PrintFooter(); - - } // for addVals - - cout << "\n-------------------------------------------------------------------------\n" << endl; +CDriver::~CDriver(void) {} +void CDriver::Print_DirectResidual(RECORDING kind_recording) { + + if (!(rank == MASTER_NODE && kind_recording == RECORDING::SOLUTION_VARIABLES)) return; + + const bool multizone = config_container[ZONE_0]->GetMultizone_Problem(); + + /*--- Helper lambda func to return lenghty [iVar][iZone] string. ---*/ + auto iVar_iZone2string = [&](unsigned short ivar, unsigned short izone) { + if (multizone) + return "[" + std::to_string(ivar) + "][" + std::to_string(izone) + "]"; + else + return "[" + std::to_string(ivar) + "]"; + }; + + /*--- Print residuals in the first iteration ---*/ + + const unsigned short fieldWidth = 15; + PrintingToolbox::CTablePrinter RMSTable(&std::cout); + RMSTable.SetPrecision(config_container[ZONE_0]->GetOutput_Precision()); + + /*--- The CTablePrinter requires two sweeps: + *--- 0. Add the colum names (addVals=0=false) plus CTablePrinter.PrintHeader() + *--- 1. Add the RMS-residual values (addVals=1=true) plus CTablePrinter.PrintFooter() ---*/ + for (int addVals = 0; addVals < 2; addVals++) { + + for (unsigned short iZone = 0; iZone < nZone; iZone++) { + + auto solvers = solver_container[iZone][INST_0][MESH_0]; + auto configs = config_container[iZone]; + + /*--- Note: the FEM-Flow solvers are availalbe for disc. adjoint runs only for SingleZone. ---*/ + if (configs->GetFluidProblem() || configs->GetFEMSolver()) { + + for (unsigned short iVar = 0; iVar < solvers[FLOW_SOL]->GetnVar(); iVar++) { + if (!addVals) + RMSTable.AddColumn("rms_Flow" + iVar_iZone2string(iVar, iZone), fieldWidth); + else + RMSTable << log10(solvers[FLOW_SOL]->GetRes_RMS(iVar)); + } + + if (configs->GetKind_Turb_Model() != TURB_MODEL::NONE && !configs->GetFrozen_Visc_Disc()) { + for (unsigned short iVar = 0; iVar < solvers[TURB_SOL]->GetnVar(); iVar++) { + if (!addVals) + RMSTable.AddColumn("rms_Turb" + iVar_iZone2string(iVar, iZone), fieldWidth); + else + RMSTable << log10(solvers[TURB_SOL]->GetRes_RMS(iVar)); + } + } + + if (configs->GetKind_Species_Model() != SPECIES_MODEL::NONE) { + for (unsigned short iVar = 0; iVar < solvers[SPECIES_SOL]->GetnVar(); iVar++) { + if (!addVals) + RMSTable.AddColumn("rms_Spec" + iVar_iZone2string(iVar, iZone), fieldWidth); + else + RMSTable << log10(solvers[SPECIES_SOL]->GetRes_RMS(iVar)); + } + } + + if (!multizone && configs->GetWeakly_Coupled_Heat()){ + if (!addVals) RMSTable.AddColumn("rms_Heat" + iVar_iZone2string(0, iZone), fieldWidth); + else RMSTable << log10(solvers[HEAT_SOL]->GetRes_RMS(0)); + } + + if (configs->AddRadiation()) { + if (!addVals) RMSTable.AddColumn("rms_Rad" + iVar_iZone2string(0, iZone), fieldWidth); + else RMSTable << log10(solvers[RAD_SOL]->GetRes_RMS(0)); + } + + } + else if (configs->GetStructuralProblem()) { + + if (configs->GetGeometricConditions() == STRUCT_DEFORMATION::LARGE){ + if (!addVals) { + RMSTable.AddColumn("UTOL-A", fieldWidth); + RMSTable.AddColumn("RTOL-A", fieldWidth); + RMSTable.AddColumn("ETOL-A", fieldWidth); + } + else { + RMSTable << log10(solvers[FEA_SOL]->GetRes_FEM(0)) + << log10(solvers[FEA_SOL]->GetRes_FEM(1)) + << log10(solvers[FEA_SOL]->GetRes_FEM(2)); + } + } + else{ + if (!addVals) { + RMSTable.AddColumn("log10[RMS Ux]", fieldWidth); + RMSTable.AddColumn("log10[RMS Uy]", fieldWidth); + if (nDim == 3) RMSTable.AddColumn("log10[RMS Uz]", fieldWidth); + } + else { + RMSTable << log10(solvers[FEA_SOL]->GetRes_FEM(0)) + << log10(solvers[FEA_SOL]->GetRes_FEM(1)); + if (nDim == 3) RMSTable << log10(solvers[FEA_SOL]->GetRes_FEM(2)); + } + } + + } + else if (configs->GetHeatProblem()) { + + if (!addVals) RMSTable.AddColumn("rms_Heat" + iVar_iZone2string(0, iZone), fieldWidth); + else RMSTable << log10(solvers[HEAT_SOL]->GetRes_RMS(0)); + } else { + SU2_MPI::Error("Invalid KindSolver for CDiscAdj-MultiZone/SingleZone-Driver.", CURRENT_FUNCTION); + } + } // loop iZone + + if (!addVals) RMSTable.PrintHeader(); + else RMSTable.PrintFooter(); + + } // for addVals + + cout << "\n-------------------------------------------------------------------------\n" << endl; + } CFluidDriver::CFluidDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator) : CDriver(confFile, val_nZone, MPICommunicator, false) { - Max_Iter = config_container[ZONE_0]->GetnInner_Iter(); + Max_Iter = config_container[ZONE_0]->GetnInner_Iter(); } CFluidDriver::~CFluidDriver(void) { } void CFluidDriver::StartSolver(){ - + #ifdef VTUNEPROF - __itt_resume(); + __itt_resume(); #endif - - /*--- Main external loop of the solver. Within this loop, each iteration ---*/ - - if (rank == MASTER_NODE){ - cout << endl <<"------------------------------ Begin Solver -----------------------------" << endl; - } - - unsigned long Iter = 0; - while ( Iter < Max_Iter ) { - - /*--- Perform some external iteration preprocessing. ---*/ - - Preprocess(Iter); - - /*--- Perform a dynamic mesh update if required. ---*/ - /*--- For the Disc.Adj. of a case with (rigidly) moving grid, the appropriate - mesh cordinates are read from the restart files. ---*/ - if (!fem_solver && - !(config_container[ZONE_0]->GetGrid_Movement() && config_container[ZONE_0]->GetDiscrete_Adjoint())) { - DynamicMeshUpdate(Iter); + + /*--- Main external loop of the solver. Within this loop, each iteration ---*/ + + if (rank == MASTER_NODE){ + cout << endl <<"------------------------------ Begin Solver -----------------------------" << endl; + } + + unsigned long Iter = 0; + while ( Iter < Max_Iter ) { + + /*--- Perform some external iteration preprocessing. ---*/ + + Preprocess(Iter); + + /*--- Perform a dynamic mesh update if required. ---*/ + /*--- For the Disc.Adj. of a case with (rigidly) moving grid, the appropriate + mesh cordinates are read from the restart files. ---*/ + if (!fem_solver && + !(config_container[ZONE_0]->GetGrid_Movement() && config_container[ZONE_0]->GetDiscrete_Adjoint())) { + DynamicMeshUpdate(Iter); + } + + /*--- Run a single iteration of the problem (fluid, elasticity, heat, ...). ---*/ + + Run(); + + /*--- Update the solution for dual time stepping strategy ---*/ + + Update(); + + /*--- Terminate the simulation if only the Jacobian must be computed. ---*/ + if (config_container[ZONE_0]->GetJacobian_Spatial_Discretization_Only()) break; + + /*--- Monitor the computations after each iteration. ---*/ + + Monitor(Iter); + + /*--- Output the solution in files. ---*/ + + Output(Iter); + + /*--- If the convergence criteria has been met, terminate the simulation. ---*/ + + if (StopCalc) break; + + Iter++; + } - - /*--- Run a single iteration of the problem (fluid, elasticity, heat, ...). ---*/ - - Run(); - - /*--- Update the solution for dual time stepping strategy ---*/ - - Update(); - - /*--- Terminate the simulation if only the Jacobian must be computed. ---*/ - if (config_container[ZONE_0]->GetJacobian_Spatial_Discretization_Only()) break; - - /*--- Monitor the computations after each iteration. ---*/ - - Monitor(Iter); - - /*--- Output the solution in files. ---*/ - - Output(Iter); - - /*--- If the convergence criteria has been met, terminate the simulation. ---*/ - - if (StopCalc) break; - - Iter++; - - } #ifdef VTUNEPROF - __itt_pause(); + __itt_pause(); #endif } void CFluidDriver::Preprocess(unsigned long Iter) { - - /*--- Set the value of the external iteration and physical time. ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - config_container[iZone]->SetInnerIter(Iter); - if (config_container[iZone]->GetTime_Marching() != TIME_MARCHING::STEADY) - config_container[iZone]->SetPhysicalTime(static_cast(Iter)*config_container[iZone]->GetDelta_UnstTimeND()); - else - config_container[iZone]->SetPhysicalTime(0.0); - } - - /*--- Set the initial condition for EULER/N-S/RANS and for a non FSI simulation ---*/ - - if(!fsi) { + + /*--- Set the value of the external iteration and physical time. ---*/ + for (iZone = 0; iZone < nZone; iZone++) { - if (config_container[iZone]->GetFluidProblem()) { - for (iInst = 0; iInst < nInst[iZone]; iInst++) { - solver_container[iZone][iInst][MESH_0][FLOW_SOL]->SetInitialCondition(geometry_container[iZone][INST_0], solver_container[iZone][iInst], config_container[iZone], Iter); + config_container[iZone]->SetInnerIter(Iter); + if (config_container[iZone]->GetTime_Marching() != TIME_MARCHING::STEADY) + config_container[iZone]->SetPhysicalTime(static_cast(Iter)*config_container[iZone]->GetDelta_UnstTimeND()); + else + config_container[iZone]->SetPhysicalTime(0.0); + } + + /*--- Set the initial condition for EULER/N-S/RANS and for a non FSI simulation ---*/ + + if(!fsi) { + for (iZone = 0; iZone < nZone; iZone++) { + if (config_container[iZone]->GetFluidProblem()) { + for (iInst = 0; iInst < nInst[iZone]; iInst++) { + solver_container[iZone][iInst][MESH_0][FLOW_SOL]->SetInitialCondition(geometry_container[iZone][INST_0], solver_container[iZone][iInst], config_container[iZone], Iter); + } + } } - } } - } } void CFluidDriver::Run() { - - unsigned short iZone, jZone, checkConvergence; - unsigned long IntIter, nIntIter; - bool unsteady; - - /*--- Run a single iteration of a multi-zone problem by looping over all - zones and executing the iterations. Note that data transers between zones - and other intermediate procedures may be required. ---*/ - - unsteady = (config_container[MESH_0]->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || - (config_container[MESH_0]->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND); - - /*--- Zone preprocessing ---*/ - - for (iZone = 0; iZone < nZone; iZone++) - iteration_container[iZone][INST_0]->Preprocess(output_container[iZone], integration_container, geometry_container, solver_container, numerics_container, config_container, surface_movement, grid_movement, FFDBox, iZone, INST_0); - - /*--- Updating zone interface communication patterns, - needed only for unsteady simulation since for steady problems - this is done once in the interpolator_container constructor - at the beginning of the computation ---*/ - - if ( unsteady ) { - for (iZone = 0; iZone < nZone; iZone++) { - for (jZone = 0; jZone < nZone; jZone++) - if(jZone != iZone && interpolator_container[iZone][jZone] != nullptr) - interpolator_container[iZone][jZone]->SetTransferCoeff(config_container); - } - } - - /*--- Begin Unsteady pseudo-time stepping internal loop, if not unsteady it does only one step --*/ - - if (unsteady) - nIntIter = config_container[MESH_0]->GetnInner_Iter(); - else - nIntIter = 1; - - for (IntIter = 0; IntIter < nIntIter; IntIter++) { - - /*--- At each pseudo time-step updates transfer data ---*/ - for (iZone = 0; iZone < nZone; iZone++) - for (jZone = 0; jZone < nZone; jZone++) - if(jZone != iZone && interface_container[iZone][jZone] != nullptr) - Transfer_Data(iZone, jZone); - - /*--- For each zone runs one single iteration ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - config_container[iZone]->SetInnerIter(IntIter); - iteration_container[iZone][INST_0]->Iterate(output_container[iZone], integration_container, geometry_container, solver_container, numerics_container, - config_container, surface_movement, grid_movement, FFDBox, iZone, INST_0); - } - - /*--- Check convergence in each zone --*/ - - checkConvergence = 0; - for (iZone = 0; iZone < nZone; iZone++) - checkConvergence += (int) integration_container[iZone][INST_0][FLOW_SOL]->GetConvergence(); - - /*--- If convergence was reached in every zone --*/ - - if (checkConvergence == nZone) break; - } - + + unsigned short iZone, jZone, checkConvergence; + unsigned long IntIter, nIntIter; + bool unsteady; + + /*--- Run a single iteration of a multi-zone problem by looping over all + zones and executing the iterations. Note that data transers between zones + and other intermediate procedures may be required. ---*/ + + unsteady = (config_container[MESH_0]->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || + (config_container[MESH_0]->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND); + + /*--- Zone preprocessing ---*/ + + for (iZone = 0; iZone < nZone; iZone++) + iteration_container[iZone][INST_0]->Preprocess(output_container[iZone], integration_container, geometry_container, solver_container, numerics_container, config_container, surface_movement, grid_movement, FFDBox, iZone, INST_0); + + /*--- Updating zone interface communication patterns, + needed only for unsteady simulation since for steady problems + this is done once in the interpolator_container constructor + at the beginning of the computation ---*/ + + if ( unsteady ) { + for (iZone = 0; iZone < nZone; iZone++) { + for (jZone = 0; jZone < nZone; jZone++) + if(jZone != iZone && interpolator_container[iZone][jZone] != nullptr) + interpolator_container[iZone][jZone]->SetTransferCoeff(config_container); + } + } + + /*--- Begin Unsteady pseudo-time stepping internal loop, if not unsteady it does only one step --*/ + + if (unsteady) + nIntIter = config_container[MESH_0]->GetnInner_Iter(); + else + nIntIter = 1; + + for (IntIter = 0; IntIter < nIntIter; IntIter++) { + + /*--- At each pseudo time-step updates transfer data ---*/ + for (iZone = 0; iZone < nZone; iZone++) + for (jZone = 0; jZone < nZone; jZone++) + if(jZone != iZone && interface_container[iZone][jZone] != nullptr) + Transfer_Data(iZone, jZone); + + /*--- For each zone runs one single iteration ---*/ + + for (iZone = 0; iZone < nZone; iZone++) { + config_container[iZone]->SetInnerIter(IntIter); + iteration_container[iZone][INST_0]->Iterate(output_container[iZone], integration_container, geometry_container, solver_container, numerics_container, + config_container, surface_movement, grid_movement, FFDBox, iZone, INST_0); + } + + /*--- Check convergence in each zone --*/ + + checkConvergence = 0; + for (iZone = 0; iZone < nZone; iZone++) + checkConvergence += (int) integration_container[iZone][INST_0][FLOW_SOL]->GetConvergence(); + + /*--- If convergence was reached in every zone --*/ + + if (checkConvergence == nZone) break; + } + } void CFluidDriver::Transfer_Data(unsigned short donorZone, unsigned short targetZone) { - - interface_container[donorZone][targetZone]->BroadcastData(*interpolator_container[donorZone][targetZone].get(), - solver_container[donorZone][INST_0][MESH_0][FLOW_SOL], solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], - geometry_container[donorZone][INST_0][MESH_0], geometry_container[targetZone][INST_0][MESH_0], - config_container[donorZone], config_container[targetZone]); - - if (config_container[targetZone]->GetKind_Solver() == MAIN_SOLVER::RANS) { + interface_container[donorZone][targetZone]->BroadcastData(*interpolator_container[donorZone][targetZone].get(), - solver_container[donorZone][INST_0][MESH_0][TURB_SOL], solver_container[targetZone][INST_0][MESH_0][TURB_SOL], - geometry_container[donorZone][INST_0][MESH_0], geometry_container[targetZone][INST_0][MESH_0], - config_container[donorZone], config_container[targetZone]); - } + solver_container[donorZone][INST_0][MESH_0][FLOW_SOL], solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], + geometry_container[donorZone][INST_0][MESH_0], geometry_container[targetZone][INST_0][MESH_0], + config_container[donorZone], config_container[targetZone]); + + if (config_container[targetZone]->GetKind_Solver() == MAIN_SOLVER::RANS) { + interface_container[donorZone][targetZone]->BroadcastData(*interpolator_container[donorZone][targetZone].get(), + solver_container[donorZone][INST_0][MESH_0][TURB_SOL], solver_container[targetZone][INST_0][MESH_0][TURB_SOL], + geometry_container[donorZone][INST_0][MESH_0], geometry_container[targetZone][INST_0][MESH_0], + config_container[donorZone], config_container[targetZone]); + } } void CFluidDriver::Update() { - - for(iZone = 0; iZone < nZone; iZone++) - iteration_container[iZone][INST_0]->Update(output_container[iZone], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, iZone, INST_0); + + for(iZone = 0; iZone < nZone; iZone++) + iteration_container[iZone][INST_0]->Update(output_container[iZone], integration_container, geometry_container, + solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, iZone, INST_0); } void CFluidDriver::DynamicMeshUpdate(unsigned long TimeIter) { - - bool harmonic_balance; - - for (iZone = 0; iZone < nZone; iZone++) { - harmonic_balance = (config_container[iZone]->GetTime_Marching() == TIME_MARCHING::HARMONIC_BALANCE); - /*--- Dynamic mesh update ---*/ - if ((config_container[iZone]->GetGrid_Movement()) && (!harmonic_balance)) { - iteration_container[iZone][INST_0]->SetGrid_Movement(geometry_container[iZone][INST_0], surface_movement[iZone], grid_movement[iZone][INST_0], solver_container[iZone][INST_0], config_container[iZone], 0, TimeIter ); + + bool harmonic_balance; + + for (iZone = 0; iZone < nZone; iZone++) { + harmonic_balance = (config_container[iZone]->GetTime_Marching() == TIME_MARCHING::HARMONIC_BALANCE); + /*--- Dynamic mesh update ---*/ + if ((config_container[iZone]->GetGrid_Movement()) && (!harmonic_balance)) { + iteration_container[iZone][INST_0]->SetGrid_Movement(geometry_container[iZone][INST_0], surface_movement[iZone], grid_movement[iZone][INST_0], solver_container[iZone][INST_0], config_container[iZone], 0, TimeIter ); + } } - } - + } bool CFluidDriver::Monitor(unsigned long ExtIter) { - - /*--- Synchronization point after a single solver iteration. Compute the - wall clock time required. ---*/ - - StopTime = SU2_MPI::Wtime(); - - IterCount++; - UsedTime = (StopTime - StartTime) + UsedTimeCompute; - - /*--- Check if there is any change in the runtime parameters ---*/ - - CConfig *runtime = nullptr; - strcpy(runtime_file_name, "runtime.dat"); - runtime = new CConfig(runtime_file_name, config_container[ZONE_0]); - runtime->SetTimeIter(ExtIter); - delete runtime; - - /*--- Check whether the current simulation has reached the specified - convergence criteria, and set StopCalc to true, if so. ---*/ - - switch (config_container[ZONE_0]->GetKind_Solver()) { - case MAIN_SOLVER::EULER: case MAIN_SOLVER::NAVIER_STOKES: case MAIN_SOLVER::RANS: - case MAIN_SOLVER::NEMO_EULER: case MAIN_SOLVER::NEMO_NAVIER_STOKES: - StopCalc = integration_container[ZONE_0][INST_0][FLOW_SOL]->GetConvergence(); break; - case MAIN_SOLVER::HEAT_EQUATION: - StopCalc = integration_container[ZONE_0][INST_0][HEAT_SOL]->GetConvergence(); break; - case MAIN_SOLVER::FEM_ELASTICITY: - StopCalc = integration_container[ZONE_0][INST_0][FEA_SOL]->GetConvergence(); break; - case MAIN_SOLVER::ADJ_EULER: case MAIN_SOLVER::ADJ_NAVIER_STOKES: case MAIN_SOLVER::ADJ_RANS: - case MAIN_SOLVER::DISC_ADJ_EULER: case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_RANS: - case MAIN_SOLVER::DISC_ADJ_INC_EULER: case MAIN_SOLVER::DISC_ADJ_INC_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_INC_RANS: - case MAIN_SOLVER::DISC_ADJ_FEM_EULER: case MAIN_SOLVER::DISC_ADJ_FEM_NS: case MAIN_SOLVER::DISC_ADJ_FEM_RANS: - StopCalc = integration_container[ZONE_0][INST_0][ADJFLOW_SOL]->GetConvergence(); break; - default: - break; - } - - /*--- Set StopCalc to true if max. number of iterations has been reached ---*/ - - StopCalc = StopCalc || (ExtIter == Max_Iter - 1); - - return StopCalc; - + + /*--- Synchronization point after a single solver iteration. Compute the + wall clock time required. ---*/ + + StopTime = SU2_MPI::Wtime(); + + IterCount++; + UsedTime = (StopTime - StartTime) + UsedTimeCompute; + + /*--- Check if there is any change in the runtime parameters ---*/ + + CConfig *runtime = nullptr; + strcpy(runtime_file_name, "runtime.dat"); + runtime = new CConfig(runtime_file_name, config_container[ZONE_0]); + runtime->SetTimeIter(ExtIter); + delete runtime; + + /*--- Check whether the current simulation has reached the specified + convergence criteria, and set StopCalc to true, if so. ---*/ + + switch (config_container[ZONE_0]->GetKind_Solver()) { + case MAIN_SOLVER::EULER: case MAIN_SOLVER::NAVIER_STOKES: case MAIN_SOLVER::RANS: + case MAIN_SOLVER::NEMO_EULER: case MAIN_SOLVER::NEMO_NAVIER_STOKES: + StopCalc = integration_container[ZONE_0][INST_0][FLOW_SOL]->GetConvergence(); break; + case MAIN_SOLVER::HEAT_EQUATION: + StopCalc = integration_container[ZONE_0][INST_0][HEAT_SOL]->GetConvergence(); break; + case MAIN_SOLVER::FEM_ELASTICITY: + StopCalc = integration_container[ZONE_0][INST_0][FEA_SOL]->GetConvergence(); break; + case MAIN_SOLVER::ADJ_EULER: case MAIN_SOLVER::ADJ_NAVIER_STOKES: case MAIN_SOLVER::ADJ_RANS: + case MAIN_SOLVER::DISC_ADJ_EULER: case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_RANS: + case MAIN_SOLVER::DISC_ADJ_INC_EULER: case MAIN_SOLVER::DISC_ADJ_INC_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_INC_RANS: + case MAIN_SOLVER::DISC_ADJ_FEM_EULER: case MAIN_SOLVER::DISC_ADJ_FEM_NS: case MAIN_SOLVER::DISC_ADJ_FEM_RANS: + StopCalc = integration_container[ZONE_0][INST_0][ADJFLOW_SOL]->GetConvergence(); break; + default: + break; + } + + /*--- Set StopCalc to true if max. number of iterations has been reached ---*/ + + StopCalc = StopCalc || (ExtIter == Max_Iter - 1); + + return StopCalc; + } void CFluidDriver::Output(unsigned long InnerIter) { - - for (iZone = 0; iZone < nZone; iZone++) { - const auto inst = config_container[iZone]->GetiInst(); - - for (iInst = 0; iInst < nInst[iZone]; ++iInst) { - config_container[iZone]->SetiInst(iInst); - output_container[iZone]->SetResult_Files(geometry_container[iZone][iInst][MESH_0], - config_container[iZone], - solver_container[iZone][iInst][MESH_0], - InnerIter, StopCalc); + + for (iZone = 0; iZone < nZone; iZone++) { + const auto inst = config_container[iZone]->GetiInst(); + + for (iInst = 0; iInst < nInst[iZone]; ++iInst) { + config_container[iZone]->SetiInst(iInst); + output_container[iZone]->SetResult_Files(geometry_container[iZone][iInst][MESH_0], + config_container[iZone], + solver_container[iZone][iInst][MESH_0], + InnerIter, StopCalc); + } + config_container[iZone]->SetiInst(inst); } - config_container[iZone]->SetiInst(inst); - } - + } CTurbomachineryDriver::CTurbomachineryDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator): - CFluidDriver(confFile, val_nZone, MPICommunicator) { - - output_legacy = COutputFactory::CreateLegacyOutput(config_container[ZONE_0]); - - /*--- LEGACY OUTPUT (going to be removed soon) --- */ - - /*--- Open the convergence history file ---*/ - ConvHist_file = nullptr; - ConvHist_file = new ofstream*[nZone]; - for (iZone = 0; iZone < nZone; iZone++) { - ConvHist_file[iZone] = nullptr; - if (rank == MASTER_NODE){ - ConvHist_file[iZone] = new ofstream[nInst[iZone]]; - for (iInst = 0; iInst < nInst[iZone]; iInst++) { - output_legacy->SetConvHistory_Header(&ConvHist_file[iZone][iInst], config_container[iZone], iZone, iInst); - } +CFluidDriver(confFile, val_nZone, MPICommunicator) { + + output_legacy = COutputFactory::CreateLegacyOutput(config_container[ZONE_0]); + + /*--- LEGACY OUTPUT (going to be removed soon) --- */ + + /*--- Open the convergence history file ---*/ + ConvHist_file = nullptr; + ConvHist_file = new ofstream*[nZone]; + for (iZone = 0; iZone < nZone; iZone++) { + ConvHist_file[iZone] = nullptr; + if (rank == MASTER_NODE){ + ConvHist_file[iZone] = new ofstream[nInst[iZone]]; + for (iInst = 0; iInst < nInst[iZone]; iInst++) { + output_legacy->SetConvHistory_Header(&ConvHist_file[iZone][iInst], config_container[iZone], iZone, iInst); + } + } + } + + if (nZone > 1){ + Max_Iter = config_container[ZONE_0]->GetnOuter_Iter(); } - } - - if (nZone > 1){ - Max_Iter = config_container[ZONE_0]->GetnOuter_Iter(); - } } CTurbomachineryDriver::~CTurbomachineryDriver(void) { - if (rank == MASTER_NODE){ - /*--- Close the convergence history file. ---*/ - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < 1; iInst++) { - ConvHist_file[iZone][iInst].close(); - } - delete [] ConvHist_file[iZone]; + if (rank == MASTER_NODE){ + /*--- Close the convergence history file. ---*/ + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < 1; iInst++) { + ConvHist_file[iZone][iInst].close(); + } + delete [] ConvHist_file[iZone]; + } + delete [] ConvHist_file; } - delete [] ConvHist_file; - } } void CTurbomachineryDriver::Run() { - - /*--- Run a single iteration of a multi-zone problem by looping over all - zones and executing the iterations. Note that data transers between zones - and other intermediate procedures may be required. ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - iteration_container[iZone][INST_0]->Preprocess(output_container[iZone], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, iZone, INST_0); - } - - /* --- Update the mixing-plane interface ---*/ - for (iZone = 0; iZone < nZone; iZone++) { - if(mixingplane)SetMixingPlane(iZone); - } - - for (iZone = 0; iZone < nZone; iZone++) { - iteration_container[iZone][INST_0]->Iterate(output_container[iZone], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, iZone, INST_0); - } - - for (iZone = 0; iZone < nZone; iZone++) { - iteration_container[iZone][INST_0]->Postprocess(output_container[iZone], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, iZone, INST_0); - } - - if (rank == MASTER_NODE){ - SetTurboPerformance(ZONE_0); - } - - + + /*--- Run a single iteration of a multi-zone problem by looping over all + zones and executing the iterations. Note that data transers between zones + and other intermediate procedures may be required. ---*/ + + for (iZone = 0; iZone < nZone; iZone++) { + iteration_container[iZone][INST_0]->Preprocess(output_container[iZone], integration_container, geometry_container, + solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, iZone, INST_0); + } + + /* --- Update the mixing-plane interface ---*/ + for (iZone = 0; iZone < nZone; iZone++) { + if(mixingplane)SetMixingPlane(iZone); + } + + for (iZone = 0; iZone < nZone; iZone++) { + iteration_container[iZone][INST_0]->Iterate(output_container[iZone], integration_container, geometry_container, + solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, iZone, INST_0); + } + + for (iZone = 0; iZone < nZone; iZone++) { + iteration_container[iZone][INST_0]->Postprocess(output_container[iZone], integration_container, geometry_container, + solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, iZone, INST_0); + } + + if (rank == MASTER_NODE){ + SetTurboPerformance(ZONE_0); + } + + } void CTurbomachineryDriver::SetMixingPlane(unsigned short donorZone){ - - unsigned short targetZone, nMarkerInt, iMarkerInt ; - nMarkerInt = config_container[donorZone]->GetnMarker_MixingPlaneInterface()/2; - - /* --- transfer the average value from the donorZone to the targetZone*/ - for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++){ - for (targetZone = 0; targetZone < nZone; targetZone++) { - if (targetZone != donorZone){ - interface_container[donorZone][targetZone]->AllgatherAverage(solver_container[donorZone][INST_0][MESH_0][FLOW_SOL],solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], - geometry_container[donorZone][INST_0][MESH_0],geometry_container[targetZone][INST_0][MESH_0], - config_container[donorZone], config_container[targetZone], iMarkerInt ); - } + + unsigned short targetZone, nMarkerInt, iMarkerInt ; + nMarkerInt = config_container[donorZone]->GetnMarker_MixingPlaneInterface()/2; + + /* --- transfer the average value from the donorZone to the targetZone*/ + for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++){ + for (targetZone = 0; targetZone < nZone; targetZone++) { + if (targetZone != donorZone){ + interface_container[donorZone][targetZone]->AllgatherAverage(solver_container[donorZone][INST_0][MESH_0][FLOW_SOL],solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], + geometry_container[donorZone][INST_0][MESH_0],geometry_container[targetZone][INST_0][MESH_0], + config_container[donorZone], config_container[targetZone], iMarkerInt ); + } + } } - } } void CTurbomachineryDriver::SetTurboPerformance(unsigned short targetZone){ - - unsigned short donorZone; - //IMPORTANT this approach of multi-zone performances rely upon the fact that turbomachinery markers follow the natural (stator-rotor) development of the real machine. - /* --- transfer the local turboperfomance quantities (for each blade) from all the donorZones to the targetZone (ZONE_0) ---*/ - for (donorZone = 1; donorZone < nZone; donorZone++) { - interface_container[donorZone][targetZone]->GatherAverageValues(solver_container[donorZone][INST_0][MESH_0][FLOW_SOL],solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], donorZone); - } - - /* --- compute turboperformance for each stage and the global machine ---*/ - - output_legacy->ComputeTurboPerformance(solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], geometry_container[targetZone][INST_0][MESH_0], config_container[targetZone]); - + + unsigned short donorZone; + //IMPORTANT this approach of multi-zone performances rely upon the fact that turbomachinery markers follow the natural (stator-rotor) development of the real machine. + /* --- transfer the local turboperfomance quantities (for each blade) from all the donorZones to the targetZone (ZONE_0) ---*/ + for (donorZone = 1; donorZone < nZone; donorZone++) { + interface_container[donorZone][targetZone]->GatherAverageValues(solver_container[donorZone][INST_0][MESH_0][FLOW_SOL],solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], donorZone); + } + + /* --- compute turboperformance for each stage and the global machine ---*/ + + output_legacy->ComputeTurboPerformance(solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], geometry_container[targetZone][INST_0][MESH_0], config_container[targetZone]); + } bool CTurbomachineryDriver::Monitor(unsigned long ExtIter) { - - su2double rot_z_ini, rot_z_final ,rot_z; - su2double outPres_ini, outPres_final, outPres; - unsigned long rampFreq, finalRamp_Iter; - unsigned short iMarker, KindBC, KindBCOption; - string Marker_Tag; - - bool print; - - /*--- Synchronization point after a single solver iteration. Compute the - wall clock time required. ---*/ - - StopTime = SU2_MPI::Wtime(); - - IterCount++; - UsedTime = (StopTime - StartTime); - - - /*--- Check if there is any change in the runtime parameters ---*/ - CConfig *runtime = nullptr; - strcpy(runtime_file_name, "runtime.dat"); - runtime = new CConfig(runtime_file_name, config_container[ZONE_0]); - runtime->SetInnerIter(ExtIter); - delete runtime; - - /*--- Update the convergence history file (serial and parallel computations). ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++) - output_legacy->SetConvHistory_Body(&ConvHist_file[iZone][iInst], geometry_container, solver_container, - config_container, integration_container, false, UsedTime, iZone, iInst); - } - - /*--- ROTATING FRAME Ramp: Compute the updated rotational velocity. ---*/ - if (config_container[ZONE_0]->GetGrid_Movement() && config_container[ZONE_0]->GetRampRotatingFrame()) { - rampFreq = SU2_TYPE::Int(config_container[ZONE_0]->GetRampRotatingFrame_Coeff(1)); - finalRamp_Iter = SU2_TYPE::Int(config_container[ZONE_0]->GetRampRotatingFrame_Coeff(2)); - rot_z_ini = config_container[ZONE_0]->GetRampRotatingFrame_Coeff(0); - print = false; - if(ExtIter % rampFreq == 0 && ExtIter <= finalRamp_Iter){ - - for (iZone = 0; iZone < nZone; iZone++) { - rot_z_final = config_container[iZone]->GetFinalRotation_Rate_Z(); - if(abs(rot_z_final) > 0.0){ - rot_z = rot_z_ini + ExtIter*( rot_z_final - rot_z_ini)/finalRamp_Iter; - config_container[iZone]->SetRotation_Rate(2, rot_z); - if(rank == MASTER_NODE && print && ExtIter > 0) { - cout << endl << " Updated rotating frame grid velocities"; - cout << " for zone " << iZone << "." << endl; - } - geometry_container[iZone][INST_0][MESH_0]->SetRotationalVelocity(config_container[iZone], print); - geometry_container[iZone][INST_0][MESH_0]->SetShroudVelocity(config_container[iZone]); + + su2double rot_z_ini, rot_z_final ,rot_z; + su2double outPres_ini, outPres_final, outPres; + unsigned long rampFreq, finalRamp_Iter; + unsigned short iMarker, KindBC, KindBCOption; + string Marker_Tag; + + bool print; + + /*--- Synchronization point after a single solver iteration. Compute the + wall clock time required. ---*/ + + StopTime = SU2_MPI::Wtime(); + + IterCount++; + UsedTime = (StopTime - StartTime); + + + /*--- Check if there is any change in the runtime parameters ---*/ + CConfig *runtime = nullptr; + strcpy(runtime_file_name, "runtime.dat"); + runtime = new CConfig(runtime_file_name, config_container[ZONE_0]); + runtime->SetInnerIter(ExtIter); + delete runtime; + + /*--- Update the convergence history file (serial and parallel computations). ---*/ + + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < nInst[iZone]; iInst++) + output_legacy->SetConvHistory_Body(&ConvHist_file[iZone][iInst], geometry_container, solver_container, + config_container, integration_container, false, UsedTime, iZone, iInst); + } + + /*--- ROTATING FRAME Ramp: Compute the updated rotational velocity. ---*/ + if (config_container[ZONE_0]->GetGrid_Movement() && config_container[ZONE_0]->GetRampRotatingFrame()) { + rampFreq = SU2_TYPE::Int(config_container[ZONE_0]->GetRampRotatingFrame_Coeff(1)); + finalRamp_Iter = SU2_TYPE::Int(config_container[ZONE_0]->GetRampRotatingFrame_Coeff(2)); + rot_z_ini = config_container[ZONE_0]->GetRampRotatingFrame_Coeff(0); + print = false; + if(ExtIter % rampFreq == 0 && ExtIter <= finalRamp_Iter){ + + for (iZone = 0; iZone < nZone; iZone++) { + rot_z_final = config_container[iZone]->GetFinalRotation_Rate_Z(); + if(abs(rot_z_final) > 0.0){ + rot_z = rot_z_ini + ExtIter*( rot_z_final - rot_z_ini)/finalRamp_Iter; + config_container[iZone]->SetRotation_Rate(2, rot_z); + if(rank == MASTER_NODE && print && ExtIter > 0) { + cout << endl << " Updated rotating frame grid velocities"; + cout << " for zone " << iZone << "." << endl; + } + geometry_container[iZone][INST_0][MESH_0]->SetRotationalVelocity(config_container[iZone], print); + geometry_container[iZone][INST_0][MESH_0]->SetShroudVelocity(config_container[iZone]); + } + } + + for (iZone = 0; iZone < nZone; iZone++) { + geometry_container[iZone][INST_0][MESH_0]->SetAvgTurboValue(config_container[iZone], iZone, INFLOW, false); + geometry_container[iZone][INST_0][MESH_0]->SetAvgTurboValue(config_container[iZone],iZone, OUTFLOW, false); + geometry_container[iZone][INST_0][MESH_0]->GatherInOutAverageValues(config_container[iZone], false); + + } + + for (iZone = 1; iZone < nZone; iZone++) { + interface_container[iZone][ZONE_0]->GatherAverageTurboGeoValues(geometry_container[iZone][INST_0][MESH_0],geometry_container[ZONE_0][INST_0][MESH_0], iZone); + } + } - } - - for (iZone = 0; iZone < nZone; iZone++) { - geometry_container[iZone][INST_0][MESH_0]->SetAvgTurboValue(config_container[iZone], iZone, INFLOW, false); - geometry_container[iZone][INST_0][MESH_0]->SetAvgTurboValue(config_container[iZone],iZone, OUTFLOW, false); - geometry_container[iZone][INST_0][MESH_0]->GatherInOutAverageValues(config_container[iZone], false); - - } - - for (iZone = 1; iZone < nZone; iZone++) { - interface_container[iZone][ZONE_0]->GatherAverageTurboGeoValues(geometry_container[iZone][INST_0][MESH_0],geometry_container[ZONE_0][INST_0][MESH_0], iZone); - } - } - } - - - /*--- Outlet Pressure Ramp: Compute the updated rotational velocity. ---*/ - if (config_container[ZONE_0]->GetRampOutletPressure()) { - rampFreq = SU2_TYPE::Int(config_container[ZONE_0]->GetRampOutletPressure_Coeff(1)); - finalRamp_Iter = SU2_TYPE::Int(config_container[ZONE_0]->GetRampOutletPressure_Coeff(2)); - outPres_ini = config_container[ZONE_0]->GetRampOutletPressure_Coeff(0); - outPres_final = config_container[ZONE_0]->GetFinalOutletPressure(); - - if(ExtIter % rampFreq == 0 && ExtIter <= finalRamp_Iter){ - outPres = outPres_ini + ExtIter*(outPres_final - outPres_ini)/finalRamp_Iter; - if(rank == MASTER_NODE) config_container[ZONE_0]->SetMonitotOutletPressure(outPres); - - for (iZone = 0; iZone < nZone; iZone++) { - for (iMarker = 0; iMarker < config_container[iZone]->GetnMarker_All(); iMarker++) { - KindBC = config_container[iZone]->GetMarker_All_KindBC(iMarker); - switch (KindBC) { - case RIEMANN_BOUNDARY: - Marker_Tag = config_container[iZone]->GetMarker_All_TagBound(iMarker); - KindBCOption = config_container[iZone]->GetKind_Data_Riemann(Marker_Tag); - if(KindBCOption == STATIC_PRESSURE || KindBCOption == RADIAL_EQUILIBRIUM ){ - SU2_MPI::Error("Outlet pressure ramp only implemented for NRBC", CURRENT_FUNCTION); - } - break; - case GILES_BOUNDARY: - Marker_Tag = config_container[iZone]->GetMarker_All_TagBound(iMarker); - KindBCOption = config_container[iZone]->GetKind_Data_Giles(Marker_Tag); - if(KindBCOption == STATIC_PRESSURE || KindBCOption == STATIC_PRESSURE_1D || KindBCOption == RADIAL_EQUILIBRIUM ){ - config_container[iZone]->SetGiles_Var1(outPres, Marker_Tag); + + + /*--- Outlet Pressure Ramp: Compute the updated rotational velocity. ---*/ + if (config_container[ZONE_0]->GetRampOutletPressure()) { + rampFreq = SU2_TYPE::Int(config_container[ZONE_0]->GetRampOutletPressure_Coeff(1)); + finalRamp_Iter = SU2_TYPE::Int(config_container[ZONE_0]->GetRampOutletPressure_Coeff(2)); + outPres_ini = config_container[ZONE_0]->GetRampOutletPressure_Coeff(0); + outPres_final = config_container[ZONE_0]->GetFinalOutletPressure(); + + if(ExtIter % rampFreq == 0 && ExtIter <= finalRamp_Iter){ + outPres = outPres_ini + ExtIter*(outPres_final - outPres_ini)/finalRamp_Iter; + if(rank == MASTER_NODE) config_container[ZONE_0]->SetMonitotOutletPressure(outPres); + + for (iZone = 0; iZone < nZone; iZone++) { + for (iMarker = 0; iMarker < config_container[iZone]->GetnMarker_All(); iMarker++) { + KindBC = config_container[iZone]->GetMarker_All_KindBC(iMarker); + switch (KindBC) { + case RIEMANN_BOUNDARY: + Marker_Tag = config_container[iZone]->GetMarker_All_TagBound(iMarker); + KindBCOption = config_container[iZone]->GetKind_Data_Riemann(Marker_Tag); + if(KindBCOption == STATIC_PRESSURE || KindBCOption == RADIAL_EQUILIBRIUM ){ + SU2_MPI::Error("Outlet pressure ramp only implemented for NRBC", CURRENT_FUNCTION); + } + break; + case GILES_BOUNDARY: + Marker_Tag = config_container[iZone]->GetMarker_All_TagBound(iMarker); + KindBCOption = config_container[iZone]->GetKind_Data_Giles(Marker_Tag); + if(KindBCOption == STATIC_PRESSURE || KindBCOption == STATIC_PRESSURE_1D || KindBCOption == RADIAL_EQUILIBRIUM ){ + config_container[iZone]->SetGiles_Var1(outPres, Marker_Tag); + } + break; + } + } } - break; - } } - } } - } - - - /*--- Check whether the current simulation has reached the specified - convergence criteria, and set StopCalc to true, if so. ---*/ - - switch (config_container[ZONE_0]->GetKind_Solver()) { - case MAIN_SOLVER::EULER: case MAIN_SOLVER::NAVIER_STOKES: case MAIN_SOLVER::RANS: - case MAIN_SOLVER::INC_EULER: case MAIN_SOLVER::INC_NAVIER_STOKES: case MAIN_SOLVER::INC_RANS: - case MAIN_SOLVER::NEMO_EULER: case MAIN_SOLVER::NEMO_NAVIER_STOKES: - StopCalc = integration_container[ZONE_0][INST_0][FLOW_SOL]->GetConvergence(); - break; - case MAIN_SOLVER::DISC_ADJ_EULER: case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_RANS: - case MAIN_SOLVER::DISC_ADJ_INC_EULER: case MAIN_SOLVER::DISC_ADJ_INC_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_INC_RANS: - case MAIN_SOLVER::DISC_ADJ_FEM_EULER: case MAIN_SOLVER::DISC_ADJ_FEM_NS: case MAIN_SOLVER::DISC_ADJ_FEM_RANS: - StopCalc = integration_container[ZONE_0][INST_0][ADJFLOW_SOL]->GetConvergence(); - break; - default: - break; - - } - - /*--- Set StopCalc to true if max. number of iterations has been reached ---*/ - - StopCalc = StopCalc || (ExtIter == Max_Iter - 1); - - return StopCalc; - + + + /*--- Check whether the current simulation has reached the specified + convergence criteria, and set StopCalc to true, if so. ---*/ + + switch (config_container[ZONE_0]->GetKind_Solver()) { + case MAIN_SOLVER::EULER: case MAIN_SOLVER::NAVIER_STOKES: case MAIN_SOLVER::RANS: + case MAIN_SOLVER::INC_EULER: case MAIN_SOLVER::INC_NAVIER_STOKES: case MAIN_SOLVER::INC_RANS: + case MAIN_SOLVER::NEMO_EULER: case MAIN_SOLVER::NEMO_NAVIER_STOKES: + StopCalc = integration_container[ZONE_0][INST_0][FLOW_SOL]->GetConvergence(); + break; + case MAIN_SOLVER::DISC_ADJ_EULER: case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_RANS: + case MAIN_SOLVER::DISC_ADJ_INC_EULER: case MAIN_SOLVER::DISC_ADJ_INC_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_INC_RANS: + case MAIN_SOLVER::DISC_ADJ_FEM_EULER: case MAIN_SOLVER::DISC_ADJ_FEM_NS: case MAIN_SOLVER::DISC_ADJ_FEM_RANS: + StopCalc = integration_container[ZONE_0][INST_0][ADJFLOW_SOL]->GetConvergence(); + break; + default: + break; + + } + + /*--- Set StopCalc to true if max. number of iterations has been reached ---*/ + + StopCalc = StopCalc || (ExtIter == Max_Iter - 1); + + return StopCalc; + } CHBDriver::CHBDriver(char* confFile, - unsigned short val_nZone, - SU2_Comm MPICommunicator) : CFluidDriver(confFile, - val_nZone, - MPICommunicator) { - unsigned short kInst; - - nInstHB = nInst[ZONE_0]; - - D = nullptr; - /*--- allocate dynamic memory for the Harmonic Balance operator ---*/ - D = new su2double*[nInstHB]; for (kInst = 0; kInst < nInstHB; kInst++) D[kInst] = new su2double[nInstHB]; - - output_legacy = COutputFactory::CreateLegacyOutput(config_container[ZONE_0]); - - /*--- Open the convergence history file ---*/ - ConvHist_file = nullptr; - ConvHist_file = new ofstream*[nZone]; - for (iZone = 0; iZone < nZone; iZone++) { - ConvHist_file[iZone] = nullptr; - if (rank == MASTER_NODE){ - ConvHist_file[iZone] = new ofstream[nInst[iZone]]; - for (iInst = 0; iInst < nInst[iZone]; iInst++) { - output_legacy->SetConvHistory_Header(&ConvHist_file[iZone][iInst], config_container[iZone], iZone, iInst); - } - } - } - - -} + unsigned short val_nZone, + SU2_Comm MPICommunicator) : CFluidDriver(confFile, + val_nZone, + MPICommunicator) { + unsigned short kInst; + + nInstHB = nInst[ZONE_0]; + + D = nullptr; + /*--- allocate dynamic memory for the Harmonic Balance operator ---*/ + D = new su2double*[nInstHB]; for (kInst = 0; kInst < nInstHB; kInst++) D[kInst] = new su2double[nInstHB]; + + output_legacy = COutputFactory::CreateLegacyOutput(config_container[ZONE_0]); + + /*--- Open the convergence history file ---*/ + ConvHist_file = nullptr; + ConvHist_file = new ofstream*[nZone]; + for (iZone = 0; iZone < nZone; iZone++) { + ConvHist_file[iZone] = nullptr; + if (rank == MASTER_NODE){ + ConvHist_file[iZone] = new ofstream[nInst[iZone]]; + for (iInst = 0; iInst < nInst[iZone]; iInst++) { + output_legacy->SetConvHistory_Header(&ConvHist_file[iZone][iInst], config_container[iZone], iZone, iInst); + } + } + } + + + } CHBDriver::~CHBDriver(void) { - - unsigned short kInst; - - /*--- delete dynamic memory for the Harmonic Balance operator ---*/ - for (kInst = 0; kInst < nInstHB; kInst++) delete [] D[kInst]; - delete [] D; - - if (rank == MASTER_NODE){ - /*--- Close the convergence history file. ---*/ - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInstHB; iInst++) { - ConvHist_file[iZone][iInst].close(); + + unsigned short kInst; + + /*--- delete dynamic memory for the Harmonic Balance operator ---*/ + for (kInst = 0; kInst < nInstHB; kInst++) delete [] D[kInst]; + delete [] D; + + if (rank == MASTER_NODE){ + /*--- Close the convergence history file. ---*/ + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < nInstHB; iInst++) { + ConvHist_file[iZone][iInst].close(); + } + delete [] ConvHist_file[iZone]; + } + delete [] ConvHist_file; } - delete [] ConvHist_file[iZone]; - } - delete [] ConvHist_file; - } } void CHBDriver::Run() { - - /*--- Run a single iteration of a Harmonic Balance problem. Preprocess all - all zones before beginning the iteration. ---*/ - - for (iInst = 0; iInst < nInstHB; iInst++) - iteration_container[ZONE_0][iInst]->Preprocess(output_container[ZONE_0], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, ZONE_0, iInst); - - for (iInst = 0; iInst < nInstHB; iInst++) - iteration_container[ZONE_0][iInst]->Iterate(output_container[ZONE_0], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, ZONE_0, iInst); - - /*--- Update the convergence history file (serial and parallel computations). ---*/ - - for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++) - output_legacy->SetConvHistory_Body(&ConvHist_file[iZone][iInst], geometry_container, solver_container, - config_container, integration_container, false, UsedTime, iZone, iInst); - } - + + /*--- Run a single iteration of a Harmonic Balance problem. Preprocess all + all zones before beginning the iteration. ---*/ + + for (iInst = 0; iInst < nInstHB; iInst++) + iteration_container[ZONE_0][iInst]->Preprocess(output_container[ZONE_0], integration_container, geometry_container, + solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, ZONE_0, iInst); + + for (iInst = 0; iInst < nInstHB; iInst++) + iteration_container[ZONE_0][iInst]->Iterate(output_container[ZONE_0], integration_container, geometry_container, + solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, ZONE_0, iInst); + + /*--- Update the convergence history file (serial and parallel computations). ---*/ + + for (iZone = 0; iZone < nZone; iZone++) { + for (iInst = 0; iInst < nInst[iZone]; iInst++) + output_legacy->SetConvHistory_Body(&ConvHist_file[iZone][iInst], geometry_container, solver_container, + config_container, integration_container, false, UsedTime, iZone, iInst); + } + } void CHBDriver::Update() { - - for (iInst = 0; iInst < nInstHB; iInst++) { - /*--- Compute the harmonic balance terms across all zones ---*/ - SetHarmonicBalance(iInst); - - } - - /*--- Precondition the harmonic balance source terms ---*/ - if (config_container[ZONE_0]->GetHB_Precondition() == YES) { - StabilizeHarmonicBalance(); - - } - - for (iInst = 0; iInst < nInstHB; iInst++) { - - /*--- Update the harmonic balance terms across all zones ---*/ - iteration_container[ZONE_0][iInst]->Update(output_container[ZONE_0], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, ZONE_0, iInst); - - } - + + for (iInst = 0; iInst < nInstHB; iInst++) { + /*--- Compute the harmonic balance terms across all zones ---*/ + SetHarmonicBalance(iInst); + + } + + /*--- Precondition the harmonic balance source terms ---*/ + if (config_container[ZONE_0]->GetHB_Precondition() == YES) { + StabilizeHarmonicBalance(); + + } + + for (iInst = 0; iInst < nInstHB; iInst++) { + + /*--- Update the harmonic balance terms across all zones ---*/ + iteration_container[ZONE_0][iInst]->Update(output_container[ZONE_0], integration_container, geometry_container, + solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, ZONE_0, iInst); + + } + } void CHBDriver::ResetConvergence() { - - for(iInst = 0; iInst < nZone; iInst++) { - switch (config_container[ZONE_0]->GetKind_Solver()) { - - case MAIN_SOLVER::EULER: case MAIN_SOLVER::NAVIER_STOKES: case MAIN_SOLVER::RANS: - integration_container[ZONE_0][iInst][FLOW_SOL]->SetConvergence(false); - if (config_container[ZONE_0]->GetKind_Solver() == MAIN_SOLVER::RANS) integration_container[ZONE_0][iInst][TURB_SOL]->SetConvergence(false); - if(config_container[ZONE_0]->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM) integration_container[ZONE_0][iInst][TRANS_SOL]->SetConvergence(false); - break; - - case MAIN_SOLVER::FEM_ELASTICITY: - integration_container[ZONE_0][iInst][FEA_SOL]->SetConvergence(false); - break; - - case MAIN_SOLVER::ADJ_EULER: case MAIN_SOLVER::ADJ_NAVIER_STOKES: case MAIN_SOLVER::ADJ_RANS: case MAIN_SOLVER::DISC_ADJ_EULER: case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_RANS: - integration_container[ZONE_0][iInst][ADJFLOW_SOL]->SetConvergence(false); - if( (config_container[ZONE_0]->GetKind_Solver() == MAIN_SOLVER::ADJ_RANS) || (config_container[ZONE_0]->GetKind_Solver() == MAIN_SOLVER::DISC_ADJ_RANS) ) - integration_container[ZONE_0][iInst][ADJTURB_SOL]->SetConvergence(false); - break; - - default: - SU2_MPI::Error("Harmonic Balance has not been set up for this solver.", CURRENT_FUNCTION); + + for(iInst = 0; iInst < nZone; iInst++) { + switch (config_container[ZONE_0]->GetKind_Solver()) { + + case MAIN_SOLVER::EULER: case MAIN_SOLVER::NAVIER_STOKES: case MAIN_SOLVER::RANS: + integration_container[ZONE_0][iInst][FLOW_SOL]->SetConvergence(false); + if (config_container[ZONE_0]->GetKind_Solver() == MAIN_SOLVER::RANS) integration_container[ZONE_0][iInst][TURB_SOL]->SetConvergence(false); + if(config_container[ZONE_0]->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM) integration_container[ZONE_0][iInst][TRANS_SOL]->SetConvergence(false); + break; + + case MAIN_SOLVER::FEM_ELASTICITY: + integration_container[ZONE_0][iInst][FEA_SOL]->SetConvergence(false); + break; + + case MAIN_SOLVER::ADJ_EULER: case MAIN_SOLVER::ADJ_NAVIER_STOKES: case MAIN_SOLVER::ADJ_RANS: case MAIN_SOLVER::DISC_ADJ_EULER: case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_RANS: + integration_container[ZONE_0][iInst][ADJFLOW_SOL]->SetConvergence(false); + if( (config_container[ZONE_0]->GetKind_Solver() == MAIN_SOLVER::ADJ_RANS) || (config_container[ZONE_0]->GetKind_Solver() == MAIN_SOLVER::DISC_ADJ_RANS) ) + integration_container[ZONE_0][iInst][ADJTURB_SOL]->SetConvergence(false); + break; + + default: + SU2_MPI::Error("Harmonic Balance has not been set up for this solver.", CURRENT_FUNCTION); + } } - } - + } void CHBDriver::SetHarmonicBalance(unsigned short iInst) { - - unsigned short iVar, jInst, iMGlevel; - unsigned short nVar = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - unsigned long iPoint; - bool implicit = (config_container[ZONE_0]->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - bool adjoint = (config_container[ZONE_0]->GetContinuous_Adjoint()); - if (adjoint) { - implicit = (config_container[ZONE_0]->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); - } - - unsigned long InnerIter = config_container[ZONE_0]->GetInnerIter(); - - /*--- Retrieve values from the config file ---*/ - su2double *U = new su2double[nVar]; - su2double *U_old = new su2double[nVar]; - su2double *Psi = new su2double[nVar]; - su2double *Psi_old = new su2double[nVar]; - su2double *Source = new su2double[nVar]; - su2double deltaU, deltaPsi; - - /*--- Compute period of oscillation ---*/ - su2double period = config_container[ZONE_0]->GetHarmonicBalance_Period(); - - /*--- Non-dimensionalize the input period, if necessary. */ - period /= config_container[ZONE_0]->GetTime_Ref(); - - if (InnerIter == 0) - ComputeHB_Operator(); - - /*--- Compute various source terms for explicit direct, implicit direct, and adjoint problems ---*/ - /*--- Loop over all grid levels ---*/ - for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++) { - - /*--- Loop over each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry_container[ZONE_0][iInst][iMGlevel]->GetnPoint(); iPoint++) { - - for (iVar = 0; iVar < nVar; iVar++) { - Source[iVar] = 0.0; - } - - /*--- Step across the columns ---*/ - for (jInst = 0; jInst < nInstHB; jInst++) { - - /*--- Retrieve solution at this node in current zone ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - - if (!adjoint) { - U[iVar] = solver_container[ZONE_0][jInst][iMGlevel][FLOW_SOL]->GetNodes()->GetSolution(iPoint, iVar); - Source[iVar] += U[iVar]*D[iInst][jInst]; - - if (implicit) { - U_old[iVar] = solver_container[ZONE_0][jInst][iMGlevel][FLOW_SOL]->GetNodes()->GetSolution_Old(iPoint, iVar); - deltaU = U[iVar] - U_old[iVar]; - Source[iVar] += deltaU*D[iInst][jInst]; + + unsigned short iVar, jInst, iMGlevel; + unsigned short nVar = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetnVar(); + unsigned long iPoint; + bool implicit = (config_container[ZONE_0]->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); + bool adjoint = (config_container[ZONE_0]->GetContinuous_Adjoint()); + if (adjoint) { + implicit = (config_container[ZONE_0]->GetKind_TimeIntScheme_AdjFlow() == EULER_IMPLICIT); + } + + unsigned long InnerIter = config_container[ZONE_0]->GetInnerIter(); + + /*--- Retrieve values from the config file ---*/ + su2double *U = new su2double[nVar]; + su2double *U_old = new su2double[nVar]; + su2double *Psi = new su2double[nVar]; + su2double *Psi_old = new su2double[nVar]; + su2double *Source = new su2double[nVar]; + su2double deltaU, deltaPsi; + + /*--- Compute period of oscillation ---*/ + su2double period = config_container[ZONE_0]->GetHarmonicBalance_Period(); + + /*--- Non-dimensionalize the input period, if necessary. */ + period /= config_container[ZONE_0]->GetTime_Ref(); + + if (InnerIter == 0) + ComputeHB_Operator(); + + /*--- Compute various source terms for explicit direct, implicit direct, and adjoint problems ---*/ + /*--- Loop over all grid levels ---*/ + for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++) { + + /*--- Loop over each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry_container[ZONE_0][iInst][iMGlevel]->GetnPoint(); iPoint++) { + + for (iVar = 0; iVar < nVar; iVar++) { + Source[iVar] = 0.0; } - - } - - else { - Psi[iVar] = solver_container[ZONE_0][jInst][iMGlevel][ADJFLOW_SOL]->GetNodes()->GetSolution(iPoint, iVar); - Source[iVar] += Psi[iVar]*D[jInst][iInst]; - - if (implicit) { - Psi_old[iVar] = solver_container[ZONE_0][jInst][iMGlevel][ADJFLOW_SOL]->GetNodes()->GetSolution_Old(iPoint, iVar); - deltaPsi = Psi[iVar] - Psi_old[iVar]; - Source[iVar] += deltaPsi*D[jInst][iInst]; + + /*--- Step across the columns ---*/ + for (jInst = 0; jInst < nInstHB; jInst++) { + + /*--- Retrieve solution at this node in current zone ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + + if (!adjoint) { + U[iVar] = solver_container[ZONE_0][jInst][iMGlevel][FLOW_SOL]->GetNodes()->GetSolution(iPoint, iVar); + Source[iVar] += U[iVar]*D[iInst][jInst]; + + if (implicit) { + U_old[iVar] = solver_container[ZONE_0][jInst][iMGlevel][FLOW_SOL]->GetNodes()->GetSolution_Old(iPoint, iVar); + deltaU = U[iVar] - U_old[iVar]; + Source[iVar] += deltaU*D[iInst][jInst]; + } + + } + + else { + Psi[iVar] = solver_container[ZONE_0][jInst][iMGlevel][ADJFLOW_SOL]->GetNodes()->GetSolution(iPoint, iVar); + Source[iVar] += Psi[iVar]*D[jInst][iInst]; + + if (implicit) { + Psi_old[iVar] = solver_container[ZONE_0][jInst][iMGlevel][ADJFLOW_SOL]->GetNodes()->GetSolution_Old(iPoint, iVar); + deltaPsi = Psi[iVar] - Psi_old[iVar]; + Source[iVar] += deltaPsi*D[jInst][iInst]; + } + } + } + + /*--- Store sources for current row ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + if (!adjoint) { + solver_container[ZONE_0][iInst][iMGlevel][FLOW_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source[iVar]); + } + else { + solver_container[ZONE_0][iInst][iMGlevel][ADJFLOW_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source[iVar]); + } + } + } - } - } - - /*--- Store sources for current row ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - if (!adjoint) { - solver_container[ZONE_0][iInst][iMGlevel][FLOW_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source[iVar]); - } - else { - solver_container[ZONE_0][iInst][iMGlevel][ADJFLOW_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source[iVar]); - } } - - } } - } - - /*--- Source term for a turbulence model ---*/ - if (config_container[ZONE_0]->GetKind_Solver() == MAIN_SOLVER::RANS) { - - /*--- Extra variables needed if we have a turbulence model. ---*/ - unsigned short nVar_Turb = solver_container[ZONE_0][INST_0][MESH_0][TURB_SOL]->GetnVar(); - su2double *U_Turb = new su2double[nVar_Turb]; - su2double *Source_Turb = new su2double[nVar_Turb]; - - /*--- Loop over only the finest mesh level (turbulence is always solved - on the original grid only). ---*/ - for (iPoint = 0; iPoint < geometry_container[ZONE_0][INST_0][MESH_0]->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < nVar_Turb; iVar++) Source_Turb[iVar] = 0.0; - for (jInst = 0; jInst < nInstHB; jInst++) { - - /*--- Retrieve solution at this node in current zone ---*/ - for (iVar = 0; iVar < nVar_Turb; iVar++) { - U_Turb[iVar] = solver_container[ZONE_0][jInst][MESH_0][TURB_SOL]->GetNodes()->GetSolution(iPoint, iVar); - Source_Turb[iVar] += U_Turb[iVar]*D[iInst][jInst]; + + /*--- Source term for a turbulence model ---*/ + if (config_container[ZONE_0]->GetKind_Solver() == MAIN_SOLVER::RANS) { + + /*--- Extra variables needed if we have a turbulence model. ---*/ + unsigned short nVar_Turb = solver_container[ZONE_0][INST_0][MESH_0][TURB_SOL]->GetnVar(); + su2double *U_Turb = new su2double[nVar_Turb]; + su2double *Source_Turb = new su2double[nVar_Turb]; + + /*--- Loop over only the finest mesh level (turbulence is always solved + on the original grid only). ---*/ + for (iPoint = 0; iPoint < geometry_container[ZONE_0][INST_0][MESH_0]->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < nVar_Turb; iVar++) Source_Turb[iVar] = 0.0; + for (jInst = 0; jInst < nInstHB; jInst++) { + + /*--- Retrieve solution at this node in current zone ---*/ + for (iVar = 0; iVar < nVar_Turb; iVar++) { + U_Turb[iVar] = solver_container[ZONE_0][jInst][MESH_0][TURB_SOL]->GetNodes()->GetSolution(iPoint, iVar); + Source_Turb[iVar] += U_Turb[iVar]*D[iInst][jInst]; + } + } + + /*--- Store sources for current iZone ---*/ + for (iVar = 0; iVar < nVar_Turb; iVar++) + solver_container[ZONE_0][iInst][MESH_0][TURB_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source_Turb[iVar]); } - } - - /*--- Store sources for current iZone ---*/ - for (iVar = 0; iVar < nVar_Turb; iVar++) - solver_container[ZONE_0][iInst][MESH_0][TURB_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source_Turb[iVar]); - } - - delete [] U_Turb; - delete [] Source_Turb; - } - - delete [] Source; - delete [] U; - delete [] U_old; - delete [] Psi; - delete [] Psi_old; - + + delete [] U_Turb; + delete [] Source_Turb; + } + + delete [] Source; + delete [] U; + delete [] U_old; + delete [] Psi; + delete [] Psi_old; + } void CHBDriver::StabilizeHarmonicBalance() { + + unsigned short i, j, k, iVar, iInst, jInst, iMGlevel; + unsigned short nVar = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetnVar(); + unsigned long iPoint; + bool adjoint = (config_container[ZONE_0]->GetContinuous_Adjoint()); + + /*--- Retrieve values from the config file ---*/ + su2double *Source = new su2double[nInstHB]; + su2double *Source_old = new su2double[nInstHB]; + su2double Delta; + + su2double **Pinv = new su2double*[nInstHB]; + su2double **P = new su2double*[nInstHB]; + for (iInst = 0; iInst < nInstHB; iInst++) { + Pinv[iInst] = new su2double[nInstHB]; + P[iInst] = new su2double[nInstHB]; + } + + /*--- Loop over all grid levels ---*/ + for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++) { + + /*--- Loop over each node in the volume mesh ---*/ + for (iPoint = 0; iPoint < geometry_container[ZONE_0][INST_0][iMGlevel]->GetnPoint(); iPoint++) { + + /*--- Get time step for current node ---*/ + Delta = solver_container[ZONE_0][INST_0][iMGlevel][FLOW_SOL]->GetNodes()->GetDelta_Time(iPoint); + + /*--- Setup stabilization matrix for this node ---*/ + for (iInst = 0; iInst < nInstHB; iInst++) { + for (jInst = 0; jInst < nInstHB; jInst++) { + if (jInst == iInst ) { + Pinv[iInst][jInst] = 1.0 + Delta*D[iInst][jInst]; + } + else { + Pinv[iInst][jInst] = Delta*D[iInst][jInst]; + } + } + } + + /*--- Invert stabilization matrix Pinv with Gauss elimination---*/ + + /*-- A temporary matrix to hold the inverse, dynamically allocated ---*/ + su2double **temp = new su2double*[nInstHB]; + for (i = 0; i < nInstHB; i++) { + temp[i] = new su2double[2 * nInstHB]; + } + + /*--- Copy the desired matrix into the temporary matrix ---*/ + for (i = 0; i < nInstHB; i++) { + for (j = 0; j < nInstHB; j++) { + temp[i][j] = Pinv[i][j]; + temp[i][nInstHB + j] = 0; + } + temp[i][nInstHB + i] = 1; + } + + su2double max_val; + unsigned short max_idx; + + /*--- Pivot each column such that the largest number possible divides the other rows ---*/ + for (k = 0; k < nInstHB - 1; k++) { + max_idx = k; + max_val = abs(temp[k][k]); + /*--- Find the largest value (pivot) in the column ---*/ + for (j = k; j < nInstHB; j++) { + if (abs(temp[j][k]) > max_val) { + max_idx = j; + max_val = abs(temp[j][k]); + } + } + + /*--- Move the row with the highest value up ---*/ + for (j = 0; j < (nInstHB * 2); j++) { + su2double d = temp[k][j]; + temp[k][j] = temp[max_idx][j]; + temp[max_idx][j] = d; + } + /*--- Subtract the moved row from all other rows ---*/ + for (i = k + 1; i < nInstHB; i++) { + su2double c = temp[i][k] / temp[k][k]; + for (j = 0; j < (nInstHB * 2); j++) { + temp[i][j] = temp[i][j] - temp[k][j] * c; + } + } + } + + /*--- Back-substitution ---*/ + for (k = nInstHB - 1; k > 0; k--) { + if (temp[k][k] != su2double(0.0)) { + for (int i = k - 1; i > -1; i--) { + su2double c = temp[i][k] / temp[k][k]; + for (j = 0; j < (nInstHB * 2); j++) { + temp[i][j] = temp[i][j] - temp[k][j] * c; + } + } + } + } + + /*--- Normalize the inverse ---*/ + for (i = 0; i < nInstHB; i++) { + su2double c = temp[i][i]; + for (j = 0; j < nInstHB; j++) { + temp[i][j + nInstHB] = temp[i][j + nInstHB] / c; + } + } + + /*--- Copy the inverse back to the main program flow ---*/ + for (i = 0; i < nInstHB; i++) { + for (j = 0; j < nInstHB; j++) { + P[i][j] = temp[i][j + nInstHB]; + } + } + + /*--- Delete dynamic template ---*/ + for (iInst = 0; iInst < nInstHB; iInst++) { + delete[] temp[iInst]; + } + delete[] temp; + + /*--- Loop through variables to precondition ---*/ + for (iVar = 0; iVar < nVar; iVar++) { + + /*--- Get current source terms (not yet preconditioned) and zero source array to prepare preconditioning ---*/ + for (iInst = 0; iInst < nInstHB; iInst++) { + Source_old[iInst] = solver_container[ZONE_0][iInst][iMGlevel][FLOW_SOL]->GetNodes()->GetHarmonicBalance_Source(iPoint, iVar); + Source[iInst] = 0; + } + + /*--- Step through columns ---*/ + for (iInst = 0; iInst < nInstHB; iInst++) { + for (jInst = 0; jInst < nInstHB; jInst++) { + Source[iInst] += P[iInst][jInst]*Source_old[jInst]; + } + + /*--- Store updated source terms for current node ---*/ + if (!adjoint) { + solver_container[ZONE_0][iInst][iMGlevel][FLOW_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source[iInst]); + } + else { + solver_container[ZONE_0][iInst][iMGlevel][ADJFLOW_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source[iInst]); + } + } + + } + } + } + + /*--- Deallocate dynamic memory ---*/ + for (iInst = 0; iInst < nInstHB; iInst++){ + delete [] P[iInst]; + delete [] Pinv[iInst]; + } + delete [] P; + delete [] Pinv; + delete [] Source; + delete [] Source_old; + +} - unsigned short i, j, k, iVar, iInst, jInst, iMGlevel; - unsigned short nVar = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetnVar(); - unsigned long iPoint; - bool adjoint = (config_container[ZONE_0]->GetContinuous_Adjoint()); - - /*--- Retrieve values from the config file ---*/ - su2double *Source = new su2double[nInstHB]; - su2double *Source_old = new su2double[nInstHB]; - su2double Delta; - - su2double **Pinv = new su2double*[nInstHB]; - su2double **P = new su2double*[nInstHB]; - for (iInst = 0; iInst < nInstHB; iInst++) { - Pinv[iInst] = new su2double[nInstHB]; - P[iInst] = new su2double[nInstHB]; - } - - /*--- Loop over all grid levels ---*/ - for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++) { - - /*--- Loop over each node in the volume mesh ---*/ - for (iPoint = 0; iPoint < geometry_container[ZONE_0][INST_0][iMGlevel]->GetnPoint(); iPoint++) { - - /*--- Get time step for current node ---*/ - Delta = solver_container[ZONE_0][INST_0][iMGlevel][FLOW_SOL]->GetNodes()->GetDelta_Time(iPoint); - - /*--- Setup stabilization matrix for this node ---*/ - for (iInst = 0; iInst < nInstHB; iInst++) { - for (jInst = 0; jInst < nInstHB; jInst++) { - if (jInst == iInst ) { - Pinv[iInst][jInst] = 1.0 + Delta*D[iInst][jInst]; - } - else { - Pinv[iInst][jInst] = Delta*D[iInst][jInst]; - } - } - } - - /*--- Invert stabilization matrix Pinv with Gauss elimination---*/ - - /*-- A temporary matrix to hold the inverse, dynamically allocated ---*/ - su2double **temp = new su2double*[nInstHB]; - for (i = 0; i < nInstHB; i++) { - temp[i] = new su2double[2 * nInstHB]; - } - - /*--- Copy the desired matrix into the temporary matrix ---*/ - for (i = 0; i < nInstHB; i++) { +void CHBDriver::ComputeHB_Operator() { + + const complex J(0.0,1.0); + unsigned short i, j, k, iInst; + + su2double *Omega_HB = new su2double[nInstHB]; + complex **E = new complex*[nInstHB]; + complex **Einv = new complex*[nInstHB]; + complex **DD = new complex*[nInstHB]; + for (iInst = 0; iInst < nInstHB; iInst++) { + E[iInst] = new complex[nInstHB]; + Einv[iInst] = new complex[nInstHB]; + DD[iInst] = new complex[nInstHB]; + } + + /*--- Get simualation period from config file ---*/ + su2double Period = config_container[ZONE_0]->GetHarmonicBalance_Period(); + + /*--- Non-dimensionalize the input period, if necessary. */ + Period /= config_container[ZONE_0]->GetTime_Ref(); + + /*--- Build the array containing the selected frequencies to solve ---*/ + for (iInst = 0; iInst < nInstHB; iInst++) { + Omega_HB[iInst] = config_container[ZONE_0]->GetOmega_HB()[iInst]; + Omega_HB[iInst] /= config_container[ZONE_0]->GetOmega_Ref(); //TODO: check + } + + /*--- Build the diagonal matrix of the frequencies DD ---*/ + for (i = 0; i < nInstHB; i++) { + for (k = 0; k < nInstHB; k++) { + if (k == i ) { + DD[i][k] = J*Omega_HB[k]; + } + } + } + + + /*--- Build the harmonic balance inverse matrix ---*/ + for (i = 0; i < nInstHB; i++) { + for (k = 0; k < nInstHB; k++) { + Einv[i][k] = complex(cos(Omega_HB[k]*(i*Period/nInstHB))) + J*complex(sin(Omega_HB[k]*(i*Period/nInstHB))); + } + } + + /*--- Invert inverse harmonic balance Einv with Gauss elimination ---*/ + + /*-- A temporary matrix to hold the inverse, dynamically allocated ---*/ + complex **temp = new complex*[nInstHB]; + for (i = 0; i < nInstHB; i++) { + temp[i] = new complex[2 * nInstHB]; + } + + /*--- Copy the desired matrix into the temporary matrix ---*/ + for (i = 0; i < nInstHB; i++) { for (j = 0; j < nInstHB; j++) { - temp[i][j] = Pinv[i][j]; - temp[i][nInstHB + j] = 0; + temp[i][j] = Einv[i][j]; + temp[i][nInstHB + j] = 0; } temp[i][nInstHB + i] = 1; - } - - su2double max_val; - unsigned short max_idx; - - /*--- Pivot each column such that the largest number possible divides the other rows ---*/ - for (k = 0; k < nInstHB - 1; k++) { + } + + su2double max_val; + unsigned short max_idx; + + /*--- Pivot each column such that the largest number possible divides the other rows ---*/ + for (k = 0; k < nInstHB - 1; k++) { max_idx = k; max_val = abs(temp[k][k]); /*--- Find the largest value (pivot) in the column ---*/ for (j = k; j < nInstHB; j++) { - if (abs(temp[j][k]) > max_val) { - max_idx = j; - max_val = abs(temp[j][k]); - } + if (abs(temp[j][k]) > max_val) { + max_idx = j; + max_val = abs(temp[j][k]); + } } - /*--- Move the row with the highest value up ---*/ for (j = 0; j < (nInstHB * 2); j++) { - su2double d = temp[k][j]; - temp[k][j] = temp[max_idx][j]; - temp[max_idx][j] = d; + complex d = temp[k][j]; + temp[k][j] = temp[max_idx][j]; + temp[max_idx][j] = d; } /*--- Subtract the moved row from all other rows ---*/ for (i = k + 1; i < nInstHB; i++) { - su2double c = temp[i][k] / temp[k][k]; - for (j = 0; j < (nInstHB * 2); j++) { - temp[i][j] = temp[i][j] - temp[k][j] * c; - } - } - } - - /*--- Back-substitution ---*/ - for (k = nInstHB - 1; k > 0; k--) { - if (temp[k][k] != su2double(0.0)) { - for (int i = k - 1; i > -1; i--) { - su2double c = temp[i][k] / temp[k][k]; + complex c = temp[i][k] / temp[k][k]; for (j = 0; j < (nInstHB * 2); j++) { - temp[i][j] = temp[i][j] - temp[k][j] * c; + temp[i][j] = temp[i][j] - temp[k][j] * c; } - } } - } - - /*--- Normalize the inverse ---*/ - for (i = 0; i < nInstHB; i++) { - su2double c = temp[i][i]; + } + /*--- Back-substitution ---*/ + for (k = nInstHB - 1; k > 0; k--) { + if (temp[k][k] != complex(0.0)) { + for (int i = k - 1; i > -1; i--) { + complex c = temp[i][k] / temp[k][k]; + for (j = 0; j < (nInstHB * 2); j++) { + temp[i][j] = temp[i][j] - temp[k][j] * c; + } + } + } + } + /*--- Normalize the inverse ---*/ + for (i = 0; i < nInstHB; i++) { + complex c = temp[i][i]; for (j = 0; j < nInstHB; j++) { - temp[i][j + nInstHB] = temp[i][j + nInstHB] / c; + temp[i][j + nInstHB] = temp[i][j + nInstHB] / c; } - } - - /*--- Copy the inverse back to the main program flow ---*/ - for (i = 0; i < nInstHB; i++) { + } + /*--- Copy the inverse back to the main program flow ---*/ + for (i = 0; i < nInstHB; i++) { for (j = 0; j < nInstHB; j++) { - P[i][j] = temp[i][j + nInstHB]; + E[i][j] = temp[i][j + nInstHB]; } - } - - /*--- Delete dynamic template ---*/ - for (iInst = 0; iInst < nInstHB; iInst++) { - delete[] temp[iInst]; - } - delete[] temp; - - /*--- Loop through variables to precondition ---*/ - for (iVar = 0; iVar < nVar; iVar++) { - - /*--- Get current source terms (not yet preconditioned) and zero source array to prepare preconditioning ---*/ - for (iInst = 0; iInst < nInstHB; iInst++) { - Source_old[iInst] = solver_container[ZONE_0][iInst][iMGlevel][FLOW_SOL]->GetNodes()->GetHarmonicBalance_Source(iPoint, iVar); - Source[iInst] = 0; + } + /*--- Delete dynamic template ---*/ + for (i = 0; i < nInstHB; i++) { + delete[] temp[i]; + } + delete[] temp; + + + /*--- Temporary matrix for performing product ---*/ + complex **Temp = new complex*[nInstHB]; + + /*--- Temporary complex HB operator ---*/ + complex **Dcpx = new complex*[nInstHB]; + + for (iInst = 0; iInst < nInstHB; iInst++){ + Temp[iInst] = new complex[nInstHB]; + Dcpx[iInst] = new complex[nInstHB]; + } + + + /*--- Calculation of the HB operator matrix ---*/ + for (int row = 0; row < nInstHB; row++) { + for (int col = 0; col < nInstHB; col++) { + for (int inner = 0; inner < nInstHB; inner++) { + Temp[row][col] += Einv[row][inner] * DD[inner][col]; + } } - - /*--- Step through columns ---*/ - for (iInst = 0; iInst < nInstHB; iInst++) { - for (jInst = 0; jInst < nInstHB; jInst++) { - Source[iInst] += P[iInst][jInst]*Source_old[jInst]; - } - - /*--- Store updated source terms for current node ---*/ - if (!adjoint) { - solver_container[ZONE_0][iInst][iMGlevel][FLOW_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source[iInst]); - } - else { - solver_container[ZONE_0][iInst][iMGlevel][ADJFLOW_SOL]->GetNodes()->SetHarmonicBalance_Source(iPoint, iVar, Source[iInst]); - } + } + + unsigned short row, col, inner; + + for (row = 0; row < nInstHB; row++) { + for (col = 0; col < nInstHB; col++) { + for (inner = 0; inner < nInstHB; inner++) { + Dcpx[row][col] += Temp[row][inner] * E[inner][col]; + } } - - } } - } - - /*--- Deallocate dynamic memory ---*/ - for (iInst = 0; iInst < nInstHB; iInst++){ - delete [] P[iInst]; - delete [] Pinv[iInst]; - } - delete [] P; - delete [] Pinv; - delete [] Source; - delete [] Source_old; - -} - -void CHBDriver::ComputeHB_Operator() { - - const complex J(0.0,1.0); - unsigned short i, j, k, iInst; - - su2double *Omega_HB = new su2double[nInstHB]; - complex **E = new complex*[nInstHB]; - complex **Einv = new complex*[nInstHB]; - complex **DD = new complex*[nInstHB]; - for (iInst = 0; iInst < nInstHB; iInst++) { - E[iInst] = new complex[nInstHB]; - Einv[iInst] = new complex[nInstHB]; - DD[iInst] = new complex[nInstHB]; - } - - /*--- Get simualation period from config file ---*/ - su2double Period = config_container[ZONE_0]->GetHarmonicBalance_Period(); - - /*--- Non-dimensionalize the input period, if necessary. */ - Period /= config_container[ZONE_0]->GetTime_Ref(); - - /*--- Build the array containing the selected frequencies to solve ---*/ - for (iInst = 0; iInst < nInstHB; iInst++) { - Omega_HB[iInst] = config_container[ZONE_0]->GetOmega_HB()[iInst]; - Omega_HB[iInst] /= config_container[ZONE_0]->GetOmega_Ref(); //TODO: check - } - - /*--- Build the diagonal matrix of the frequencies DD ---*/ - for (i = 0; i < nInstHB; i++) { - for (k = 0; k < nInstHB; k++) { - if (k == i ) { - DD[i][k] = J*Omega_HB[k]; - } - } - } - - - /*--- Build the harmonic balance inverse matrix ---*/ - for (i = 0; i < nInstHB; i++) { - for (k = 0; k < nInstHB; k++) { - Einv[i][k] = complex(cos(Omega_HB[k]*(i*Period/nInstHB))) + J*complex(sin(Omega_HB[k]*(i*Period/nInstHB))); - } - } - - /*--- Invert inverse harmonic balance Einv with Gauss elimination ---*/ - - /*-- A temporary matrix to hold the inverse, dynamically allocated ---*/ - complex **temp = new complex*[nInstHB]; - for (i = 0; i < nInstHB; i++) { - temp[i] = new complex[2 * nInstHB]; - } - - /*--- Copy the desired matrix into the temporary matrix ---*/ - for (i = 0; i < nInstHB; i++) { - for (j = 0; j < nInstHB; j++) { - temp[i][j] = Einv[i][j]; - temp[i][nInstHB + j] = 0; - } - temp[i][nInstHB + i] = 1; - } - - su2double max_val; - unsigned short max_idx; - - /*--- Pivot each column such that the largest number possible divides the other rows ---*/ - for (k = 0; k < nInstHB - 1; k++) { - max_idx = k; - max_val = abs(temp[k][k]); - /*--- Find the largest value (pivot) in the column ---*/ - for (j = k; j < nInstHB; j++) { - if (abs(temp[j][k]) > max_val) { - max_idx = j; - max_val = abs(temp[j][k]); - } - } - /*--- Move the row with the highest value up ---*/ - for (j = 0; j < (nInstHB * 2); j++) { - complex d = temp[k][j]; - temp[k][j] = temp[max_idx][j]; - temp[max_idx][j] = d; - } - /*--- Subtract the moved row from all other rows ---*/ - for (i = k + 1; i < nInstHB; i++) { - complex c = temp[i][k] / temp[k][k]; - for (j = 0; j < (nInstHB * 2); j++) { - temp[i][j] = temp[i][j] - temp[k][j] * c; - } - } - } - /*--- Back-substitution ---*/ - for (k = nInstHB - 1; k > 0; k--) { - if (temp[k][k] != complex(0.0)) { - for (int i = k - 1; i > -1; i--) { - complex c = temp[i][k] / temp[k][k]; - for (j = 0; j < (nInstHB * 2); j++) { - temp[i][j] = temp[i][j] - temp[k][j] * c; - } - } - } - } - /*--- Normalize the inverse ---*/ - for (i = 0; i < nInstHB; i++) { - complex c = temp[i][i]; - for (j = 0; j < nInstHB; j++) { - temp[i][j + nInstHB] = temp[i][j + nInstHB] / c; - } - } - /*--- Copy the inverse back to the main program flow ---*/ - for (i = 0; i < nInstHB; i++) { - for (j = 0; j < nInstHB; j++) { - E[i][j] = temp[i][j + nInstHB]; - } - } - /*--- Delete dynamic template ---*/ - for (i = 0; i < nInstHB; i++) { - delete[] temp[i]; - } - delete[] temp; - - - /*--- Temporary matrix for performing product ---*/ - complex **Temp = new complex*[nInstHB]; - - /*--- Temporary complex HB operator ---*/ - complex **Dcpx = new complex*[nInstHB]; - - for (iInst = 0; iInst < nInstHB; iInst++){ - Temp[iInst] = new complex[nInstHB]; - Dcpx[iInst] = new complex[nInstHB]; - } - - - /*--- Calculation of the HB operator matrix ---*/ - for (int row = 0; row < nInstHB; row++) { - for (int col = 0; col < nInstHB; col++) { - for (int inner = 0; inner < nInstHB; inner++) { - Temp[row][col] += Einv[row][inner] * DD[inner][col]; - } - } - } - - unsigned short row, col, inner; - - for (row = 0; row < nInstHB; row++) { - for (col = 0; col < nInstHB; col++) { - for (inner = 0; inner < nInstHB; inner++) { - Dcpx[row][col] += Temp[row][inner] * E[inner][col]; - } - } - } - - /*--- Take just the real part of the HB operator matrix ---*/ - for (i = 0; i < nInstHB; i++) { - for (k = 0; k < nInstHB; k++) { - D[i][k] = real(Dcpx[i][k]); - } - } - - /*--- Deallocate dynamic memory ---*/ - for (iInst = 0; iInst < nInstHB; iInst++){ - delete [] E[iInst]; - delete [] Einv[iInst]; - delete [] DD[iInst]; - delete [] Temp[iInst]; - delete [] Dcpx[iInst]; - } - delete [] E; - delete [] Einv; - delete [] DD; - delete [] Temp; - delete [] Dcpx; - delete [] Omega_HB; - + + /*--- Take just the real part of the HB operator matrix ---*/ + for (i = 0; i < nInstHB; i++) { + for (k = 0; k < nInstHB; k++) { + D[i][k] = real(Dcpx[i][k]); + } + } + + /*--- Deallocate dynamic memory ---*/ + for (iInst = 0; iInst < nInstHB; iInst++){ + delete [] E[iInst]; + delete [] Einv[iInst]; + delete [] DD[iInst]; + delete [] Temp[iInst]; + delete [] Dcpx[iInst]; + } + delete [] E; + delete [] Einv; + delete [] DD; + delete [] Temp; + delete [] Dcpx; + delete [] Omega_HB; + } diff --git a/SU2_CFD/src/python_wrapper_structure.cpp b/SU2_CFD/src/python_wrapper_structure.cpp index 2f85546f4d3..ba6a563c5b0 100644 --- a/SU2_CFD/src/python_wrapper_structure.cpp +++ b/SU2_CFD/src/python_wrapper_structure.cpp @@ -31,32 +31,32 @@ #include "../../Common/include/toolboxes/geometry_toolbox.hpp" void CDriver::PythonInterface_Preprocessing(CConfig **config, CGeometry ****geometry, CSolver *****solver){ - - int rank = MASTER_NODE; - SU2_MPI::Comm_rank(SU2_MPI::GetComm(), &rank); - - /* --- Initialize boundary conditions customization, this is achieve through the Python wrapper --- */ - for(iZone=0; iZone < nZone; iZone++){ - - if (config[iZone]->GetnMarker_PyCustom() > 0){ - - if (rank == MASTER_NODE) cout << endl << "----------------- Python Interface Preprocessing ( Zone "<< iZone <<" ) -----------------" << endl; - - if (rank == MASTER_NODE) cout << "Setting customized boundary conditions for zone " << iZone << endl; - for (iMesh = 0; iMesh <= config[iZone]->GetnMGLevels(); iMesh++) { - geometry[iZone][INST_0][iMesh]->SetCustomBoundary(config[iZone]); - } - geometry[iZone][INST_0][MESH_0]->UpdateCustomBoundaryConditions(geometry[iZone][INST_0], config[iZone]); - - if ((config[iZone]->GetKind_Solver() == MAIN_SOLVER::EULER) || - (config[iZone]->GetKind_Solver() == MAIN_SOLVER::NAVIER_STOKES) || - (config[iZone]->GetKind_Solver() == MAIN_SOLVER::RANS)) { - - solver[iZone][INST_0][MESH_0][FLOW_SOL]->UpdateCustomBoundaryConditions(geometry[iZone][INST_0], config[iZone]); - } + + int rank = MASTER_NODE; + SU2_MPI::Comm_rank(SU2_MPI::GetComm(), &rank); + + /* --- Initialize boundary conditions customization, this is achieve through the Python wrapper --- */ + for(iZone=0; iZone < nZone; iZone++){ + + if (config[iZone]->GetnMarker_PyCustom() > 0){ + + if (rank == MASTER_NODE) cout << endl << "----------------- Python Interface Preprocessing ( Zone "<< iZone <<" ) -----------------" << endl; + + if (rank == MASTER_NODE) cout << "Setting customized boundary conditions for zone " << iZone << endl; + for (iMesh = 0; iMesh <= config[iZone]->GetnMGLevels(); iMesh++) { + geometry[iZone][INST_0][iMesh]->SetCustomBoundary(config[iZone]); + } + geometry[iZone][INST_0][MESH_0]->UpdateCustomBoundaryConditions(geometry[iZone][INST_0], config[iZone]); + + if ((config[iZone]->GetKind_Solver() == MAIN_SOLVER::EULER) || + (config[iZone]->GetKind_Solver() == MAIN_SOLVER::NAVIER_STOKES) || + (config[iZone]->GetKind_Solver() == MAIN_SOLVER::RANS)) { + + solver[iZone][INST_0][MESH_0][FLOW_SOL]->UpdateCustomBoundaryConditions(geometry[iZone][INST_0], config[iZone]); + } + } } - } - + } ///////////////////////////////////////////////////////////////////////////// @@ -64,106 +64,106 @@ void CDriver::PythonInterface_Preprocessing(CConfig **config, CGeometry ****geom ///////////////////////////////////////////////////////////////////////////// passivedouble CDriver::Get_Drag() const { - - unsigned short val_iZone = ZONE_0; - unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); - su2double CDrag, factor, val_Drag; - - /*--- Calculate drag force based on drag coefficient ---*/ - factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); - CDrag = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CD(); - - val_Drag = CDrag*factor; - - return SU2_TYPE::GetValue(val_Drag); + + unsigned short val_iZone = ZONE_0; + unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); + su2double CDrag, factor, val_Drag; + + /*--- Calculate drag force based on drag coefficient ---*/ + factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); + CDrag = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CD(); + + val_Drag = CDrag*factor; + + return SU2_TYPE::GetValue(val_Drag); } passivedouble CDriver::Get_Lift() const { - - unsigned short val_iZone = ZONE_0; - unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); - su2double CLift, factor, val_Lift; - - /*--- Calculate drag force based on drag coefficient ---*/ - factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); - CLift = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CL(); - - val_Lift = CLift*factor; - - return SU2_TYPE::GetValue(val_Lift); + + unsigned short val_iZone = ZONE_0; + unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); + su2double CLift, factor, val_Lift; + + /*--- Calculate drag force based on drag coefficient ---*/ + factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); + CLift = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CL(); + + val_Lift = CLift*factor; + + return SU2_TYPE::GetValue(val_Lift); } passivedouble CDriver::Get_Mx() const { - - unsigned short val_iZone = ZONE_0; - unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); - su2double CMx, RefLengthCoeff, factor, val_Mx; - - RefLengthCoeff = config_container[val_iZone]->GetRefLength(); - - /*--- Calculate moment around x-axis based on coefficients ---*/ - factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); - CMx = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CMx(); - - val_Mx = CMx*factor*RefLengthCoeff; - - return SU2_TYPE::GetValue(val_Mx); + + unsigned short val_iZone = ZONE_0; + unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); + su2double CMx, RefLengthCoeff, factor, val_Mx; + + RefLengthCoeff = config_container[val_iZone]->GetRefLength(); + + /*--- Calculate moment around x-axis based on coefficients ---*/ + factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); + CMx = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CMx(); + + val_Mx = CMx*factor*RefLengthCoeff; + + return SU2_TYPE::GetValue(val_Mx); } passivedouble CDriver::Get_My() const { - - unsigned short val_iZone = ZONE_0; - unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); - su2double CMy, RefLengthCoeff, factor, val_My; - - RefLengthCoeff = config_container[val_iZone]->GetRefLength(); - - /*--- Calculate moment around x-axis based on coefficients ---*/ - factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); - CMy = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CMy(); - - val_My = CMy*factor*RefLengthCoeff; - - return SU2_TYPE::GetValue(val_My); + + unsigned short val_iZone = ZONE_0; + unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); + su2double CMy, RefLengthCoeff, factor, val_My; + + RefLengthCoeff = config_container[val_iZone]->GetRefLength(); + + /*--- Calculate moment around x-axis based on coefficients ---*/ + factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); + CMy = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CMy(); + + val_My = CMy*factor*RefLengthCoeff; + + return SU2_TYPE::GetValue(val_My); } passivedouble CDriver::Get_Mz() const { - - unsigned short val_iZone = ZONE_0; - unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); - su2double CMz, RefLengthCoeff, factor, val_Mz; - - RefLengthCoeff = config_container[val_iZone]->GetRefLength(); - - /*--- Calculate moment around z-axis based on coefficients ---*/ - factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); - CMz = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CMz(); - - val_Mz = CMz*factor*RefLengthCoeff; - - return SU2_TYPE::GetValue(val_Mz); + + unsigned short val_iZone = ZONE_0; + unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); + su2double CMz, RefLengthCoeff, factor, val_Mz; + + RefLengthCoeff = config_container[val_iZone]->GetRefLength(); + + /*--- Calculate moment around z-axis based on coefficients ---*/ + factor = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetAeroCoeffsReferenceForce(); + CMz = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CMz(); + + val_Mz = CMz*factor*RefLengthCoeff; + + return SU2_TYPE::GetValue(val_Mz); } passivedouble CDriver::Get_DragCoeff() const { - - unsigned short val_iZone = ZONE_0; - unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); - su2double CDrag; - - CDrag = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CD(); - - return SU2_TYPE::GetValue(CDrag); + + unsigned short val_iZone = ZONE_0; + unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); + su2double CDrag; + + CDrag = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CD(); + + return SU2_TYPE::GetValue(CDrag); } passivedouble CDriver::Get_LiftCoeff() const { - - unsigned short val_iZone = ZONE_0; - unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); - su2double CLift; - - CLift = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CL(); - - return SU2_TYPE::GetValue(CLift); + + unsigned short val_iZone = ZONE_0; + unsigned short FinestMesh = config_container[val_iZone]->GetFinestMesh(); + su2double CLift; + + CLift = solver_container[val_iZone][INST_0][FinestMesh][FLOW_SOL]->GetTotal_CL(); + + return SU2_TYPE::GetValue(CLift); } ////////////////////////////////////////////////////////////////////////////////// @@ -171,23 +171,23 @@ passivedouble CDriver::Get_LiftCoeff() const { ////////////////////////////////////////////////////////////////////////////////// unsigned long CDriver::GetnTimeIter() const { - - return config_container[ZONE_0]->GetnTime_Iter(); + + return config_container[ZONE_0]->GetnTime_Iter(); } unsigned long CDriver::GetTime_Iter() const{ - - return TimeIter; + + return TimeIter; } passivedouble CDriver::GetUnsteady_TimeStep() const { - - return SU2_TYPE::GetValue(config_container[ZONE_0]->GetTime_Step()); + + return SU2_TYPE::GetValue(config_container[ZONE_0]->GetTime_Step()); } string CDriver::GetSurfaceFileName() const { - - return config_container[ZONE_0]->GetSurfCoeff_FileName(); + + return config_container[ZONE_0]->GetSurfCoeff_FileName(); } /////////////////////////////////////////////////////////////////////////////// @@ -195,125 +195,125 @@ string CDriver::GetSurfaceFileName() const { /////////////////////////////////////////////////////////////////////////////// passivedouble CDriver::GetVertexTemperature(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - su2double vertexWallTemp(0.0); - - bool compressible = (config_container[ZONE_0]->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE); - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - - if(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint) && compressible){ - vertexWallTemp = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetTemperature(iPoint); - } - - return SU2_TYPE::GetValue(vertexWallTemp); - + + unsigned long iPoint; + su2double vertexWallTemp(0.0); + + bool compressible = (config_container[ZONE_0]->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE); + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + + if(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint) && compressible){ + vertexWallTemp = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetTemperature(iPoint); + } + + return SU2_TYPE::GetValue(vertexWallTemp); + } void CDriver::SetVertexTemperature(unsigned short iMarker, unsigned long iVertex, passivedouble val_WallTemp){ - - geometry_container[ZONE_0][INST_0][MESH_0]->SetCustomBoundaryTemperature(iMarker, iVertex, val_WallTemp); + + geometry_container[ZONE_0][INST_0][MESH_0]->SetCustomBoundaryTemperature(iMarker, iVertex, val_WallTemp); } vector CDriver::GetVertexHeatFluxes(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - unsigned short iDim; - su2double Prandtl_Lam = config_container[ZONE_0]->GetPrandtl_Lam(); - su2double Gas_Constant = config_container[ZONE_0]->GetGas_ConstantND(); - su2double Gamma = config_container[ZONE_0]->GetGamma(); - su2double Gamma_Minus_One = Gamma - 1.0; - su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - su2double laminar_viscosity, thermal_conductivity; - vector GradT (3,0.0); - vector HeatFlux (3,0.0); - vector HeatFluxPassive (3,0.0); - - bool compressible = (config_container[ZONE_0]->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE); - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - - if(compressible){ - laminar_viscosity = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetLaminarViscosity(iPoint); - thermal_conductivity = Cp * (laminar_viscosity/Prandtl_Lam); - for(iDim=0; iDim < nDim; iDim++){ - GradT[iDim] = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetGradient_Primitive(iPoint, 0, iDim); - HeatFlux[iDim] = -thermal_conductivity*GradT[iDim]; + + unsigned long iPoint; + unsigned short iDim; + su2double Prandtl_Lam = config_container[ZONE_0]->GetPrandtl_Lam(); + su2double Gas_Constant = config_container[ZONE_0]->GetGas_ConstantND(); + su2double Gamma = config_container[ZONE_0]->GetGamma(); + su2double Gamma_Minus_One = Gamma - 1.0; + su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + su2double laminar_viscosity, thermal_conductivity; + vector GradT (3,0.0); + vector HeatFlux (3,0.0); + vector HeatFluxPassive (3,0.0); + + bool compressible = (config_container[ZONE_0]->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE); + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + + if(compressible){ + laminar_viscosity = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetLaminarViscosity(iPoint); + thermal_conductivity = Cp * (laminar_viscosity/Prandtl_Lam); + for(iDim=0; iDim < nDim; iDim++){ + GradT[iDim] = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetGradient_Primitive(iPoint, 0, iDim); + HeatFlux[iDim] = -thermal_conductivity*GradT[iDim]; + } } - } - - HeatFluxPassive[0] = SU2_TYPE::GetValue(HeatFlux[0]); - HeatFluxPassive[1] = SU2_TYPE::GetValue(HeatFlux[1]); - HeatFluxPassive[2] = SU2_TYPE::GetValue(HeatFlux[2]); - - return HeatFluxPassive; + + HeatFluxPassive[0] = SU2_TYPE::GetValue(HeatFlux[0]); + HeatFluxPassive[1] = SU2_TYPE::GetValue(HeatFlux[1]); + HeatFluxPassive[2] = SU2_TYPE::GetValue(HeatFlux[2]); + + return HeatFluxPassive; } passivedouble CDriver::GetVertexNormalHeatFlux(unsigned short iMarker, unsigned long iVertex) const{ - - unsigned long iPoint; - unsigned short iDim; - su2double vertexWallHeatFlux; - su2double Prandtl_Lam = config_container[ZONE_0]->GetPrandtl_Lam(); - su2double Gas_Constant = config_container[ZONE_0]->GetGas_ConstantND(); - su2double Gamma = config_container[ZONE_0]->GetGamma(); - su2double Gamma_Minus_One = Gamma - 1.0; - su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - su2double Area; - su2double laminar_viscosity, thermal_conductivity, dTdn; - su2double *Normal, GradT[3] = {0.0,0.0,0.0}, UnitNormal[3] = {0.0,0.0,0.0}; - - bool compressible = (config_container[ZONE_0]->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE); - - vertexWallHeatFlux = 0.0; - dTdn = 0.0; - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - - if(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint) && compressible){ - Normal = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNormal(); - - Area = GeometryToolbox::Norm(nDim, Normal); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = Normal[iDim]/Area; - - laminar_viscosity = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetLaminarViscosity(iPoint); - thermal_conductivity = Cp * (laminar_viscosity/Prandtl_Lam); - /*Compute wall heat flux (normal to the wall) based on computed temperature gradient*/ - for(iDim=0; iDim < nDim; iDim++){ - GradT[iDim] = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetGradient_Primitive(iPoint, 0, iDim); - dTdn += GradT[iDim]*UnitNormal[iDim]; + + unsigned long iPoint; + unsigned short iDim; + su2double vertexWallHeatFlux; + su2double Prandtl_Lam = config_container[ZONE_0]->GetPrandtl_Lam(); + su2double Gas_Constant = config_container[ZONE_0]->GetGas_ConstantND(); + su2double Gamma = config_container[ZONE_0]->GetGamma(); + su2double Gamma_Minus_One = Gamma - 1.0; + su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + su2double Area; + su2double laminar_viscosity, thermal_conductivity, dTdn; + su2double *Normal, GradT[3] = {0.0,0.0,0.0}, UnitNormal[3] = {0.0,0.0,0.0}; + + bool compressible = (config_container[ZONE_0]->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE); + + vertexWallHeatFlux = 0.0; + dTdn = 0.0; + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + + if(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint) && compressible){ + Normal = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNormal(); + + Area = GeometryToolbox::Norm(nDim, Normal); + + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] = Normal[iDim]/Area; + + laminar_viscosity = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetLaminarViscosity(iPoint); + thermal_conductivity = Cp * (laminar_viscosity/Prandtl_Lam); + /*Compute wall heat flux (normal to the wall) based on computed temperature gradient*/ + for(iDim=0; iDim < nDim; iDim++){ + GradT[iDim] = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetGradient_Primitive(iPoint, 0, iDim); + dTdn += GradT[iDim]*UnitNormal[iDim]; + } + + vertexWallHeatFlux = -thermal_conductivity*dTdn; } - - vertexWallHeatFlux = -thermal_conductivity*dTdn; - } - - return SU2_TYPE::GetValue(vertexWallHeatFlux); + + return SU2_TYPE::GetValue(vertexWallHeatFlux); } void CDriver::SetVertexNormalHeatFlux(unsigned short iMarker, unsigned long iVertex, passivedouble val_WallHeatFlux){ - - geometry_container[ZONE_0][INST_0][MESH_0]->SetCustomBoundaryHeatFlux(iMarker, iVertex, val_WallHeatFlux); + + geometry_container[ZONE_0][INST_0][MESH_0]->SetCustomBoundaryHeatFlux(iMarker, iVertex, val_WallHeatFlux); } passivedouble CDriver::GetThermalConductivity(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - su2double Prandtl_Lam = config_container[ZONE_0]->GetPrandtl_Lam(); - su2double Gas_Constant = config_container[ZONE_0]->GetGas_ConstantND(); - su2double Gamma = config_container[ZONE_0]->GetGamma(); - su2double Gamma_Minus_One = Gamma - 1.0; - su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - su2double laminar_viscosity, thermal_conductivity; - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - laminar_viscosity = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetLaminarViscosity(iPoint); - thermal_conductivity = Cp * (laminar_viscosity/Prandtl_Lam); - - return SU2_TYPE::GetValue(thermal_conductivity); - + + unsigned long iPoint; + su2double Prandtl_Lam = config_container[ZONE_0]->GetPrandtl_Lam(); + su2double Gas_Constant = config_container[ZONE_0]->GetGas_ConstantND(); + su2double Gamma = config_container[ZONE_0]->GetGamma(); + su2double Gamma_Minus_One = Gamma - 1.0; + su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + su2double laminar_viscosity, thermal_conductivity; + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + laminar_viscosity = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->GetNodes()->GetLaminarViscosity(iPoint); + thermal_conductivity = Cp * (laminar_viscosity/Prandtl_Lam); + + return SU2_TYPE::GetValue(thermal_conductivity); + } //////////////////////////////////////////////////////////////////////////////// @@ -321,83 +321,83 @@ passivedouble CDriver::GetThermalConductivity(unsigned short iMarker, unsigned l //////////////////////////////////////////////////////////////////////////////// vector CDriver::GetAllBoundaryMarkersTag() const { - - vector boundariesTagList; - unsigned short iMarker,nBoundariesMarkers; - string Marker_Tag; - - nBoundariesMarkers = config_container[ZONE_0]->GetnMarker_All(); - boundariesTagList.resize(nBoundariesMarkers); - - for(iMarker=0; iMarker < nBoundariesMarkers; iMarker++){ - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - boundariesTagList[iMarker] = Marker_Tag; - } - - return boundariesTagList; + + vector boundariesTagList; + unsigned short iMarker,nBoundariesMarkers; + string Marker_Tag; + + nBoundariesMarkers = config_container[ZONE_0]->GetnMarker_All(); + boundariesTagList.resize(nBoundariesMarkers); + + for(iMarker=0; iMarker < nBoundariesMarkers; iMarker++){ + Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); + boundariesTagList[iMarker] = Marker_Tag; + } + + return boundariesTagList; } vector CDriver::GetAllCHTMarkersTag() const { - - vector CHTBoundariesTagList; - unsigned short iMarker, nBoundariesMarker; - string Marker_Tag; - - nBoundariesMarker = config_container[ZONE_0]->GetnMarker_All(); - - //The CHT markers can be identified as the markers that are customizable with a BC type HEAT_FLUX or ISOTHERMAL. - for(iMarker=0; iMarkerGetMarker_All_KindBC(iMarker) == HEAT_FLUX || config_container[ZONE_0]->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) && config_container[ZONE_0]->GetMarker_All_PyCustom(iMarker)){ - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - CHTBoundariesTagList.push_back(Marker_Tag); + + vector CHTBoundariesTagList; + unsigned short iMarker, nBoundariesMarker; + string Marker_Tag; + + nBoundariesMarker = config_container[ZONE_0]->GetnMarker_All(); + + //The CHT markers can be identified as the markers that are customizable with a BC type HEAT_FLUX or ISOTHERMAL. + for(iMarker=0; iMarkerGetMarker_All_KindBC(iMarker) == HEAT_FLUX || config_container[ZONE_0]->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) && config_container[ZONE_0]->GetMarker_All_PyCustom(iMarker)){ + Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); + CHTBoundariesTagList.push_back(Marker_Tag); + } } - } - - return CHTBoundariesTagList; + + return CHTBoundariesTagList; } vector CDriver::GetAllInletMarkersTag() const { - - vector BoundariesTagList; - unsigned short iMarker, nBoundariesMarker; - string Marker_Tag; - - nBoundariesMarker = config_container[ZONE_0]->GetnMarker_All(); - - for(iMarker=0; iMarkerGetMarker_All_PyCustom(iMarker); - bool isInlet = (config_container[ZONE_0]->GetMarker_All_KindBC(iMarker) == INLET_FLOW); - if(isCustomizable && isInlet) { - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - BoundariesTagList.push_back(Marker_Tag); + + vector BoundariesTagList; + unsigned short iMarker, nBoundariesMarker; + string Marker_Tag; + + nBoundariesMarker = config_container[ZONE_0]->GetnMarker_All(); + + for(iMarker=0; iMarkerGetMarker_All_PyCustom(iMarker); + bool isInlet = (config_container[ZONE_0]->GetMarker_All_KindBC(iMarker) == INLET_FLOW); + if(isCustomizable && isInlet) { + Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); + BoundariesTagList.push_back(Marker_Tag); + } } - } - - return BoundariesTagList; + + return BoundariesTagList; } void CDriver::SetHeatSource_Position(passivedouble alpha, passivedouble pos_x, passivedouble pos_y, passivedouble pos_z){ - - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][RAD_SOL]; - - config_container[ZONE_0]->SetHeatSource_Rot_Z(alpha); - config_container[ZONE_0]->SetHeatSource_Center(pos_x, pos_y, pos_z); - - solver->SetVolumetricHeatSource(geometry_container[ZONE_0][INST_0][MESH_0], config_container[ZONE_0]); - + + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][RAD_SOL]; + + config_container[ZONE_0]->SetHeatSource_Rot_Z(alpha); + config_container[ZONE_0]->SetHeatSource_Center(pos_x, pos_y, pos_z); + + solver->SetVolumetricHeatSource(geometry_container[ZONE_0][INST_0][MESH_0], config_container[ZONE_0]); + } void CDriver::SetInlet_Angle(unsigned short iMarker, passivedouble alpha){ - - su2double alpha_rad = alpha * PI_NUMBER/180.0; - - unsigned long iVertex; - - for (iVertex = 0; iVertex < geometry_container[ZONE_0][INST_0][MESH_0]->nVertex[iMarker]; iVertex++){ - solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->SetInlet_FlowDir(iMarker, iVertex, 0, cos(alpha_rad)); - solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->SetInlet_FlowDir(iMarker, iVertex, 1, sin(alpha_rad)); - } - + + su2double alpha_rad = alpha * PI_NUMBER/180.0; + + unsigned long iVertex; + + for (iVertex = 0; iVertex < geometry_container[ZONE_0][INST_0][MESH_0]->nVertex[iMarker]; iVertex++){ + solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->SetInlet_FlowDir(iMarker, iVertex, 0, cos(alpha_rad)); + solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]->SetInlet_FlowDir(iMarker, iVertex, 1, sin(alpha_rad)); + } + } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -405,74 +405,74 @@ void CDriver::SetInlet_Angle(unsigned short iMarker, passivedouble alpha){ ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// void CDriver::ResetConvergence() { - - for(iZone = 0; iZone < nZone; iZone++) { - switch (config_container[iZone]->GetKind_Solver()) { - - case MAIN_SOLVER::EULER: case MAIN_SOLVER::NAVIER_STOKES: case MAIN_SOLVER::RANS: - case MAIN_SOLVER::INC_EULER: case MAIN_SOLVER::INC_NAVIER_STOKES: case MAIN_SOLVER::INC_RANS: - integration_container[iZone][INST_0][FLOW_SOL]->SetConvergence(false); - if (config_container[iZone]->GetKind_Solver() == MAIN_SOLVER::RANS) integration_container[iZone][INST_0][TURB_SOL]->SetConvergence(false); - if(config_container[iZone]->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM) integration_container[iZone][INST_0][TRANS_SOL]->SetConvergence(false); - break; - - case MAIN_SOLVER::FEM_ELASTICITY: - integration_container[iZone][INST_0][FEA_SOL]->SetConvergence(false); - break; - - case MAIN_SOLVER::ADJ_EULER: case MAIN_SOLVER::ADJ_NAVIER_STOKES: case MAIN_SOLVER::ADJ_RANS: case MAIN_SOLVER::DISC_ADJ_EULER: case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_RANS: - case MAIN_SOLVER::DISC_ADJ_INC_EULER: case MAIN_SOLVER::DISC_ADJ_INC_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_INC_RANS: - integration_container[iZone][INST_0][ADJFLOW_SOL]->SetConvergence(false); - if( (config_container[iZone]->GetKind_Solver() == MAIN_SOLVER::ADJ_RANS) || (config_container[iZone]->GetKind_Solver() == MAIN_SOLVER::DISC_ADJ_RANS) ) - integration_container[iZone][INST_0][ADJTURB_SOL]->SetConvergence(false); - break; - - default: - break; + + for(iZone = 0; iZone < nZone; iZone++) { + switch (config_container[iZone]->GetKind_Solver()) { + + case MAIN_SOLVER::EULER: case MAIN_SOLVER::NAVIER_STOKES: case MAIN_SOLVER::RANS: + case MAIN_SOLVER::INC_EULER: case MAIN_SOLVER::INC_NAVIER_STOKES: case MAIN_SOLVER::INC_RANS: + integration_container[iZone][INST_0][FLOW_SOL]->SetConvergence(false); + if (config_container[iZone]->GetKind_Solver() == MAIN_SOLVER::RANS) integration_container[iZone][INST_0][TURB_SOL]->SetConvergence(false); + if(config_container[iZone]->GetKind_Trans_Model() == TURB_TRANS_MODEL::LM) integration_container[iZone][INST_0][TRANS_SOL]->SetConvergence(false); + break; + + case MAIN_SOLVER::FEM_ELASTICITY: + integration_container[iZone][INST_0][FEA_SOL]->SetConvergence(false); + break; + + case MAIN_SOLVER::ADJ_EULER: case MAIN_SOLVER::ADJ_NAVIER_STOKES: case MAIN_SOLVER::ADJ_RANS: case MAIN_SOLVER::DISC_ADJ_EULER: case MAIN_SOLVER::DISC_ADJ_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_RANS: + case MAIN_SOLVER::DISC_ADJ_INC_EULER: case MAIN_SOLVER::DISC_ADJ_INC_NAVIER_STOKES: case MAIN_SOLVER::DISC_ADJ_INC_RANS: + integration_container[iZone][INST_0][ADJFLOW_SOL]->SetConvergence(false); + if( (config_container[iZone]->GetKind_Solver() == MAIN_SOLVER::ADJ_RANS) || (config_container[iZone]->GetKind_Solver() == MAIN_SOLVER::DISC_ADJ_RANS) ) + integration_container[iZone][INST_0][ADJTURB_SOL]->SetConvergence(false); + break; + + default: + break; + } } - } - + } void CSinglezoneDriver::SetInitialMesh() { - - DynamicMeshUpdate(0); - - SU2_OMP_PARALLEL { - // Overwrite fictious velocities - for (iMesh = 0u; iMesh <= config_container[ZONE_0]->GetnMGLevels(); iMesh++) { - SU2_OMP_FOR_STAT(roundUpDiv(geometry_container[ZONE_0][INST_0][iMesh]->GetnPoint(),omp_get_max_threads())) - for (unsigned long iPoint = 0; iPoint < geometry_container[ZONE_0][INST_0][iMesh]->GetnPoint(); iPoint++) { - - /*--- Overwrite fictitious velocities ---*/ - su2double Grid_Vel[3] = {0.0, 0.0, 0.0}; - - /*--- Set the grid velocity for this coarse node. ---*/ - geometry_container[ZONE_0][INST_0][iMesh]->nodes->SetGridVel(iPoint, Grid_Vel); - } - END_SU2_OMP_FOR - /*--- Push back the volume. ---*/ - geometry_container[ZONE_0][INST_0][iMesh]->nodes->SetVolume_n(); - geometry_container[ZONE_0][INST_0][iMesh]->nodes->SetVolume_nM1(); + + DynamicMeshUpdate(0); + + SU2_OMP_PARALLEL { + // Overwrite fictious velocities + for (iMesh = 0u; iMesh <= config_container[ZONE_0]->GetnMGLevels(); iMesh++) { + SU2_OMP_FOR_STAT(roundUpDiv(geometry_container[ZONE_0][INST_0][iMesh]->GetnPoint(),omp_get_max_threads())) + for (unsigned long iPoint = 0; iPoint < geometry_container[ZONE_0][INST_0][iMesh]->GetnPoint(); iPoint++) { + + /*--- Overwrite fictitious velocities ---*/ + su2double Grid_Vel[3] = {0.0, 0.0, 0.0}; + + /*--- Set the grid velocity for this coarse node. ---*/ + geometry_container[ZONE_0][INST_0][iMesh]->nodes->SetGridVel(iPoint, Grid_Vel); + } + END_SU2_OMP_FOR + /*--- Push back the volume. ---*/ + geometry_container[ZONE_0][INST_0][iMesh]->nodes->SetVolume_n(); + geometry_container[ZONE_0][INST_0][iMesh]->nodes->SetVolume_nM1(); + } + /*--- Push back the solution so that there is no fictious velocity at the next step. ---*/ + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->Set_Solution_time_n(); + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->Set_Solution_time_n1(); } - /*--- Push back the solution so that there is no fictious velocity at the next step. ---*/ - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->Set_Solution_time_n(); - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->Set_Solution_time_n1(); - } - END_SU2_OMP_PARALLEL + END_SU2_OMP_PARALLEL } void CDriver::BoundaryConditionsUpdate(){ - - int rank = MASTER_NODE; - unsigned short iZone; - - SU2_MPI::Comm_rank(SU2_MPI::GetComm(), &rank); - - if(rank == MASTER_NODE) cout << "Updating boundary conditions." << endl; - for(iZone = 0; iZone < nZone; iZone++){ - geometry_container[iZone][INST_0][MESH_0]->UpdateCustomBoundaryConditions(geometry_container[iZone][INST_0], config_container[iZone]); - } + + int rank = MASTER_NODE; + unsigned short iZone; + + SU2_MPI::Comm_rank(SU2_MPI::GetComm(), &rank); + + if(rank == MASTER_NODE) cout << "Updating boundary conditions." << endl; + for(iZone = 0; iZone < nZone; iZone++){ + geometry_container[iZone][INST_0][MESH_0]->UpdateCustomBoundaryConditions(geometry_container[iZone][INST_0], config_container[iZone]); + } } //////////////////////////////////////////////////////////////////////////////// @@ -480,95 +480,95 @@ void CDriver::BoundaryConditionsUpdate(){ //////////////////////////////////////////////////////////////////////////////// void CDriver::SetFEA_Loads(unsigned short iMarker, unsigned long iVertex, passivedouble LoadX, - passivedouble LoadY, passivedouble LoadZ) { - - unsigned long iPoint; - su2double NodalForce[3] = {0.0,0.0,0.0}; - NodalForce[0] = LoadX; - NodalForce[1] = LoadY; - NodalForce[2] = LoadZ; - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - solver_container[ZONE_0][INST_0][MESH_0][FEA_SOL]->GetNodes()->Set_FlowTraction(iPoint,NodalForce); - + passivedouble LoadY, passivedouble LoadZ) { + + unsigned long iPoint; + su2double NodalForce[3] = {0.0,0.0,0.0}; + NodalForce[0] = LoadX; + NodalForce[1] = LoadY; + NodalForce[2] = LoadZ; + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + solver_container[ZONE_0][INST_0][MESH_0][FEA_SOL]->GetNodes()->Set_FlowTraction(iPoint,NodalForce); + } vector CDriver::GetFEA_Displacements(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - vector Displacements(3, 0.0); - vector Displacements_passive(3, 0.0); - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FEA_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - Displacements[0] = solver->GetNodes()->GetSolution(iPoint, 0); - Displacements[1] = solver->GetNodes()->GetSolution(iPoint, 1); - if (geometry->GetnDim() == 3) - Displacements[2] = solver->GetNodes()->GetSolution(iPoint, 2); - else - Displacements[2] = 0.0; - - Displacements_passive[0] = SU2_TYPE::GetValue(Displacements[0]); - Displacements_passive[1] = SU2_TYPE::GetValue(Displacements[1]); - Displacements_passive[2] = SU2_TYPE::GetValue(Displacements[2]); - - return Displacements_passive; -} - - -vector CDriver::GetFEA_Velocity(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - vector Velocity(3, 0.0); - vector Velocity_passive(3,0.0); - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FEA_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - if (config_container[ZONE_0]->GetDynamic_Analysis() == DYNAMIC){ - Velocity[0] = solver->GetNodes()->GetSolution_Vel(iPoint, 0); - Velocity[1] = solver->GetNodes()->GetSolution_Vel(iPoint, 1); + + unsigned long iPoint; + vector Displacements(3, 0.0); + vector Displacements_passive(3, 0.0); + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FEA_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + Displacements[0] = solver->GetNodes()->GetSolution(iPoint, 0); + Displacements[1] = solver->GetNodes()->GetSolution(iPoint, 1); if (geometry->GetnDim() == 3) - Velocity[2] = solver->GetNodes()->GetSolution_Vel(iPoint, 2); + Displacements[2] = solver->GetNodes()->GetSolution(iPoint, 2); else - Velocity[2] = 0.0; - } + Displacements[2] = 0.0; + + Displacements_passive[0] = SU2_TYPE::GetValue(Displacements[0]); + Displacements_passive[1] = SU2_TYPE::GetValue(Displacements[1]); + Displacements_passive[2] = SU2_TYPE::GetValue(Displacements[2]); + + return Displacements_passive; +} - Velocity_passive[0] = SU2_TYPE::GetValue(Velocity[0]); - Velocity_passive[1] = SU2_TYPE::GetValue(Velocity[1]); - Velocity_passive[2] = SU2_TYPE::GetValue(Velocity[2]); - return Velocity_passive; +vector CDriver::GetFEA_Velocity(unsigned short iMarker, unsigned long iVertex) const { + + unsigned long iPoint; + vector Velocity(3, 0.0); + vector Velocity_passive(3,0.0); + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FEA_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + if (config_container[ZONE_0]->GetDynamic_Analysis() == DYNAMIC){ + Velocity[0] = solver->GetNodes()->GetSolution_Vel(iPoint, 0); + Velocity[1] = solver->GetNodes()->GetSolution_Vel(iPoint, 1); + if (geometry->GetnDim() == 3) + Velocity[2] = solver->GetNodes()->GetSolution_Vel(iPoint, 2); + else + Velocity[2] = 0.0; + } + + Velocity_passive[0] = SU2_TYPE::GetValue(Velocity[0]); + Velocity_passive[1] = SU2_TYPE::GetValue(Velocity[1]); + Velocity_passive[2] = SU2_TYPE::GetValue(Velocity[2]); + + return Velocity_passive; } vector CDriver::GetFEA_Velocity_n(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - vector Velocity_n(3, 0.0); - vector Velocity_n_passive(3, 0.0); - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FEA_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - if (config_container[ZONE_0]->GetDynamic_Analysis() == DYNAMIC){ - Velocity_n[0] = solver->GetNodes()->GetSolution_Vel_time_n(iPoint, 0); - Velocity_n[1] = solver->GetNodes()->GetSolution_Vel_time_n(iPoint, 1); - if (geometry->GetnDim() == 3) - Velocity_n[2] = solver->GetNodes()->GetSolution_Vel_time_n(iPoint, 2); - else - Velocity_n[2] = 0.0; - } - - Velocity_n_passive[0] = SU2_TYPE::GetValue(Velocity_n[0]); - Velocity_n_passive[1] = SU2_TYPE::GetValue(Velocity_n[1]); - Velocity_n_passive[2] = SU2_TYPE::GetValue(Velocity_n[2]); - - return Velocity_n_passive; - + + unsigned long iPoint; + vector Velocity_n(3, 0.0); + vector Velocity_n_passive(3, 0.0); + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FEA_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + if (config_container[ZONE_0]->GetDynamic_Analysis() == DYNAMIC){ + Velocity_n[0] = solver->GetNodes()->GetSolution_Vel_time_n(iPoint, 0); + Velocity_n[1] = solver->GetNodes()->GetSolution_Vel_time_n(iPoint, 1); + if (geometry->GetnDim() == 3) + Velocity_n[2] = solver->GetNodes()->GetSolution_Vel_time_n(iPoint, 2); + else + Velocity_n[2] = 0.0; + } + + Velocity_n_passive[0] = SU2_TYPE::GetValue(Velocity_n[0]); + Velocity_n_passive[1] = SU2_TYPE::GetValue(Velocity_n[1]); + Velocity_n_passive[2] = SU2_TYPE::GetValue(Velocity_n[2]); + + return Velocity_n_passive; + } //////////////////////////////////////////////////////////////////////////////// @@ -576,96 +576,96 @@ vector CDriver::GetFEA_Velocity_n(unsigned short iMarker, unsigne //////////////////////////////////////////////////////////////////////////////// vector CDriver::GetMeshDisp_Sensitivity(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - vector Disp_Sens(3, 0.0); - vector Disp_Sens_passive(3, 0.0); - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJMESH_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - Disp_Sens[0] = solver->GetNodes()->GetBoundDisp_Sens(iPoint, 0); - Disp_Sens[1] = solver->GetNodes()->GetBoundDisp_Sens(iPoint, 1); - if (geometry->GetnDim() == 3) - Disp_Sens[2] = solver->GetNodes()->GetBoundDisp_Sens(iPoint, 2); - else - Disp_Sens[2] = 0.0; - - Disp_Sens_passive[0] = SU2_TYPE::GetValue(Disp_Sens[0]); - Disp_Sens_passive[1] = SU2_TYPE::GetValue(Disp_Sens[1]); - Disp_Sens_passive[2] = SU2_TYPE::GetValue(Disp_Sens[2]); - - return Disp_Sens_passive; - + + unsigned long iPoint; + vector Disp_Sens(3, 0.0); + vector Disp_Sens_passive(3, 0.0); + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJMESH_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + Disp_Sens[0] = solver->GetNodes()->GetBoundDisp_Sens(iPoint, 0); + Disp_Sens[1] = solver->GetNodes()->GetBoundDisp_Sens(iPoint, 1); + if (geometry->GetnDim() == 3) + Disp_Sens[2] = solver->GetNodes()->GetBoundDisp_Sens(iPoint, 2); + else + Disp_Sens[2] = 0.0; + + Disp_Sens_passive[0] = SU2_TYPE::GetValue(Disp_Sens[0]); + Disp_Sens_passive[1] = SU2_TYPE::GetValue(Disp_Sens[1]); + Disp_Sens_passive[2] = SU2_TYPE::GetValue(Disp_Sens[2]); + + return Disp_Sens_passive; + } vector CDriver::GetFlowLoad_Sensitivity(unsigned short iMarker, unsigned long iVertex) const { - - unsigned long iPoint; - vector FlowLoad_Sens(3, 0.0); - vector FlowLoad_Sens_passive(3, 0.0); - - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJFEA_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - FlowLoad_Sens[0] = solver->GetNodes()->GetFlowTractionSensitivity(iPoint, 0); - FlowLoad_Sens[1] = solver->GetNodes()->GetFlowTractionSensitivity(iPoint, 1); - if (geometry->GetnDim() == 3) - FlowLoad_Sens[2] = solver->GetNodes()->GetFlowTractionSensitivity(iPoint, 2); - else - FlowLoad_Sens[2] = 0.0; - - FlowLoad_Sens_passive[0] = SU2_TYPE::GetValue(FlowLoad_Sens[0]); - FlowLoad_Sens_passive[1] = SU2_TYPE::GetValue(FlowLoad_Sens[1]); - FlowLoad_Sens_passive[2] = SU2_TYPE::GetValue(FlowLoad_Sens[2]); - - return FlowLoad_Sens_passive; - + + unsigned long iPoint; + vector FlowLoad_Sens(3, 0.0); + vector FlowLoad_Sens_passive(3, 0.0); + + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJFEA_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + FlowLoad_Sens[0] = solver->GetNodes()->GetFlowTractionSensitivity(iPoint, 0); + FlowLoad_Sens[1] = solver->GetNodes()->GetFlowTractionSensitivity(iPoint, 1); + if (geometry->GetnDim() == 3) + FlowLoad_Sens[2] = solver->GetNodes()->GetFlowTractionSensitivity(iPoint, 2); + else + FlowLoad_Sens[2] = 0.0; + + FlowLoad_Sens_passive[0] = SU2_TYPE::GetValue(FlowLoad_Sens[0]); + FlowLoad_Sens_passive[1] = SU2_TYPE::GetValue(FlowLoad_Sens[1]); + FlowLoad_Sens_passive[2] = SU2_TYPE::GetValue(FlowLoad_Sens[2]); + + return FlowLoad_Sens_passive; + } void CDriver::SetFlowLoad_Adjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, passivedouble val_AdjointY, passivedouble val_AdjointZ) { - - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - solver->StoreVertexTractionsAdjoint(iMarker, iVertex, 0, val_AdjointX); - solver->StoreVertexTractionsAdjoint(iMarker, iVertex, 1, val_AdjointY); - if (geometry->GetnDim() == 3) - solver->StoreVertexTractionsAdjoint(iMarker, iVertex, 2, val_AdjointZ); - + + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + solver->StoreVertexTractionsAdjoint(iMarker, iVertex, 0, val_AdjointX); + solver->StoreVertexTractionsAdjoint(iMarker, iVertex, 1, val_AdjointY); + if (geometry->GetnDim() == 3) + solver->StoreVertexTractionsAdjoint(iMarker, iVertex, 2, val_AdjointZ); + } void CDriver::SetSourceTerm_DispAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, passivedouble val_AdjointY, passivedouble val_AdjointZ) { - - unsigned long iPoint; - - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJFEA_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - - solver->GetNodes()->SetSourceTerm_DispAdjoint(iPoint, 0, val_AdjointX); - solver->GetNodes()->SetSourceTerm_DispAdjoint(iPoint, 1, val_AdjointY); - if (geometry->GetnDim() == 3) - solver->GetNodes()->SetSourceTerm_DispAdjoint(iPoint, 2, val_AdjointZ); - + + unsigned long iPoint; + + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJFEA_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + + solver->GetNodes()->SetSourceTerm_DispAdjoint(iPoint, 0, val_AdjointX); + solver->GetNodes()->SetSourceTerm_DispAdjoint(iPoint, 1, val_AdjointY); + if (geometry->GetnDim() == 3) + solver->GetNodes()->SetSourceTerm_DispAdjoint(iPoint, 2, val_AdjointZ); + } void CDriver::SetSourceTerm_VelAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, - passivedouble val_AdjointY, passivedouble val_AdjointZ) { - - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJFEA_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - const auto iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); - - solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 0, val_AdjointX); - solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 1, val_AdjointY); - if (geometry->GetnDim() == 3) - solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 2, val_AdjointZ); - + passivedouble val_AdjointY, passivedouble val_AdjointZ) { + + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJFEA_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + const auto iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + + solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 0, val_AdjointX); + solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 1, val_AdjointY); + if (geometry->GetnDim() == 3) + solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 2, val_AdjointZ); + } //////////////////////////////////////////////////////////////////////////////// @@ -673,26 +673,26 @@ void CDriver::SetSourceTerm_VelAdjoint(unsigned short iMarker, unsigned long iVe //////////////////////////////////////////////////////////////////////////////// vector CDriver::GetFlowLoad(unsigned short iMarker, unsigned long iVertex) const { - - vector FlowLoad(3, 0.0); - vector FlowLoad_passive(3, 0.0); - - CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]; - CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - if (config_container[ZONE_0]->GetSolid_Wall(iMarker)) { - FlowLoad[0] = solver->GetVertexTractions(iMarker, iVertex, 0); - FlowLoad[1] = solver->GetVertexTractions(iMarker, iVertex, 1); - if (geometry->GetnDim() == 3) - FlowLoad[2] = solver->GetVertexTractions(iMarker, iVertex, 2); - else - FlowLoad[2] = 0.0; - } - - FlowLoad_passive[0] = SU2_TYPE::GetValue(FlowLoad[0]); - FlowLoad_passive[1] = SU2_TYPE::GetValue(FlowLoad[1]); - FlowLoad_passive[2] = SU2_TYPE::GetValue(FlowLoad[2]); - - return FlowLoad_passive; - + + vector FlowLoad(3, 0.0); + vector FlowLoad_passive(3, 0.0); + + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][FLOW_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + + if (config_container[ZONE_0]->GetSolid_Wall(iMarker)) { + FlowLoad[0] = solver->GetVertexTractions(iMarker, iVertex, 0); + FlowLoad[1] = solver->GetVertexTractions(iMarker, iVertex, 1); + if (geometry->GetnDim() == 3) + FlowLoad[2] = solver->GetVertexTractions(iMarker, iVertex, 2); + else + FlowLoad[2] = 0.0; + } + + FlowLoad_passive[0] = SU2_TYPE::GetValue(FlowLoad[0]); + FlowLoad_passive[1] = SU2_TYPE::GetValue(FlowLoad[1]); + FlowLoad_passive[2] = SU2_TYPE::GetValue(FlowLoad[2]); + + return FlowLoad_passive; + } diff --git a/SU2_DEF/include/SU2_DEF.hpp b/SU2_DEF/include/SU2_DEF.hpp index b0f7ab26fc2..ea076540340 100644 --- a/SU2_DEF/include/SU2_DEF.hpp +++ b/SU2_DEF/include/SU2_DEF.hpp @@ -26,7 +26,6 @@ * License along with SU2. If not, see . */ - #pragma once #include "../../Common/include/parallelization/mpi_structure.hpp" diff --git a/SU2_DEF/include/drivers/CDeformationDriver.hpp b/SU2_DEF/include/drivers/CDeformationDriver.hpp index 329c660bb4c..507978d77e7 100644 --- a/SU2_DEF/include/drivers/CDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDeformationDriver.hpp @@ -41,74 +41,74 @@ #include "../../../Common/include/drivers/CDriverBase.hpp" class CDeformationDriver : public CDriverBase { - + protected: - bool haveSurfaceDeformation = false; // flag used to determine whether surface deformation is available for output - + bool haveSurfaceDeformation = false; // flag used to determine whether surface deformation is available for output + public: - /*! - * \brief Constructor of the class. - * \param[in] confFile - Configuration file name. - * \param[in] MPICommunicator - MPI communicator for SU2. - */ - CDeformationDriver(char* confFile, SU2_Comm MPICommunicator); - - /*! - * \brief Destructor of the class. - */ - ~CDeformationDriver(void); - - /*! - * \brief [Overload] Launch the computation for single-zone problems. - */ - void Run(); - - /*! - * \brief Output the mesh. - */ - void Output(); - - /*! - * \brief Deallocation routine - */ - void Postprocessing(); - - void CommunicateMeshDisplacements(void); - + /*! + * \brief Constructor of the class. + * \param[in] confFile - Configuration file name. + * \param[in] MPICommunicator - MPI communicator for SU2. + */ + CDeformationDriver(char* confFile, SU2_Comm MPICommunicator); + + /*! + * \brief Destructor of the class. + */ + ~CDeformationDriver(void); + + /*! + * \brief [Overload] Launch the computation for single-zone problems. + */ + void Run(); + + /*! + * \brief Output the mesh. + */ + void Output(); + + /*! + * \brief Deallocation routine + */ + void Postprocessing(); + + void CommunicateMeshDisplacements(void); + protected: - /*! - * \brief Read in the config and mesh files. - */ - void Input_Preprocessing(); - - /*! - * \brief Construction of the edge-based data structure. - */ - void Geometrical_Preprocessing(); - - /*! - * \brief Preprocess the output container. - */ - void Output_Preprocessing(); - - /*! - * \brief Preprocess the mesh solver container. - */ - void Solver_Preprocessing(); - - /*! - * \brief Preprocess the numerics container. - */ - void Numerics_Preprocessing(); - - /*! - * \brief Mesh deformation based on linear elasticity solver (CMeshSolver). - */ - void Update(); - - /*! - * \brief Mesh deformation based on legacy implementation. - */ - void Update_Legacy(); - + /*! + * \brief Read in the config and mesh files. + */ + void Input_Preprocessing(); + + /*! + * \brief Construction of the edge-based data structure. + */ + void Geometrical_Preprocessing(); + + /*! + * \brief Preprocess the output container. + */ + void Output_Preprocessing(); + + /*! + * \brief Preprocess the mesh solver container. + */ + void Solver_Preprocessing(); + + /*! + * \brief Preprocess the numerics container. + */ + void Numerics_Preprocessing(); + + /*! + * \brief Mesh deformation based on linear elasticity solver (CMeshSolver). + */ + void Update(); + + /*! + * \brief Mesh deformation based on legacy implementation. + */ + void Update_Legacy(); + }; diff --git a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp index 1f1f79b76c1..176f89b93f9 100644 --- a/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp +++ b/SU2_DEF/include/drivers/CDiscAdjDeformationDriver.hpp @@ -51,7 +51,7 @@ * \version 7.3.0 "Blackbird" */ class CDiscAdjDeformationDriver : public CDriverBase { - + protected: su2double** Gradient; ofstream Gradient_file; diff --git a/SU2_DEF/src/SU2_DEF.cpp b/SU2_DEF/src/SU2_DEF.cpp index 4cf24b8b5d1..3c5d4db9273 100644 --- a/SU2_DEF/src/SU2_DEF.cpp +++ b/SU2_DEF/src/SU2_DEF.cpp @@ -25,52 +25,51 @@ * License along with SU2. If not, see . */ - #include "../include/SU2_DEF.hpp" using namespace std; int main(int argc, char *argv[]) { - - char config_file_name[MAX_STRING_SIZE]; - - /*--- Create a pointer to the main SU2_DEF Driver ---*/ - - CDeformationDriver* driver = nullptr; - - /*--- MPI initialization ---*/ - + + char config_file_name[MAX_STRING_SIZE]; + + /*--- Create a pointer to the main SU2_DEF Driver ---*/ + + CDeformationDriver* driver = nullptr; + + /*--- MPI initialization ---*/ + #if defined(HAVE_OMP) && defined(HAVE_MPI) - int provided; - SU2_MPI::Init_thread(&argc, &argv, MPI_THREAD_FUNNELED, &provided); + int provided; + SU2_MPI::Init_thread(&argc, &argv, MPI_THREAD_FUNNELED, &provided); #else - SU2_MPI::Init(&argc, &argv); + SU2_MPI::Init(&argc, &argv); #endif - SU2_MPI::Comm comm = SU2_MPI::GetComm(); - - /*--- Load in the number of zones and spatial dimensions in the mesh file - (if no config file is specified, default.cfg is used) ---*/ - - if (argc == 2) { strcpy(config_file_name, argv[1]); } - else { strcpy(config_file_name, "default.cfg"); } - - /*--- Initialize the mesh deformation driver ---*/ - - driver = new CDeformationDriver(config_file_name, comm); - - /*--- Launch the main external loop of the solver. ---*/ - - driver->Run(); - - /*--- Postprocess all the containers, close history file, exit SU2. ---*/ - - driver->Postprocessing(); - - delete driver; - - /*--- Finalize MPI parallelization ---*/ - SU2_MPI::Finalize(); - - return EXIT_SUCCESS; - + SU2_MPI::Comm comm = SU2_MPI::GetComm(); + + /*--- Load in the number of zones and spatial dimensions in the mesh file + (if no config file is specified, default.cfg is used) ---*/ + + if (argc == 2) { strcpy(config_file_name, argv[1]); } + else { strcpy(config_file_name, "default.cfg"); } + + /*--- Initialize the mesh deformation driver ---*/ + + driver = new CDeformationDriver(config_file_name, comm); + + /*--- Launch the main external loop of the solver. ---*/ + + driver->Run(); + + /*--- Postprocess all the containers, close history file, exit SU2. ---*/ + + driver->Postprocessing(); + + delete driver; + + /*--- Finalize MPI parallelization ---*/ + SU2_MPI::Finalize(); + + return EXIT_SUCCESS; + } diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 8bf4b8b9e98..ecca754838a 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -36,7 +36,7 @@ using namespace std; CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator): - CDriverBase(confFile, 1, MPICommunicator) +CDriverBase(confFile, 1, MPICommunicator) { /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ @@ -107,7 +107,7 @@ void CDeformationDriver::Input_Preprocessing() { /*--- Initialize the configuration of the driver ---*/ driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); - nZone = driver_config->GetnZone(); + nZone = driver_config->GetnZone(); /*--- Loop over all zones to initialize the various classes. In most cases, nZone is equal to one. This represents the solution of a partial @@ -162,7 +162,7 @@ void CDeformationDriver::Geometrical_Preprocessing() { unsigned short nInst_Zone = nInst[iZone]; unsigned short nMesh = 1; - + geometry_container[iZone] = new CGeometry**[nInst_Zone] (); geometry_container[iZone][INST_0] = new CGeometry*[nMesh] (); geometry_container[iZone][INST_0][MESH_0] = new CPhysicalGeometry(geometry_aux, config_container[iZone]); @@ -217,7 +217,7 @@ void CDeformationDriver::Geometrical_Preprocessing() { geometry_container[iZone][INST_0][MESH_0]->PreprocessP2PComms(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); } - + /*--- Get the number of dimensions ---*/ nDim = geometry_container[ZONE_0][INST_0][MESH_0]->GetnDim(); } @@ -247,13 +247,13 @@ void CDeformationDriver::Solver_Preprocessing() { unsigned short nInst_Zone = nInst[iZone]; unsigned short nMesh = 1; unsigned short nSols = MAX_SOLS; - - + + solver_container[iZone] = new CSolver*** [nInst_Zone] (); solver_container[iZone][INST_0] = new CSolver** [nMesh] (); solver_container[iZone][INST_0][MESH_0] = new CSolver* [nSols] (); solver_container[iZone][INST_0][MESH_0][MESH_SOL] = new CMeshSolver(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); - } + } } void CDeformationDriver::Numerics_Preprocessing() { @@ -263,7 +263,7 @@ void CDeformationDriver::Numerics_Preprocessing() { unsigned short nMesh = 1; unsigned short nSols = MAX_SOLS; unsigned int nTerm = omp_get_num_threads() * MAX_TERMS; - + numerics_container[iZone] = new CNumerics**** [nInst_Zone] (); numerics_container[iZone][INST_0] = new CNumerics*** [nMesh] (); numerics_container[iZone][INST_0][MESH_0] = new CNumerics** [nSols] (); @@ -328,7 +328,7 @@ void CDeformationDriver::Update() { } void CDeformationDriver::Update_Legacy() { - + for (iZone = 0; iZone < nZone; iZone++){ if (config_container[iZone]->GetDesign_Variable(0) != NO_DEFORMATION) { @@ -510,7 +510,7 @@ void CDeformationDriver::Output() { /*--- Load the data --- */ output_container[iZone]->Load_Data(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], nullptr); - + output_container[iZone]->WriteToFile(config_container[iZone], geometry_container[iZone][INST_0][MESH_0], OUTPUT_TYPE::MESH, driver_config->GetMesh_Out_FileName()); /*--- Set the file names for the visualization files ---*/ @@ -539,9 +539,9 @@ void CDeformationDriver::Output() { } else { if (rank == MASTER_NODE) cout << "Adding any FFD information to the SU2 file." << endl; - + surface_movement[ZONE_0]->WriteFFDInfo(surface_movement, geometry_container, config_container); - } + } } } } diff --git a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp index fea679b6f55..bab02b385ca 100644 --- a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp @@ -32,7 +32,7 @@ using namespace std; CDiscAdjDeformationDriver::CDiscAdjDeformationDriver(char* confFile, SU2_Comm MPICommunicator): - CDriverBase(confFile, 1, MPICommunicator) +CDriverBase(confFile, 1, MPICommunicator) { /*--- Initialize Medipack (must also be here so it is initialized from python) ---*/ #ifdef HAVE_MPI @@ -83,14 +83,14 @@ CDiscAdjDeformationDriver::~CDiscAdjDeformationDriver(void) { } void CDiscAdjDeformationDriver::Input_Preprocessing() { - + /*--- Initialize a char to store the zone filename ---*/ char zone_file_name[MAX_STRING_SIZE]; /*--- Initialize the configuration of the driver ---*/ driver_config = new CConfig(config_file_name, SU2_COMPONENT::SU2_DEF); - nZone = driver_config->GetnZone(); + nZone = driver_config->GetnZone(); /*--- Loop over all zones to initialize the various classes. In most cases, nZone is equal to one. This represents the solution of a partial @@ -110,11 +110,11 @@ void CDiscAdjDeformationDriver::Input_Preprocessing() { } config_container[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); - + if (!config_container[iZone]->GetDiscrete_Adjoint()) { SU2_MPI::Error("The discrete adjoint solver was not specified in the configuration file.", CURRENT_FUNCTION); } - + } /*--- Set the multizone part of the problem. ---*/ @@ -265,7 +265,7 @@ void CDiscAdjDeformationDriver::Run() { for (iZone = 0; iZone < nZone; iZone++) { if (rank == MASTER_NODE) cout << "Reading volume sensitivities at each node from file." << endl; unsigned short nInst_Zone = nInst[iZone]; - + grid_movement[iZone] = new CVolumetricMovement* [nInst_Zone] (); grid_movement[iZone][INST_0] = new CVolumetricMovement(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); @@ -366,7 +366,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { } delete [] solver_container; if (rank == MASTER_NODE) cout << "Deleted CSolver container." << endl; - + if (geometry_container != nullptr) { for (iZone = 0; iZone < nZone; iZone++) { if (geometry_container[iZone] != nullptr) { @@ -425,7 +425,7 @@ void CDiscAdjDeformationDriver::Postprocessing() { if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; if (nInst != nullptr) delete [] nInst; - + /*--- Exit the solver cleanly ---*/ if (rank == MASTER_NODE) From 976408cfbc3a97e4a43a0954f5add106028a4157 Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 21 Feb 2022 16:23:49 +0100 Subject: [PATCH 020/598] Fix dangling if statement in CDiscAdjDeformationDriver --- SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp index bab02b385ca..a91ade80097 100644 --- a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp @@ -312,18 +312,19 @@ void CDiscAdjDeformationDriver::Run() { /*--- Copy coordinates to the surface structure ---*/ surface_movement[iZone]->CopyBoundary(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); - + /*--- If AD mode is enabled we can use it to compute the projection, * otherwise we use finite differences. ---*/ - if (config_container[iZone]->GetAD_Mode()) + if (config_container[iZone]->GetAD_Mode()) { if (config_container[iZone]->GetSmoothGradient()) { DerivativeTreatment_Gradient(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], grid_movement[iZone][INST_0], surface_movement[iZone] , Gradient); } else { SetProjection_AD(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], surface_movement[iZone] , Gradient); } - } else { - SetProjection_FD(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], surface_movement[iZone] , Gradient); + } else { + SetProjection_FD(geometry_container[iZone][INST_0][MESH_0], config_container[iZone], surface_movement[iZone] , Gradient); + } } } // for iZone From 1b4ba30126576d9141d7b76c4ed72115d8ca2250 Mon Sep 17 00:00:00 2001 From: aa-g Date: Thu, 3 Mar 2022 22:58:57 +0100 Subject: [PATCH 021/598] Fix py_wrapper tests broken by new Python interface --- .../py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py | 2 +- .../py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TestCases/py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py b/TestCases/py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py index 1f994db4118..89006b9a53a 100755 --- a/TestCases/py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py +++ b/TestCases/py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py @@ -71,7 +71,7 @@ def main(): MarkerList = SU2Driver.GetAllBoundaryMarkersTag() # Get all the markers defined on this rank and their associated indices. - allMarkerIDs = SU2Driver.GetAllBoundaryMarkers() + allMarkerIDs = SU2Driver.GetBoundaryMarkerIndices() #Check if the specified marker exists and if it belongs to this rank. if MarkerName in MarkerList and MarkerName in allMarkerIDs.keys(): diff --git a/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py b/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py index f4ee6ed5b68..2229ad8ce5c 100755 --- a/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py +++ b/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py @@ -70,7 +70,7 @@ def main(): MarkerList = SU2Driver.GetAllBoundaryMarkersTag() # Get all the markers defined on this rank and their associated indices. - allMarkerIDs = SU2Driver.GetAllBoundaryMarkers() + allMarkerIDs = SU2Driver.GetBoundaryMarkerIndices() #Check if the specified marker exists and if it belongs to this rank. if MarkerName in MarkerList and MarkerName in allMarkerIDs.keys(): @@ -80,7 +80,7 @@ def main(): nVertex_Marker = 0 #total number of vertices (physical + halo) if MarkerID != None: - nVertex_Marker = SU2Driver.GetNumberVertices(MarkerID) + nVertex_Marker = SU2Driver.GetNumberVerticesMarker(MarkerID) # Time loop is defined in Python so that we have acces to SU2 functionalities at each time step if rank == 0: From 4a79c133f4fe29405961451de71c7e4a5fe9dbfd Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 7 Mar 2022 20:12:46 +0100 Subject: [PATCH 022/598] Implement overleaded getters/setter --- Common/include/drivers/CDriverBase.hpp | 376 ++++++++-- Common/src/drivers/CDriverBase.cpp | 688 ++++++++++++------ SU2_CFD/include/drivers/CDriver.hpp | 16 +- SU2_CFD/src/python_wrapper_structure.cpp | 58 +- .../flow_load_sens/run_adjoint.py | 4 +- .../mesh_disp_sens/run_adjoint.py | 8 +- .../launch_flatPlate_rigidMotion.py | 17 +- .../launch_unsteady_CHT_FlatPlate.py | 15 +- 8 files changed, 832 insertions(+), 350 deletions(-) diff --git a/Common/include/drivers/CDriverBase.hpp b/Common/include/drivers/CDriverBase.hpp index 28619eab44e..6b9590fdd22 100644 --- a/Common/include/drivers/CDriverBase.hpp +++ b/Common/include/drivers/CDriverBase.hpp @@ -111,19 +111,30 @@ class CDriverBase { * \brief A virtual member. */ virtual void Postprocessing() {}; + /*! + * \brief Get the number of markers in the mesh. + * \return Number of markers. + */ + unsigned short GetNumberMarkers() const; /*! * \brief Get all the boundary markers tags with their associated indices. * \return List of boundary markers tags with their indices. */ - map GetBoundaryMarkerIndices() const; + map GetMarkerIndices() const; /*! * \brief Get all the boundary markers tags with their associated types. * \return List of boundary markers tags with their types. */ - map GetBoundaryMarkerTypes() const; + map GetMarkerTypes() const; + /*! + * \brief Get all the boundary marker tags. + * \return List of boundary markers tags. + */ + vector GetMarkerTags() const; + /*! * \brief Get all the deformable boundary marker tags. * \return List of deformable boundary markers tags. @@ -131,170 +142,393 @@ class CDriverBase { vector GetDeformableMarkerTags() const; /*! - * \brief Get the number of mesh dimensions. + * \brief Get the number of dimensions of the mesh. * \return Number of dimensions. */ unsigned long GetNumberDimensions() const; /*! - * \brief Get the number of mesh elements. + * \brief Get the number of elements in the mesh. * \return Number of elements. */ unsigned long GetNumberElements() const; /*! - * \brief Get the number of mesh elements from a specified marker. - * \param[in] iMarker - Marker identifier. + * \brief Get the number of elements in the marker. + * \param[in] iMarker - Marker index. * \return Number of elements. */ - unsigned long GetNumberElementsMarker(unsigned short iMarker) const; + unsigned long GetNumberMarkerElements(unsigned short iMarker) const; + + /*! + * \brief Get the global IDs of the mesh elements. + * \return Global element IDs. + */ + vector GetElementIDs() const; /*! - * \brief Get the number of mesh vertices. + * \brief Get the global ID of a mesh element. + * \param[in] iElem - Mesh element index. + * \return Global element ID. + */ + unsigned long GetElementIDs(unsigned long iElem) const; + + /*! + * \brief Get the global IDs of the marker elements. + * \param[in] iMarker - Marker index. + * \return Global element IDs. + */ + vector GetMarkerElementIDs(unsigned short iMarker) const; + + /*! + * \brief Get the global IDs of a marker element. + * \param[in] iMarker - Marker index. + * \param[in] iBound - Marker element index. + * \return Global element ID. + */ + unsigned long GetMarkerElementIDs(unsigned short iMarker, unsigned long iBound) const; + + /*! + * \brief Get the MPI colors for mesh elements. + * \return Element colors. + */ + vector GetElementColors() const; + + /*! + * \brief Get the MPI color for a mesh element. + * \param[in] iElem - Mesh element index. + * \return Element color. + */ + unsigned long GetElementColors(unsigned long iElem) const; + + /*! + * \brief Get the MPI colors for marker elements. + * \param[in] iMarker - Marker index. + * \return Element colors. + */ + vector GetMarkerElementColors(unsigned short iMarker) const; + + /*! + * \brief Get the MPI color for a marker element. + * \param[in] iMarker - Marker index. + * \param[in] iBound - Marker element index. + * \return Element color. + */ + unsigned long GetMarkerElementColors(unsigned short iMarker, unsigned long iBound) const; + + /*! + * \brief Get the table of vertex IDs belonging to the mesh elements. + * \return Element connectivities (nElem, nNode) + */ + vector> GetElementConnectivities() const; + + /*! + * \brief Get the row of vertex IDs belonging to a mesh element. + * \param[in] iElem - Mesh element index. + * \return Element connectivity (nNode) + */ + vector GetElementConnectivities(unsigned long iElem) const; + + /*! + * \brief Get the table of vertex IDs belonging to the marker elements. + * \param[in] iMarker - Marker index. + * \return Element connectivities (nBound, nNode). + */ + vector> GetMarkerElementConnectivities(unsigned short iMarker) const; + + /*! + * \brief Get the row of vertex IDs belonging to a marker element. + * \param[in] iMarker - Marker index. + * \param[in] iBound - Marker element index. + * \return Element connectivity (nNode). + */ + vector GetMarkerElementConnectivities(unsigned short iMarker, unsigned long iBound) const; + + /*! + * \brief Get the number of vertices in the mesh. * \return Number of vertices. */ unsigned long GetNumberVertices() const; /*! - * \brief Get the number of mesh vertices from a specified marker. - * \param[in] iMarker - Marker identifier. + * \brief Get the number of vertices in the marker. + * \param[in] iMarker - Marker index. * \return Number of vertices. */ - unsigned long GetNumberVerticesMarker(unsigned short iMarker) const; + unsigned long GetNumberMarkerVertices(unsigned short iMarker) const; /*! - * \brief Get the number of halo mesh vertices. + * \brief Get the number of halo vertices in the mesh. * \return Number of vertices. */ unsigned long GetNumberHaloVertices() const; /*! - * \brief Get the number of halo mesh vertices from a specified marker. - * \param[in] iMarker - Marker identifier. + * \brief Get the number of halo vertices in the marker. + * \param[in] iMarker - Marker index. * \return Number of vertices. */ - unsigned long GetNumberHaloVerticesMarker(unsigned short iMarker) const; + unsigned long GetNumberMarkerHaloVertices(unsigned short iMarker) const; /*! - * \brief Get global IDs of mesh vertices. + * \brief Get the mesh vertex indices of the marker vertices. + * \param[in] iMarker - Marker index. + * \return Mesh vertex indices. + */ + vector GetMarkerVertexIndex(unsigned short iMarker) const; + + /*! + * \brief Get the mesh vertex index of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \return Mesh vertex index. + */ + unsigned long GetMarkerVertexIndex(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get the global IDs of the mesh vertices. * \return Global vertex IDs. */ vector GetVertexIDs() const; + + /*! + * \brief Get the global ID of a mesh vertex. + * \param[in] iPoint - Mesh vertex index. + * \return Global vertex ID. + */ + unsigned long GetVertexIDs(unsigned long iPoint) const; /*! - * \brief Get global IDs of mesh vertices. - * \param[in] iMarker - Marker identifier. + * \brief Get the global IDs of the marker vertices. + * \param[in] iMarker - Marker index. * \return Global vertex IDs. */ - vector GetVertexIDsMarker(unsigned short iMarker) const; + vector GetMarkerVertexIDs(unsigned short iMarker) const; /*! - * \brief Get global IDs of mesh elements. - * \return Global element IDs. + * \brief Get the global ID of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \return Global vertex ID. */ - vector GetElementIDs() const; + unsigned long GetMarkerVertexIDs(unsigned short iMarker, unsigned long iVertex) const; /*! - * \brief Get global IDs of mesh elements. - * \param[in] iMarker - Marker identifier. - * \return Global element IDs. + * \brief Get the MPI colors of the mesh vertices. + * \return Vertex colors. */ - vector GetElementIDsMarker(unsigned short iMarker) const; + vector GetVertexColors() const; /*! - * \brief Get the connected point IDs of mesh elements. - * \return Element connectivities (nElem, nNode) + * \brief Get the MPI color of a mesh vertex. + * \param[in] iPoint - Mesh vertex index. + * \return Vertex color. */ - vector> GetConnectivity() const; + unsigned long GetVertexColors(unsigned long iPoint) const; /*! - * \brief Get the connected point IDs of mesh elements on a specified marker. - * \param[in] iMarker - Marker identifier. - * \return Element connectivities (nBound, nNode). + * \brief Get the MPI colors of the marker vertices. + * \param[in] iMarker - Marker index. + * \return Vertex colors. */ - vector> GetConnectivityMarker(unsigned short iMarker) const; + vector GetMarkerVertexColors(unsigned short iMarker) const; /*! - * \brief Get halo node stauts of mesh vertices. - * \return Point domain status. + * \brief Get the MPI color of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \return Vertex color. + */ + unsigned long GetMarkerVertexColors(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get the halo flags of the mesh vertices. + * \return Vertex domain flags. */ vector GetDomain() const; /*! - * \brief Get halo node stauts of mesh marker vertices. - * \param[in] iMarker - Marker identifier. - * \return Point domain status. + * \brief Get the halo flag of a mesh vertex. + * \param[in] iPoint - Mesh vertex index. + * \return Vertex domain flag. + */ + bool GetDomain(unsigned long iPoint) const; + + /*! + * \brief Get the halo flags of the marker vertices. + * \param[in] iMarker - Marker index. + * \return Vertex domain flags. + */ + vector GetMarkerDomain(unsigned short iMarker) const; + + /*! + * \brief Get the halo flag of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \return Vertex domain flag. + */ + bool GetMarkerDomain(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Get the initial (un-deformed) coordinates of the mesh vertices. + * \return Initial vertex coordinates (nPoint*nDim). + */ + vector GetInitialCoordinates() const; + + /*! + * \brief Get the initial (un-deformed) coordinates of a mesh vertex. + * \param[in] iPoint - Mesh vertex index. + * \return Initial vertex coordinates (nDim). + */ + vector GetInitialCoordinates(unsigned long iPoint) const; + + /*! + * \brief Get the initial (un-deformed) coordinates of the marker vertices. + * \param[in] iMarker - Marker index. + * \return Initial vertex coordinates (nVertex*nDim). + */ + vector GetMarkerInitialCoordinates(unsigned short iMarker) const; + + /*! + * \brief Get the initial (un-deformed) coordinates of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \return Initial vertex coordinates (nDim). */ - vector GetDomainMarker(unsigned short iMarker) const; + vector GetMarkerInitialCoordinates(unsigned short iMarker, unsigned long iVertex) const; /*! - * \brief Get the coordinates of the mesh points. - * \return Point coordinates (nPoint*nDim). + * \brief Get the coordinates of the mesh vertices. + * \return Vertex coordinates (nPoint*nDim). */ vector GetCoordinates() const; + + /*! + * \brief Get the coordinates of a mesh vertex. + * \param[in] iPoint - Mesh vertex index. + * \return Vertex coordinates (nDim). + */ + vector GetCoordinates(unsigned long iPoint) const; + + /*! + * \brief Get the coordinates of the marker vertices. + * \param[in] iMarker - Marker index. + * \return Vertex coordinates (nVertex*nDim). + */ + vector GetMarkerCoordinates(unsigned short iMarker) const; /*! - * \brief Get the coordinates of the mesh points on the specified marker. - * \param[in] iMarker - Marker identifier. - * \return Point coordinates (nVertex*nDim). + * \brief Get the coordinates of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \return Vertex coordinates (nDim). */ - vector GetCoordinatesMarker(unsigned short iMarker) const; + vector GetMarkerCoordinates(unsigned short iMarker, unsigned long iVertex) const; /*! - * \brief Set the coordinates of the mesh points. - * \param[in] values - Point coordinates (nPoint*nDim). + * \brief Set the coordinates of the mesh vertices. + * \param[in] values - Vertex coordinates (nPoint*nDim). */ void SetCoordinates(vector values); /*! - * \brief Set the coordinates of the mesh points on the specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] values - Point coordinates (nVertex*nDim). + * \brief Set the coordinates of a mesh vertex. + * \param[in] iPoint - Mesh vertex index. + * \param[in] values - Vertex coordinates (nDim). + */ + void SetCoordinates(unsigned long iPoint, vector values); + + /*! + * \brief Set the coordinates of the marker vertices. + * \param[in] iMarker - Marker index. + * \param[in] values - Vertex coordinates (nVertex*nDim). + */ + void SetMarkerCoordinates(unsigned short iMarker, vector values); + + /*! + * \brief Set the coordinates of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \param[in] values - Vertex coordinates (nDim). */ - void SetCoordinatesMarker(unsigned short iMarker, vector values); + void SetMarkerCoordinates(unsigned short iMarker, unsigned long iVertex, vector values); /*! - * \brief Get the vertex displacements on the specified marker. - * \param[in] iMarker - Marker identifier. + * \brief Get the displacements of the marker vertices. + * \param[in] iMarker - Marker index. * \return Vertex displacements (nVertex*nDim). */ - vector GetDisplacementsMarker(unsigned short iMarker) const; + vector GetMarkerDisplacements(unsigned short iMarker) const; /*! - * \brief Set the vertex displacements on the specified marker. - * \param[in] iMarker - Marker identifier. + * \brief Get the displacements of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \return Vertex displacements (nDim). + */ + vector GetMarkerDisplacements(unsigned short iMarker, unsigned long iVertex) const; + + /*! + * \brief Set the displacements of the marker vertices. + * \param[in] iMarker - Marker index. * \param[in] values - Vertex displacements (nVertex*nDim). */ - void SetDisplacementsMarker(unsigned short iMarker, vector values); + void SetMarkerDisplacements(unsigned short iMarker, vector values); /*! - * \brief Get the vertex velocities on the specified marker. - * \param[in] iMarker - Marker identifier. + * \brief Set the displacements of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \param[in] values - Vertex displacements (nDim). + */ + void SetMarkerDisplacements(unsigned short iMarker, unsigned long iVertex, vector values); + + /*! + * \brief Get the velocities of the marker vertices. + * \param[in] iMarker - Marker index. * \return Vertex velocities (nVertex*nDim). */ - vector GetVelocitiesMarker(unsigned short iMarker) const; + vector GetMarkerVelocities(unsigned short iMarker) const; + + /*! + * \brief Get the velocities of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \return Vertex velocities (nVertex*nDim). + */ + vector GetMarkerVelocities(unsigned short iMarker, unsigned long iVertex) const; /*! - * \brief Set the vertex velocities on the specified marker. - * \param[in] iMarker - Marker identifier. + * \brief Set the velocities of the marker vertices. + * \param[in] iMarker - Marker index. * \param[in] values - Vertex velocities (nVertex*nDim). */ - void SetVelocitiesMarker(unsigned short iMarker, vector values); + void SetMarkerVelocities(unsigned short iMarker, vector values); /*! - * \brief Get undeformed coordinates from mesh solver on the specified marker. - * \param[in] iMarker - Marker identifier. - * \return Initial point coordinates (nVertex*nDim). + * \brief Set the velocities of a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \param[in] values - Vertex velocities (nDim). */ - vector GetInitialCoordinatesMarker(unsigned short iMarker) const; + void SetMarkerVelocities(unsigned short iMarker, unsigned long iVertex, vector values); /*! - * \brief Get the vertex normal vectors on the specified marker. - * \param[in] iMarker - Marker identifier. - * \param[in] UnitNormal - Boolean to indicate if unit normal vector should be returned. + * \brief Get the normal vectors at the marker vertices. + * \param[in] iMarker - Marker index. + * \param[in] normalize - If true, the unit (i.e. normalized) normal vector is returned. * \return Normal vector at the vertex (nVertex*nDim). */ - vector GetVertexNormalsMarker(unsigned short iMarker, bool UnitNormal = false) const; + vector GetMarkerVertexNormals(unsigned short iMarker, bool normalize = false) const; + + /*! + * \brief Get the normal vectors at a marker vertex. + * \param[in] iMarker - Marker index. + * \param[in] iVertex - Marker vertex index. + * \param[in] normalize - If true, the unit (i.e. normalized) normal vector is returned. + * \return Normal vector at the vertex (nDim). + */ + vector GetMarkerVertexNormals(unsigned short iMarker, unsigned long iVertex, bool normalize = false) const; /*! * \brief Communicate the boundary mesh displacements in a python call diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index 98d05d65305..9a3ee6ba686 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -82,78 +82,85 @@ void CDriverBase::SetContainers_Null() { driver_output = nullptr; } -map CDriverBase::GetBoundaryMarkerIndices() const { - CConfig* config = config_container[ZONE_0]; - - const auto nBoundaryMarkers = config->GetnMarker_All(); - map allBoundariesMap; +unsigned short CDriverBase::GetNumberMarkers() const { + return config_container[ZONE_0]->GetnMarker_All(); +} + +map CDriverBase::GetMarkerIndices() const { + const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); + map indexMap; - for (auto iMarker = 0u; iMarker < nBoundaryMarkers; iMarker++) { - auto Marker_Tag = config->GetMarker_All_TagBound(iMarker); - allBoundariesMap[Marker_Tag] = iMarker; + for (auto iMarker = 0u; iMarker < nMarker; iMarker++) { + auto tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); + + indexMap[tag] = iMarker; } - return allBoundariesMap; + return indexMap; } -map CDriverBase::GetBoundaryMarkerTypes() const { - CConfig* config = config_container[ZONE_0]; +map CDriverBase::GetMarkerTypes() const { + map typeMap; + string type; - map allBoundariesTypeMap; - string Marker_Type; - - for (auto iMarker = 0u; iMarker < config->GetnMarker_All(); iMarker++) { - auto Marker_Tag = config->GetMarker_All_TagBound(iMarker); - auto KindBC = config->GetMarker_All_KindBC(iMarker); + for (auto iMarker = 0u; iMarker < config_container[ZONE_0]->GetnMarker_All(); iMarker++) { + auto tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); + auto kindBC = config_container[ZONE_0]->GetMarker_All_KindBC(iMarker); - switch(KindBC) { + switch(kindBC) { case EULER_WALL: - Marker_Type = "EULER_WALL"; + type = "EULER_WALL"; break; case FAR_FIELD: - Marker_Type = "FARFIELD"; + type = "FARFIELD"; break; case ISOTHERMAL: - Marker_Type = "ISOTHERMAL"; + type = "ISOTHERMAL"; break; case HEAT_FLUX: - Marker_Type = "HEATFLUX"; + type = "HEATFLUX"; break; case INLET_FLOW: - Marker_Type = "INLET_FLOW"; + type = "INLET_FLOW"; break; case OUTLET_FLOW: - Marker_Type = "OUTLET_FLOW"; + type = "OUTLET_FLOW"; break; case SYMMETRY_PLANE: - Marker_Type = "SYMMETRY"; + type = "SYMMETRY"; break; case SEND_RECEIVE: - Marker_Type = "SEND_RECEIVE"; + type = "SEND_RECEIVE"; break; default: - Marker_Type = "UNKNOWN_TYPE"; + type = "UNKNOWN_TYPE"; } - allBoundariesTypeMap[Marker_Tag] = Marker_Type; + typeMap[tag] = type; } - return allBoundariesTypeMap; + return typeMap; } -vector CDriverBase::GetDeformableMarkerTags() const { - CConfig* config = config_container[ZONE_0]; +vector CDriverBase::GetMarkerTags() const { + vector tags; + const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); - const auto nBoundariesMarker = config->GetnMarker_Deform_Mesh(); - vector interfaceBoundariesTagList; + for(auto iMarker = 0u; iMarker < nMarker; iMarker++){ + tags.push_back(config_container[ZONE_0]->GetMarker_All_TagBound(iMarker)); + } - interfaceBoundariesTagList.resize(nBoundariesMarker); + return tags; +} + +vector CDriverBase::GetDeformableMarkerTags() const { + vector tags; + const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); - for (auto iMarker = 0u; iMarker < nBoundariesMarker; iMarker++) { - auto Marker_Tag = config->GetMarker_Deform_Mesh_TagBound(iMarker); - interfaceBoundariesTagList[iMarker] = Marker_Tag; + for (auto iMarker = 0u; iMarker < nMarker; iMarker++) { + tags.push_back(config_container[ZONE_0]->GetMarker_Deform_Mesh_TagBound(iMarker)); } - return interfaceBoundariesTagList; + return tags; } unsigned long CDriverBase::GetNumberDimensions() const { @@ -164,26 +171,160 @@ unsigned long CDriverBase::GetNumberElements() const { return geometry_container[ZONE_0][INST_0][MESH_0]->GetnElem(); } -unsigned long CDriverBase::GetNumberElementsMarker(unsigned short iMarker) const { +unsigned long CDriverBase::GetNumberMarkerElements(unsigned short iMarker) const { + if (iMarker >= GetNumberMarkers()) { + SU2_MPI::Error("Marker index exceeds size.", CURRENT_FUNCTION); + } + return geometry_container[ZONE_0][INST_0][MESH_0]->GetnElem_Bound(iMarker); } +vector CDriverBase::GetElementIDs() const { + vector values; + const auto nElem = GetNumberElements(); + + for (auto iElem = 0ul; iElem < nElem; iElem++) { + values.push_back(GetElementIDs(iElem)); + } + + return values; +} + +unsigned long CDriverBase::GetElementIDs(unsigned long iElem) const { + if (iElem >= GetNumberElements()) { + SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); + } + + return geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetGlobalIndex(); +} + +vector CDriverBase::GetMarkerElementIDs(unsigned short iMarker) const { + vector values; + const auto nBound = GetNumberMarkerElements(iMarker); + + for (auto iBound = 0ul; iBound < nBound; iBound++) { + values.push_back(GetMarkerElementIDs(iMarker, iBound)); + } + + return values; +} + +unsigned long CDriverBase::GetMarkerElementIDs(unsigned short iMarker, unsigned long iBound) const { + if (iBound >= GetNumberMarkerElements(iMarker)) { + SU2_MPI::Error("Marker element index exceeds size.", CURRENT_FUNCTION); + } + + return geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetGlobalIndex(); +} + +vector CDriverBase::GetElementColors() const { + vector values; + const auto nElem = GetNumberElements(); + + for (auto iElem = 0ul; iElem < nElem; iElem++) { + values.push_back(GetElementColors(iElem)); + } + + return values; +} + +unsigned long CDriverBase::GetElementColors(unsigned long iElem) const { + if (iElem >= GetNumberElements()) { + SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); + } + + return geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetColor(); +} + +vector CDriverBase::GetMarkerElementColors(unsigned short iMarker) const { + vector values; + const auto nBound = GetNumberMarkerElements(iMarker); + + for (auto iBound = 0ul; iBound < nBound; iBound++) { + values.push_back(GetMarkerElementColors(iMarker, iBound)); + } + + return values; +} + +unsigned long CDriverBase::GetMarkerElementColors(unsigned short iMarker, unsigned long iBound) const { + if (iBound >= GetNumberMarkerElements(iMarker)) { + SU2_MPI::Error("Marker element index exceeds size.", CURRENT_FUNCTION); + } + + return geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetColor(); +} + +vector> CDriverBase::GetElementConnectivities() const { + vector> values; + const auto nElem = GetNumberElements(); + + for (auto iElem = 0ul; iElem < nElem; iElem++) { + values.push_back(GetElementConnectivities(iElem)); + } + + return values; +} + +vector CDriverBase::GetElementConnectivities(unsigned long iElem) const { + if (iElem >= GetNumberElements()) { + SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); + } + + vector values; + unsigned short nNode = geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetnNodes(); + + for (auto iNode = 0u; iNode < nNode; iNode++) { + values.push_back(geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetNode(iNode)); + } + + return values; +} + +vector> CDriverBase::GetMarkerElementConnectivities(unsigned short iMarker) const { + vector> values; + const auto nBound = GetNumberMarkerElements(iMarker); + + for (auto iBound = 0ul; iBound < nBound; iBound++) { + values.push_back(GetMarkerElementConnectivities(iMarker, iBound)); + } + + return values; +} + +vector CDriverBase::GetMarkerElementConnectivities(unsigned short iMarker, unsigned long iBound) const { + if (iBound >= GetNumberMarkerElements(iMarker)) { + SU2_MPI::Error("Marker element index exceeds size.", CURRENT_FUNCTION); + } + + vector values; + unsigned short nNode = geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetnNodes(); + + for (auto iNode = 0u; iNode < nNode; iNode++) { + values.push_back(geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetNode(iNode)); + } + + return values; +} + unsigned long CDriverBase::GetNumberVertices() const { return geometry_container[ZONE_0][INST_0][MESH_0]->GetnPoint(); } -unsigned long CDriverBase::GetNumberVerticesMarker(unsigned short iMarker) const { +unsigned long CDriverBase::GetNumberMarkerVertices(unsigned short iMarker) const { + if (iMarker >= GetNumberMarkers()) { + SU2_MPI::Error("Marker index exceeds size.", CURRENT_FUNCTION); + } + return geometry_container[ZONE_0][INST_0][MESH_0]->GetnVertex(iMarker); } unsigned long CDriverBase::GetNumberHaloVertices() const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - const auto nPoint = geometry->GetnPoint(); + const auto nPoint = GetNumberVertices(); unsigned long nHaloVertices = 0; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - if (!(geometry->nodes->GetDomain(iPoint))) { + if (!(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint))) { nHaloVertices += 1; } } @@ -191,15 +332,14 @@ unsigned long CDriverBase::GetNumberHaloVertices() const { return nHaloVertices; } -unsigned long CDriverBase::GetNumberHaloVerticesMarker(unsigned short iMarker) const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - const auto nVertex = geometry->GetnVertex(iMarker); +unsigned long CDriverBase::GetNumberMarkerHaloVertices(unsigned short iMarker) const { + const auto nVertex = GetNumberMarkerVertices(iMarker); // error-checking included unsigned long nHaloVertices = 0; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (!(geometry->nodes->GetDomain(iPoint))) { + auto iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + + if (!(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint))) { nHaloVertices += 1; } } @@ -207,338 +347,474 @@ unsigned long CDriverBase::GetNumberHaloVerticesMarker(unsigned short iMarker) c return nHaloVertices; } -vector CDriverBase::GetVertexIDs() const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; +vector CDriverBase::GetMarkerVertexIndex(unsigned short iMarker) const { + vector values; + const auto nVertex = GetNumberMarkerVertices(iMarker); + + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + values.push_back(GetMarkerVertexIndex(iMarker, iVertex)); + } + + return values; +} + +unsigned long CDriverBase::GetMarkerVertexIndex(unsigned short iMarker, unsigned long iVertex) const { + if (iVertex >= GetNumberMarkerVertices(iMarker)) { + SU2_MPI::Error("Marker vertex index exceeds size.", CURRENT_FUNCTION); + } - const auto nPoint = geometry->GetnPoint(); + return geometry_container[MESH_0][INST_0][ZONE_0]->vertex[iMarker][iVertex]->GetNode(); +} + +vector CDriverBase::GetVertexIDs() const { vector values; + const auto nPoint = GetNumberVertices(); for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - values.push_back(geometry->nodes->GetGlobalIndex(iPoint)); + values.push_back(GetVertexIDs(iPoint)); } return values; } -vector CDriverBase::GetVertexIDsMarker(unsigned short iMarker) const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - const auto nVertex = geometry->GetnVertex(iMarker); +unsigned long CDriverBase::GetVertexIDs(unsigned long iPoint) const { + if (iPoint >= GetNumberVertices()) { + SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); + } + + return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetGlobalIndex(iPoint); +} + +vector CDriverBase::GetMarkerVertexIDs(unsigned short iMarker) const { vector values; + const auto nVertex = GetNumberMarkerVertices(iMarker); for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - values.push_back(geometry->nodes->GetGlobalIndex(iPoint)); + values.push_back(GetMarkerVertexIDs(iMarker, iVertex)); } return values; } -vector CDriverBase::GetElementIDs() const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - const auto nElem = geometry->GetnElem(); +unsigned long CDriverBase::GetMarkerVertexIDs(unsigned short iMarker, unsigned long iVertex) const { + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); // includes error-checking + + return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetGlobalIndex(iPoint); +} + +vector CDriverBase::GetVertexColors() const { vector values; + const auto nPoint = GetNumberVertices(); - for (auto iElem = 0ul; iElem < nElem; iElem++) { - values.push_back(geometry->elem[iElem]->GetGlobalIndex()); + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + values.push_back(GetVertexColors(iPoint)); } return values; } -vector CDriverBase::GetElementIDsMarker(unsigned short iMarker) const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - const auto nBound = geometry->GetnElem_Bound(iMarker); +unsigned long CDriverBase::GetVertexColors(unsigned long iPoint) const { + if (iPoint >= GetNumberVertices()) { + SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); + } + + return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetColor(iPoint); +} + +vector CDriverBase::GetMarkerVertexColors(unsigned short iMarker) const { vector values; + const auto nVertex = GetNumberMarkerVertices(iMarker); - for (auto iBound = 0ul; iBound < nBound; iBound++) { - values.push_back(geometry->bound[iMarker][iBound]->GetGlobalIndex()); + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + values.push_back(GetMarkerVertexColors(iMarker, iVertex)); } return values; } -vector> CDriverBase::GetConnectivity() const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; +unsigned long CDriverBase::GetMarkerVertexColors(unsigned short iMarker, unsigned long iVertex) const { + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); // includes error-checking - const auto nElem = geometry->GetnElem(); - vector> values(nElem); + return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetColor(iPoint); +} + +vector CDriverBase::GetDomain() const { + vector values; + const auto nPoint = GetNumberVertices(); - for (auto iElem = 0ul; iElem < nElem; iElem++) { - unsigned short nNode = geometry->elem[iElem]->GetnNodes(); - - for (auto iNode = 0u; iNode < nNode; iNode++) { - values[iElem].push_back(geometry->elem[iElem]->GetNode(iNode)); - } + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + values.push_back(GetDomain(iPoint)); } return values; } -vector> CDriverBase::GetConnectivityMarker(unsigned short iMarker) const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; +bool CDriverBase::GetDomain(unsigned long iPoint) const { + if (iPoint >= GetNumberVertices()) { + SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); + } - const auto nBound = geometry->GetnElem_Bound(iMarker); - vector> values(nBound); + return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint); +} + +vector CDriverBase::GetMarkerDomain(unsigned short iMarker) const { + vector values; + const auto nVertex = GetNumberMarkerVertices(iMarker); - for (auto iBound = 0ul; iBound < nBound; iBound++) { - unsigned short nNode = geometry->bound[iMarker][iBound]->GetnNodes(); - - for (auto iNode = 0u; iNode < nNode; iNode++) { - values[iBound].push_back(geometry->bound[iMarker][iBound]->GetNode(iNode)); - } + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { + values.push_back(GetMarkerDomain(iMarker, iVertex)); } return values; } -vector CDriverBase::GetDomain() const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; +bool CDriverBase::GetMarkerDomain(unsigned short iMarker, unsigned long iVertex) const { + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - const auto nPoint = geometry->GetnPoint(); - vector values; + return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint); +} + +vector CDriverBase::GetInitialCoordinates() const { + const auto nPoint = GetNumberVertices(); + vector values; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - values.push_back(geometry->nodes->GetDomain(iPoint)); + const auto value = GetInitialCoordinates(iPoint); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + values.push_back(value[iDim]); + } } return values; } -vector CDriverBase::GetDomainMarker(unsigned short iMarker) const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; +vector CDriverBase::GetInitialCoordinates(unsigned long iPoint) const { + if (iPoint >= GetNumberVertices()) { + SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); + } + + vector values; + + for (auto iDim = 0u; iDim < nDim; iDim++) { + const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetMesh_Coord(iPoint, iDim); + + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + values.push_back(0.0); // mesh solver is not defined ! + } + else { + values.push_back(SU2_TYPE::GetValue(value)); + } + } - const auto nVertex = geometry->GetnVertex(iMarker); - vector values; + return values; +} + +vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iMarker) const { + const auto nVertex = GetNumberMarkerVertices(iMarker); + vector values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + const auto value = GetMarkerInitialCoordinates(iVertex); - values.push_back(geometry->nodes->GetDomain(iPoint)); + for (auto iDim = 0u; iDim < nDim; iDim++) { + values.push_back(value[iDim]); + } } return values; } -vector CDriverBase::GetCoordinates() const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; +vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iMarker, unsigned long iVertex) const { + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + vector values; + + for (auto iDim = 0u; iDim < nDim; iDim++) { + const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetMesh_Coord(iPoint, iDim); + + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + values.push_back(0.0); // mesh solver is not defined ! + } + else { + values.push_back(SU2_TYPE::GetValue(value)); + } + } - const auto nPoint = geometry->GetnPoint(); - vector values(nPoint*nDim, 0.0); - su2double value; + return values; +} + +vector CDriverBase::GetCoordinates() const { + const auto nPoint = GetNumberVertices(); + vector values; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + const auto value = GetCoordinates(iPoint); + for (auto iDim = 0u; iDim < nDim; iDim++) { - value = geometry->nodes->GetCoord(iPoint, iDim); - values[iPoint*nDim + iDim] = SU2_TYPE::GetValue(value); + values.push_back(value[iDim]); } } return values; } -vector CDriverBase::GetCoordinatesMarker(unsigned short iMarker) const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; +vector CDriverBase::GetCoordinates(unsigned long iPoint) const { + const auto nPoint = GetNumberVertices(); + vector values; + + for (auto iDim = 0u; iDim < nDim; iDim++) { + const su2double value = geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetCoord(iPoint, iDim); + + values.push_back(SU2_TYPE::GetValue(value)); + } - const auto nVertex = geometry->GetnVertex(iMarker); - vector values(nVertex*nDim, 0.0); - su2double value; + return values; +} + +vector CDriverBase::GetMarkerCoordinates(unsigned short iMarker) const { + const auto nVertex = GetNumberMarkerVertices(iMarker); + vector values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + const auto value = GetMarkerCoordinates(iVertex); for (auto iDim = 0u; iDim < nDim; iDim++) { - value = geometry->nodes->GetCoord(iPoint, iDim); - values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(value); + values.push_back(value[iDim]); } } return values; } +vector CDriverBase::GetMarkerCoordinates(unsigned short iMarker, unsigned long iVertex) const { + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + vector values; + + for (auto iDim = 0u; iDim < nDim; iDim++) { + const su2double value = geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetCoord(iPoint, iDim); + + values.push_back(SU2_TYPE::GetValue(value)); + } + + return values; +} + void CDriverBase::SetCoordinates(vector values) { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + const auto nPoint = GetNumberVertices(); - const auto nPoint = geometry->GetnPoint(); if (values.size() != nPoint*nDim) { SU2_MPI::Error("Size does not match nPoint * nDim!", CURRENT_FUNCTION); } for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { for (auto iDim = 0u; iDim < nDim; iDim++) { - geometry->nodes->SetCoord(iPoint, iDim, values[iPoint*nDim + iDim]); + geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iPoint*nDim + iDim]); } } } -void CDriverBase::SetCoordinatesMarker(unsigned short iMarker, vector values) { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; +void CDriverBase::SetCoordinates(unsigned long iPoint, vector values) { + if (values.size() != nDim) { + SU2_MPI::Error("Size does not match nDim!", CURRENT_FUNCTION); + } - const auto nVertex = geometry->GetnVertex(iMarker); + for (auto iDim = 0u; iDim < nDim; iDim++) { + geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iDim]); + } +} + +void CDriverBase::SetMarkerCoordinates(unsigned short iMarker, vector values) { + const auto nVertex = GetNumberMarkerVertices(iMarker); + if (values.size() != nVertex*nDim) { SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); } for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); for (auto iDim = 0u; iDim < nDim; iDim++) { - geometry->nodes->SetCoord(iPoint, iDim, values[iVertex*nDim + iDim]); + geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iVertex*nDim + iDim]); } } } -vector CDriverBase::GetDisplacementsMarker(unsigned short iMarker) const { - CConfig* config = config_container[ZONE_0]; - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; - - if (!config->GetDeform_Mesh()) { - return {}; +void CDriverBase::SetMarkerCoordinates(unsigned short iMarker, unsigned long iVertex, vector values) { + if (values.size() != nDim) { + SU2_MPI::Error("Size does not match nDim!", CURRENT_FUNCTION); } - const auto nVertex = geometry->GetnVertex(iMarker); - vector values(nVertex*nDim, 0.0); - su2double value; + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iDim]); + } +} + +vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker) const { + const auto nVertex = GetNumberMarkerVertices(iMarker); + vector values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + const auto value = GetMarkerDisplacements(iMarker, iVertex); for (auto iDim = 0u; iDim < nDim; iDim++) { - value = solver->GetNodes()->GetBound_Disp(iPoint, iDim); - values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(value); + values.push_back(values[iDim]); } } return values; } -void CDriverBase::SetDisplacementsMarker(unsigned short iMarker, vector values) { - CConfig* config = config_container[ZONE_0]; - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; +vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker, unsigned long iVertex) const { + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + vector values; - if (!config->GetDeform_Mesh()) { - SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + for (auto iDim = 0u; iDim < nDim; iDim++) { + const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Disp(iPoint, iDim); + + values.push_back(SU2_TYPE::GetValue(value)); } - const auto nVertex = geometry->GetnVertex(iMarker); + return values; +} + +void CDriverBase::SetMarkerDisplacements(unsigned short iMarker, vector values) { + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + } + + const auto nVertex = GetNumberMarkerVertices(iMarker); + if (values.size() != nVertex*nDim) { SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); } for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); for (auto iDim = 0u; iDim < nDim; iDim++) { - solver->GetNodes()->SetBound_Disp(iPoint, iDim, values[iVertex*nDim + iDim]); + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint, iDim, values[iVertex*nDim + iDim]); } } } -vector CDriverBase::GetVelocitiesMarker(unsigned short iMarker) const { - CConfig* config = config_container[ZONE_0]; - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; - - if (!config->GetDeform_Mesh()) { - return {}; +void CDriverBase::SetMarkerDisplacements(unsigned short iMarker, unsigned long iVertex, vector values) { + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + } + if (values.size() != nDim) { + SU2_MPI::Error("Size does not match nDim!", CURRENT_FUNCTION); } - const auto nVertex = geometry->GetnVertex(iMarker); - vector values(nVertex*nDim, 0.0); - su2double value; + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint, iDim, values[iDim]); + } +} + +vector CDriverBase::GetMarkerVelocities(unsigned short iMarker) const { + const auto nVertex = GetNumberMarkerVertices(iMarker); + vector values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + const auto value = GetMarkerVelocities(iMarker, iVertex); for (auto iDim = 0u; iDim < nDim; iDim++) { - value = solver->GetNodes()->GetBound_Vel(iPoint, iDim); - values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(value); + values.push_back(values[iDim]); } } return values; } -void CDriverBase::SetVelocitiesMarker(unsigned short iMarker, vector values) { - CConfig* config = config_container[ZONE_0]; - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; +vector CDriverBase::GetMarkerVelocities(unsigned short iMarker, unsigned long iVertex) const { + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + vector values; - if (!config->GetDeform_Mesh()) { - SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + for (auto iDim = 0u; iDim < nDim; iDim++) { + const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Vel(iPoint, iDim); + + values.push_back(SU2_TYPE::GetValue(value)); } - const auto nVertex = geometry->GetnVertex(iMarker); + return values; +} + +void CDriverBase::SetMarkerVelocities(unsigned short iMarker, vector values) { + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + } + + const auto nVertex = GetNumberMarkerVertices(iMarker); + if (values.size() != nVertex*nDim) { SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); } for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); for (auto iDim = 0u; iDim < nDim; iDim++) { - solver->GetNodes()->SetBound_Vel(iPoint, iDim, values[iVertex*nDim + iDim]); + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint, iDim, values[iVertex*nDim + iDim]); } } } -vector CDriverBase::GetInitialCoordinatesMarker(unsigned short iMarker) const { - CConfig* config = config_container[ZONE_0]; - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; - - if (!config->GetDeform_Mesh()) { - return {}; +void CDriverBase::SetMarkerVelocities(unsigned short iMarker, unsigned long iVertex, vector values) { + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + } + if (values.size() != nDim) { + SU2_MPI::Error("Size does not match nDim!", CURRENT_FUNCTION); } - const auto nVertex = geometry->GetnVertex(iMarker); - vector values(nVertex*nDim, 0.0); - su2double value; + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + + for (auto iDim = 0u; iDim < nDim; iDim++) { + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint, iDim, values[iDim]); + } +} + +vector CDriverBase::GetMarkerVertexNormals(unsigned short iMarker, bool normalize) const { + const auto nVertex = GetNumberMarkerVertices(iMarker); + vector values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + const auto value = GetMarkerVertexNormals(iMarker, normalize=normalize); for (auto iDim = 0u; iDim < nDim; iDim++) { - value = solver->GetNodes()->GetMesh_Coord(iPoint, iDim); - values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(value); + values.push_back(value[iDim]); } } return values; } -vector CDriverBase::GetVertexNormalsMarker(unsigned short iMarker, bool UnitNormal) const { - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - - const auto nVertex = geometry->GetnVertex(iMarker); - vector values(nVertex*nDim, 0.0); +vector CDriverBase::GetMarkerVertexNormals(unsigned short iMarker, unsigned long iVertex, bool normalize) const { + if (iVertex >= GetNumberMarkerVertices(iMarker)) { + SU2_MPI::Error("Marker vertex index exceeds size.", CURRENT_FUNCTION); + } + + vector values; + + auto normal = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNormal(); + auto area = GeometryToolbox::Norm(nDim, normal); - for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); - auto Area = GeometryToolbox::Norm(nDim, Normal); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - if (!UnitNormal) { - values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(Normal[iDim]); - } else { - values[iVertex*nDim + iDim] = SU2_TYPE::GetValue(Normal[iDim]/Area); - } + for (auto iDim = 0u; iDim < nDim; iDim++) { + if (normalize) { + values[iDim] = SU2_TYPE::GetValue(normal[iDim]/area); + } else { + values[iDim] = SU2_TYPE::GetValue(normal[iDim]); } } - + return values; } + void CDriverBase::CommunicateMeshDisplacements(void) { - CConfig* config = config_container[ZONE_0]; - CGeometry* geometry = geometry_container[ZONE_0][INST_0][MESH_0]; - CSolver* solver = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]; - - solver->InitiateComms(geometry, config, MESH_DISPLACEMENTS); - solver->CompleteComms(geometry, config, MESH_DISPLACEMENTS); + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->InitiateComms(geometry_container[ZONE_0][INST_0][MESH_0], config_container[ZONE_0], MESH_DISPLACEMENTS); + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->CompleteComms(geometry_container[ZONE_0][INST_0][MESH_0], config_container[ZONE_0], MESH_DISPLACEMENTS); } diff --git a/SU2_CFD/include/drivers/CDriver.hpp b/SU2_CFD/include/drivers/CDriver.hpp index 32843db8c50..d15a510cae4 100644 --- a/SU2_CFD/include/drivers/CDriver.hpp +++ b/SU2_CFD/include/drivers/CDriver.hpp @@ -490,22 +490,16 @@ class CDriver : public CDriverBase { void Inlet_Preprocessing(CSolver ***solver, CGeometry **geometry, CConfig *config) const; /*! - * \brief Get all the boundary markers tags. - * \return List of boundary markers tags. + * \brief Get all the CHT boundary marker tags. + * \return List of CHT boundary markers tags. */ - vector GetAllBoundaryMarkersTag() const; + vector GetCHTMarkerTags() const; /*! - * \brief Get all the heat transfer boundary markers tags. - * \return List of heat transfer boundary markers tags. - */ - vector GetAllCHTMarkersTag() const; - - /*! - * \brief Get all the (subsonic) inlet boundary markers tags. + * \brief Get all the inlet boundary marker tags. * \return List of inlet boundary markers tags. */ - vector GetAllInletMarkersTag() const; + vector GetInletMarkerTags() const; /*! * \brief Return the sensitivities of the mesh boundary vertices. diff --git a/SU2_CFD/src/python_wrapper_structure.cpp b/SU2_CFD/src/python_wrapper_structure.cpp index ba6a563c5b0..2f7e35a1247 100644 --- a/SU2_CFD/src/python_wrapper_structure.cpp +++ b/SU2_CFD/src/python_wrapper_structure.cpp @@ -320,60 +320,36 @@ passivedouble CDriver::GetThermalConductivity(unsigned short iMarker, unsigned l /* Functions related to the management of markers */ //////////////////////////////////////////////////////////////////////////////// -vector CDriver::GetAllBoundaryMarkersTag() const { - - vector boundariesTagList; - unsigned short iMarker,nBoundariesMarkers; - string Marker_Tag; - - nBoundariesMarkers = config_container[ZONE_0]->GetnMarker_All(); - boundariesTagList.resize(nBoundariesMarkers); - - for(iMarker=0; iMarker < nBoundariesMarkers; iMarker++){ - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - boundariesTagList[iMarker] = Marker_Tag; - } - - return boundariesTagList; -} - -vector CDriver::GetAllCHTMarkersTag() const { - - vector CHTBoundariesTagList; - unsigned short iMarker, nBoundariesMarker; - string Marker_Tag; - - nBoundariesMarker = config_container[ZONE_0]->GetnMarker_All(); +vector CDriver::GetCHTMarkerTags() const { + vector tags; + const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); //The CHT markers can be identified as the markers that are customizable with a BC type HEAT_FLUX or ISOTHERMAL. - for(iMarker=0; iMarkerGetMarker_All_KindBC(iMarker) == HEAT_FLUX || config_container[ZONE_0]->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) && config_container[ZONE_0]->GetMarker_All_PyCustom(iMarker)){ - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - CHTBoundariesTagList.push_back(Marker_Tag); + for (auto iMarker = 0u; iMarker < nMarker; iMarker++) { + if ((config_container[ZONE_0]->GetMarker_All_KindBC(iMarker) == HEAT_FLUX || + config_container[ZONE_0]->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) && config_container[ZONE_0]->GetMarker_All_PyCustom(iMarker)){ + + tags.push_back(config_container[ZONE_0]->GetMarker_All_TagBound(iMarker)); } } - return CHTBoundariesTagList; + return tags; } -vector CDriver::GetAllInletMarkersTag() const { +vector CDriver::GetInletMarkerTags() const { + vector tags; + const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); - vector BoundariesTagList; - unsigned short iMarker, nBoundariesMarker; - string Marker_Tag; - - nBoundariesMarker = config_container[ZONE_0]->GetnMarker_All(); - - for(iMarker=0; iMarkerGetMarker_All_PyCustom(iMarker); bool isInlet = (config_container[ZONE_0]->GetMarker_All_KindBC(iMarker) == INLET_FLOW); - if(isCustomizable && isInlet) { - Marker_Tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - BoundariesTagList.push_back(Marker_Tag); + + if (isCustomizable && isInlet) { + tags.push_back(config_container[ZONE_0]->GetMarker_All_TagBound(iMarker)); } } - return BoundariesTagList; + return tags; } void CDriver::SetHeatSource_Position(passivedouble alpha, passivedouble pos_x, passivedouble pos_y, passivedouble pos_z){ diff --git a/TestCases/py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py b/TestCases/py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py index 89006b9a53a..a962558d0d6 100755 --- a/TestCases/py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py +++ b/TestCases/py_wrapper/disc_adj_fea/flow_load_sens/run_adjoint.py @@ -68,10 +68,10 @@ def main(): MarkerName = 'RightBeamS' # Specified by the user # Get all the boundary tags - MarkerList = SU2Driver.GetAllBoundaryMarkersTag() + MarkerList = SU2Driver.GetMarkerTags() # Get all the markers defined on this rank and their associated indices. - allMarkerIDs = SU2Driver.GetBoundaryMarkerIndices() + allMarkerIDs = SU2Driver.GetMarkerIndices() #Check if the specified marker exists and if it belongs to this rank. if MarkerName in MarkerList and MarkerName in allMarkerIDs.keys(): diff --git a/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py b/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py index 2229ad8ce5c..d174d13da12 100755 --- a/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py +++ b/TestCases/py_wrapper/disc_adj_flow/mesh_disp_sens/run_adjoint.py @@ -67,12 +67,12 @@ def main(): MarkerName = 'wallF' # Specified by the user # Get all the boundary tags - MarkerList = SU2Driver.GetAllBoundaryMarkersTag() + MarkerList = SU2Driver.GetMarkerTags() # Get all the markers defined on this rank and their associated indices. - allMarkerIDs = SU2Driver.GetBoundaryMarkerIndices() + allMarkerIDs = SU2Driver.GetMarkerIndices() - #Check if the specified marker exists and if it belongs to this rank. + # Check if the specified marker exists and if it belongs to this rank. if MarkerName in MarkerList and MarkerName in allMarkerIDs.keys(): MarkerID = allMarkerIDs[MarkerName] @@ -80,7 +80,7 @@ def main(): nVertex_Marker = 0 #total number of vertices (physical + halo) if MarkerID != None: - nVertex_Marker = SU2Driver.GetNumberVerticesMarker(MarkerID) + nVertex_Marker = SU2Driver.GetNumberMarkerVertices(MarkerID) # Time loop is defined in Python so that we have acces to SU2 functionalities at each time step if rank == 0: diff --git a/TestCases/py_wrapper/flatPlate_rigidMotion/launch_flatPlate_rigidMotion.py b/TestCases/py_wrapper/flatPlate_rigidMotion/launch_flatPlate_rigidMotion.py index ea7983e2156..691f5b134c5 100755 --- a/TestCases/py_wrapper/flatPlate_rigidMotion/launch_flatPlate_rigidMotion.py +++ b/TestCases/py_wrapper/flatPlate_rigidMotion/launch_flatPlate_rigidMotion.py @@ -76,10 +76,10 @@ def main(): MovingMarker = 'plate' #specified by the user # Get all the tags with the moving option - MovingMarkerList = SU2Driver.GetAllDeformMeshMarkersTag() + MovingMarkerList = SU2Driver.GetMarkerTags() # Get all the markers defined on this rank and their associated indices. - allMarkerIDs = SU2Driver.GetAllBoundaryMarkers() + allMarkerIDs = SU2Driver.GetMarkerIndices() # Check if the specified marker has a moving option and if it exists on this rank. if MovingMarker in MovingMarkerList and MovingMarker in allMarkerIDs.keys(): @@ -91,8 +91,8 @@ def main(): nVertex_MovingMarker_PHYS = 0 #number of physical vertices if MovingMarkerID != None: - nVertex_MovingMarker = SU2Driver.GetNumberVertices(MovingMarkerID) - nVertex_MovingMarker_HALO = SU2Driver.GetNumberHaloVertices(MovingMarkerID) + nVertex_MovingMarker = SU2Driver.GetNumberMarkerVertices(MovingMarkerID) + nVertex_MovingMarker_HALO = SU2Driver.GetNumberMarkerHaloVertices(MovingMarkerID) nVertex_MovingMarker_PHYS = nVertex_MovingMarker - nVertex_MovingMarker_HALO # Retrieve some control parameters from the driver @@ -104,9 +104,8 @@ def main(): # Extract the initial position of each node on the moving marker CoordX = np.zeros(nVertex_MovingMarker) CoordY = np.zeros(nVertex_MovingMarker) - CoordZ = np.zeros(nVertex_MovingMarker) for iVertex in range(nVertex_MovingMarker): - CoordX[iVertex], CoordY[iVertex], CoordZ[iVertex] = SU2Driver.GetInitialMeshCoord(MovingMarkerID, iVertex) + CoordX[iVertex], CoordY[iVertex] = SU2Driver.GetMarkerInitialCoordinates(MovingMarkerID, iVertex) # Time loop is defined in Python so that we have acces to SU2 functionalities at each time step if rank == 0: @@ -117,9 +116,11 @@ def main(): while (TimeIter < nTimeIter): # Define the rigid body displacement and set the new coords of each node on the marker - d_y = 0.0175*sin(2*pi*time) + value = 0.0, 0.0175*sin(2*pi*time) + for iVertex in range(nVertex_MovingMarker): - SU2Driver.SetMeshDisplacement(MovingMarkerID, int(iVertex), 0.0, d_y, 0.0) + SU2Driver.SetMarkerDisplacements(MovingMarkerID, int(iVertex), value) + # Time iteration preprocessing SU2Driver.Preprocess(TimeIter) # Run one time iteration (e.g. dual-time) diff --git a/TestCases/py_wrapper/flatPlate_unsteady_CHT/launch_unsteady_CHT_FlatPlate.py b/TestCases/py_wrapper/flatPlate_unsteady_CHT/launch_unsteady_CHT_FlatPlate.py index dfde1d6b2c8..d63bb335442 100755 --- a/TestCases/py_wrapper/flatPlate_unsteady_CHT/launch_unsteady_CHT_FlatPlate.py +++ b/TestCases/py_wrapper/flatPlate_unsteady_CHT/launch_unsteady_CHT_FlatPlate.py @@ -75,23 +75,23 @@ def main(): CHTMarker = 'plate' # Specified by the user # Get all the tags with the CHT option - CHTMarkerList = SU2Driver.GetAllCHTMarkersTag() + CHTMarkerList = SU2Driver.GetCHTMarkerTags() # Get all the markers defined on this rank and their associated indices. - allMarkerIDs = SU2Driver.GetAllBoundaryMarkers() + allMarkerIDs = SU2Driver.GetMarkerIndices() #Check if the specified marker has a CHT option and if it exists on this rank. if CHTMarker in CHTMarkerList and CHTMarker in allMarkerIDs.keys(): CHTMarkerID = allMarkerIDs[CHTMarker] # Number of vertices on the specified marker (per rank) - nVertex_CHTMarker = 0 #total number of vertices (physical + halo) - nVertex_CHTMarker_HALO = 0 #number of halo vertices - nVertex_CHTMarker_PHYS = 0 #number of physical vertices + nVertex_CHTMarker = 0 # total number of vertices (physical + halo) + nVertex_CHTMarker_HALO = 0 # number of halo vertices + nVertex_CHTMarker_PHYS = 0 # number of physical vertices if CHTMarkerID != None: - nVertex_CHTMarker = SU2Driver.GetNumberVertices(CHTMarkerID) - nVertex_CHTMarker_HALO = SU2Driver.GetNumberHaloVertices(CHTMarkerID) + nVertex_CHTMarker = SU2Driver.GetNumberMarkerVertices(CHTMarkerID) + nVertex_CHTMarker_HALO = SU2Driver.GetNumberMarkerHaloVertices(CHTMarkerID) nVertex_CHTMarker_PHYS = nVertex_CHTMarker - nVertex_CHTMarker_HALO # Retrieve some control parameters from the driver @@ -115,6 +115,7 @@ def main(): # Set this temperature to all the vertices on the specified CHT marker for iVertex in range(nVertex_CHTMarker): SU2Driver.SetVertexTemperature(CHTMarkerID, iVertex, WallTemp) + # Tell the SU2 drive to update the boundary conditions SU2Driver.BoundaryConditionsUpdate() # Run one time iteration (e.g. dual-time) From fad776d390fea1ef7f6e3f28ca7c9c3eeb462885 Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 7 Mar 2022 21:20:05 +0100 Subject: [PATCH 023/598] Adapt Python API to get/set from multi-dimensional arrays --- Common/include/drivers/CDriverBase.hpp | 48 +++--- Common/src/drivers/CDriverBase.cpp | 229 +++++++++++++------------ SU2_PY/pySU2/pySU2.i | 4 +- SU2_PY/pySU2/pySU2ad.i | 4 +- 4 files changed, 144 insertions(+), 141 deletions(-) diff --git a/Common/include/drivers/CDriverBase.hpp b/Common/include/drivers/CDriverBase.hpp index 6b9590fdd22..68aa0bd5956 100644 --- a/Common/include/drivers/CDriverBase.hpp +++ b/Common/include/drivers/CDriverBase.hpp @@ -121,7 +121,7 @@ class CDriverBase { * \brief Get all the boundary markers tags with their associated indices. * \return List of boundary markers tags with their indices. */ - map GetMarkerIndices() const; + map GetMarkerIndices() const; /*! * \brief Get all the boundary markers tags with their associated types. @@ -371,9 +371,9 @@ class CDriverBase { /*! * \brief Get the initial (un-deformed) coordinates of the mesh vertices. - * \return Initial vertex coordinates (nPoint*nDim). + * \return Initial vertex coordinates (nPoint, nDim). */ - vector GetInitialCoordinates() const; + vector> GetInitialCoordinates() const; /*! * \brief Get the initial (un-deformed) coordinates of a mesh vertex. @@ -385,9 +385,9 @@ class CDriverBase { /*! * \brief Get the initial (un-deformed) coordinates of the marker vertices. * \param[in] iMarker - Marker index. - * \return Initial vertex coordinates (nVertex*nDim). + * \return Initial vertex coordinates (nVertex, nDim). */ - vector GetMarkerInitialCoordinates(unsigned short iMarker) const; + vector> GetMarkerInitialCoordinates(unsigned short iMarker) const; /*! * \brief Get the initial (un-deformed) coordinates of a marker vertex. @@ -399,9 +399,9 @@ class CDriverBase { /*! * \brief Get the coordinates of the mesh vertices. - * \return Vertex coordinates (nPoint*nDim). + * \return Vertex coordinates (nPoint, nDim). */ - vector GetCoordinates() const; + vector> GetCoordinates() const; /*! * \brief Get the coordinates of a mesh vertex. @@ -413,9 +413,9 @@ class CDriverBase { /*! * \brief Get the coordinates of the marker vertices. * \param[in] iMarker - Marker index. - * \return Vertex coordinates (nVertex*nDim). + * \return Vertex coordinates (nVertex, nDim). */ - vector GetMarkerCoordinates(unsigned short iMarker) const; + vector> GetMarkerCoordinates(unsigned short iMarker) const; /*! * \brief Get the coordinates of a marker vertex. @@ -427,9 +427,9 @@ class CDriverBase { /*! * \brief Set the coordinates of the mesh vertices. - * \param[in] values - Vertex coordinates (nPoint*nDim). + * \param[in] values - Vertex coordinates (nPoint, nDim). */ - void SetCoordinates(vector values); + void SetCoordinates(vector> values); /*! * \brief Set the coordinates of a mesh vertex. @@ -441,9 +441,9 @@ class CDriverBase { /*! * \brief Set the coordinates of the marker vertices. * \param[in] iMarker - Marker index. - * \param[in] values - Vertex coordinates (nVertex*nDim). + * \param[in] values - Vertex coordinates (nVertex, nDim). */ - void SetMarkerCoordinates(unsigned short iMarker, vector values); + void SetMarkerCoordinates(unsigned short iMarker, vector> values); /*! * \brief Set the coordinates of a marker vertex. @@ -456,9 +456,9 @@ class CDriverBase { /*! * \brief Get the displacements of the marker vertices. * \param[in] iMarker - Marker index. - * \return Vertex displacements (nVertex*nDim). + * \return Vertex displacements (nVertex, nDim). */ - vector GetMarkerDisplacements(unsigned short iMarker) const; + vector> GetMarkerDisplacements(unsigned short iMarker) const; /*! * \brief Get the displacements of a marker vertex. @@ -471,9 +471,9 @@ class CDriverBase { /*! * \brief Set the displacements of the marker vertices. * \param[in] iMarker - Marker index. - * \param[in] values - Vertex displacements (nVertex*nDim). + * \param[in] values - Vertex displacements (nVertex, nDim). */ - void SetMarkerDisplacements(unsigned short iMarker, vector values); + void SetMarkerDisplacements(unsigned short iMarker, vector> values); /*! * \brief Set the displacements of a marker vertex. @@ -486,24 +486,24 @@ class CDriverBase { /*! * \brief Get the velocities of the marker vertices. * \param[in] iMarker - Marker index. - * \return Vertex velocities (nVertex*nDim). + * \return Vertex velocities (nVertex, nDim). */ - vector GetMarkerVelocities(unsigned short iMarker) const; + vector> GetMarkerVelocities(unsigned short iMarker) const; /*! * \brief Get the velocities of a marker vertex. * \param[in] iMarker - Marker index. * \param[in] iVertex - Marker vertex index. - * \return Vertex velocities (nVertex*nDim). + * \return Vertex velocities (nDim). */ vector GetMarkerVelocities(unsigned short iMarker, unsigned long iVertex) const; /*! * \brief Set the velocities of the marker vertices. * \param[in] iMarker - Marker index. - * \param[in] values - Vertex velocities (nVertex*nDim). + * \param[in] values - Vertex velocities (nVertex, nDim). */ - void SetMarkerVelocities(unsigned short iMarker, vector values); + void SetMarkerVelocities(unsigned short iMarker, vector> values); /*! * \brief Set the velocities of a marker vertex. @@ -517,9 +517,9 @@ class CDriverBase { * \brief Get the normal vectors at the marker vertices. * \param[in] iMarker - Marker index. * \param[in] normalize - If true, the unit (i.e. normalized) normal vector is returned. - * \return Normal vector at the vertex (nVertex*nDim). + * \return Normal vector at the vertex (nVertex, nDim). */ - vector GetMarkerVertexNormals(unsigned short iMarker, bool normalize = false) const; + vector> GetMarkerVertexNormals(unsigned short iMarker, bool normalize = false) const; /*! * \brief Get the normal vectors at a marker vertex. diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index 9a3ee6ba686..8f2f74d0a99 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -86,9 +86,9 @@ unsigned short CDriverBase::GetNumberMarkers() const { return config_container[ZONE_0]->GetnMarker_All(); } -map CDriverBase::GetMarkerIndices() const { +map CDriverBase::GetMarkerIndices() const { const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); - map indexMap; + map indexMap; for (auto iMarker = 0u; iMarker < nMarker; iMarker++) { auto tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); @@ -154,7 +154,7 @@ vector CDriverBase::GetMarkerTags() const { vector CDriverBase::GetDeformableMarkerTags() const { vector tags; - const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); + const auto nMarker = config_container[ZONE_0]->GetnMarker_Deform_Mesh(); for (auto iMarker = 0u; iMarker < nMarker; iMarker++) { tags.push_back(config_container[ZONE_0]->GetMarker_Deform_Mesh_TagBound(iMarker)); @@ -180,9 +180,10 @@ unsigned long CDriverBase::GetNumberMarkerElements(unsigned short iMarker) const } vector CDriverBase::GetElementIDs() const { - vector values; const auto nElem = GetNumberElements(); + vector values; + for (auto iElem = 0ul; iElem < nElem; iElem++) { values.push_back(GetElementIDs(iElem)); } @@ -199,9 +200,10 @@ unsigned long CDriverBase::GetElementIDs(unsigned long iElem) const { } vector CDriverBase::GetMarkerElementIDs(unsigned short iMarker) const { - vector values; const auto nBound = GetNumberMarkerElements(iMarker); + vector values; + for (auto iBound = 0ul; iBound < nBound; iBound++) { values.push_back(GetMarkerElementIDs(iMarker, iBound)); } @@ -218,9 +220,10 @@ unsigned long CDriverBase::GetMarkerElementIDs(unsigned short iMarker, unsigned } vector CDriverBase::GetElementColors() const { - vector values; const auto nElem = GetNumberElements(); + vector values; + for (auto iElem = 0ul; iElem < nElem; iElem++) { values.push_back(GetElementColors(iElem)); } @@ -237,9 +240,10 @@ unsigned long CDriverBase::GetElementColors(unsigned long iElem) const { } vector CDriverBase::GetMarkerElementColors(unsigned short iMarker) const { - vector values; const auto nBound = GetNumberMarkerElements(iMarker); + vector values; + for (auto iBound = 0ul; iBound < nBound; iBound++) { values.push_back(GetMarkerElementColors(iMarker, iBound)); } @@ -256,9 +260,10 @@ unsigned long CDriverBase::GetMarkerElementColors(unsigned short iMarker, unsign } vector> CDriverBase::GetElementConnectivities() const { - vector> values; const auto nElem = GetNumberElements(); + vector> values; + for (auto iElem = 0ul; iElem < nElem; iElem++) { values.push_back(GetElementConnectivities(iElem)); } @@ -271,9 +276,10 @@ vector CDriverBase::GetElementConnectivities(unsigned long iElem) SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); } - vector values; unsigned short nNode = geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetnNodes(); + vector values; + for (auto iNode = 0u; iNode < nNode; iNode++) { values.push_back(geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetNode(iNode)); } @@ -282,9 +288,10 @@ vector CDriverBase::GetElementConnectivities(unsigned long iElem) } vector> CDriverBase::GetMarkerElementConnectivities(unsigned short iMarker) const { - vector> values; const auto nBound = GetNumberMarkerElements(iMarker); + vector> values; + for (auto iBound = 0ul; iBound < nBound; iBound++) { values.push_back(GetMarkerElementConnectivities(iMarker, iBound)); } @@ -297,9 +304,10 @@ vector CDriverBase::GetMarkerElementConnectivities(unsigned short SU2_MPI::Error("Marker element index exceeds size.", CURRENT_FUNCTION); } - vector values; unsigned short nNode = geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetnNodes(); + vector values; + for (auto iNode = 0u; iNode < nNode; iNode++) { values.push_back(geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetNode(iNode)); } @@ -348,9 +356,10 @@ unsigned long CDriverBase::GetNumberMarkerHaloVertices(unsigned short iMarker) c } vector CDriverBase::GetMarkerVertexIndex(unsigned short iMarker) const { - vector values; const auto nVertex = GetNumberMarkerVertices(iMarker); + vector values; + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { values.push_back(GetMarkerVertexIndex(iMarker, iVertex)); } @@ -367,9 +376,10 @@ unsigned long CDriverBase::GetMarkerVertexIndex(unsigned short iMarker, unsigned } vector CDriverBase::GetVertexIDs() const { - vector values; const auto nPoint = GetNumberVertices(); + vector values; + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { values.push_back(GetVertexIDs(iPoint)); } @@ -386,9 +396,10 @@ unsigned long CDriverBase::GetVertexIDs(unsigned long iPoint) const { } vector CDriverBase::GetMarkerVertexIDs(unsigned short iMarker) const { - vector values; const auto nVertex = GetNumberMarkerVertices(iMarker); + vector values; + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { values.push_back(GetMarkerVertexIDs(iMarker, iVertex)); } @@ -403,9 +414,10 @@ unsigned long CDriverBase::GetMarkerVertexIDs(unsigned short iMarker, unsigned l } vector CDriverBase::GetVertexColors() const { - vector values; const auto nPoint = GetNumberVertices(); + vector values; + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { values.push_back(GetVertexColors(iPoint)); } @@ -422,9 +434,10 @@ unsigned long CDriverBase::GetVertexColors(unsigned long iPoint) const { } vector CDriverBase::GetMarkerVertexColors(unsigned short iMarker) const { - vector values; const auto nVertex = GetNumberMarkerVertices(iMarker); + vector values; + for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { values.push_back(GetMarkerVertexColors(iMarker, iVertex)); } @@ -439,8 +452,9 @@ unsigned long CDriverBase::GetMarkerVertexColors(unsigned short iMarker, unsigne } vector CDriverBase::GetDomain() const { - vector values; const auto nPoint = GetNumberVertices(); + + vector values; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { values.push_back(GetDomain(iPoint)); @@ -458,8 +472,9 @@ bool CDriverBase::GetDomain(unsigned long iPoint) const { } vector CDriverBase::GetMarkerDomain(unsigned short iMarker) const { - vector values; const auto nVertex = GetNumberMarkerVertices(iMarker); + + vector values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { values.push_back(GetMarkerDomain(iMarker, iVertex)); @@ -474,16 +489,13 @@ bool CDriverBase::GetMarkerDomain(unsigned short iMarker, unsigned long iVertex) return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint); } -vector CDriverBase::GetInitialCoordinates() const { +vector> CDriverBase::GetInitialCoordinates() const { const auto nPoint = GetNumberVertices(); - vector values; + + vector> values; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - const auto value = GetInitialCoordinates(iPoint); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - values.push_back(value[iDim]); - } + values.push_back(GetInitialCoordinates(iPoint)); } return values; @@ -510,9 +522,10 @@ vector CDriverBase::GetInitialCoordinates(unsigned long iPoint) c return values; } -vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iMarker) const { +vector> CDriverBase::GetMarkerInitialCoordinates(unsigned short iMarker) const { const auto nVertex = GetNumberMarkerVertices(iMarker); - vector values; + + vector> values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { const auto value = GetMarkerInitialCoordinates(iVertex); @@ -527,6 +540,7 @@ vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iM vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + vector values; for (auto iDim = 0u; iDim < nDim; iDim++) { @@ -543,23 +557,23 @@ vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iM return values; } -vector CDriverBase::GetCoordinates() const { +vector> CDriverBase::GetCoordinates() const { const auto nPoint = GetNumberVertices(); - vector values; + + vector> values; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - const auto value = GetCoordinates(iPoint); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - values.push_back(value[iDim]); - } + values.push_back(GetCoordinates(iPoint)); } return values; } vector CDriverBase::GetCoordinates(unsigned long iPoint) const { - const auto nPoint = GetNumberVertices(); + if (iPoint >= GetNumberVertices()) { + SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); + } + vector values; for (auto iDim = 0u; iDim < nDim; iDim++) { @@ -571,16 +585,13 @@ vector CDriverBase::GetCoordinates(unsigned long iPoint) const { return values; } -vector CDriverBase::GetMarkerCoordinates(unsigned short iMarker) const { +vector> CDriverBase::GetMarkerCoordinates(unsigned short iMarker) const { const auto nVertex = GetNumberMarkerVertices(iMarker); - vector values; + + vector> values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - const auto value = GetMarkerCoordinates(iVertex); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - values.push_back(value[iDim]); - } + values.push_back(GetMarkerCoordinates(iMarker, iVertex)); } return values; @@ -588,6 +599,7 @@ vector CDriverBase::GetMarkerCoordinates(unsigned short iMarker) vector CDriverBase::GetMarkerCoordinates(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + vector values; for (auto iDim = 0u; iDim < nDim; iDim++) { @@ -599,23 +611,25 @@ vector CDriverBase::GetMarkerCoordinates(unsigned short iMarker, return values; } -void CDriverBase::SetCoordinates(vector values) { +void CDriverBase::SetCoordinates(vector> values) { const auto nPoint = GetNumberVertices(); - if (values.size() != nPoint*nDim) { - SU2_MPI::Error("Size does not match nPoint * nDim!", CURRENT_FUNCTION); + if (values.size() != nPoint) { + SU2_MPI::Error("Invalid number of vertices !", CURRENT_FUNCTION); } for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - for (auto iDim = 0u; iDim < nDim; iDim++) { - geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iPoint*nDim + iDim]); - } + SetCoordinates(iPoint, values[iPoint]); } } void CDriverBase::SetCoordinates(unsigned long iPoint, vector values) { + if (iPoint >= GetNumberVertices()) { + SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); + } + if (values.size() != nDim) { - SU2_MPI::Error("Size does not match nDim!", CURRENT_FUNCTION); + SU2_MPI::Error("Invalid number of dimensions !", CURRENT_FUNCTION); } for (auto iDim = 0u; iDim < nDim; iDim++) { @@ -623,44 +637,37 @@ void CDriverBase::SetCoordinates(unsigned long iPoint, vector val } } -void CDriverBase::SetMarkerCoordinates(unsigned short iMarker, vector values) { +void CDriverBase::SetMarkerCoordinates(unsigned short iMarker, vector> values) { const auto nVertex = GetNumberMarkerVertices(iMarker); - if (values.size() != nVertex*nDim) { - SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); + if (values.size() != nVertex) { + SU2_MPI::Error("Invalid number of marker vertices !", CURRENT_FUNCTION); } for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iVertex*nDim + iDim]); - } + SetMarkerCoordinates(iMarker, iVertex, values[iVertex]); } } void CDriverBase::SetMarkerCoordinates(unsigned short iMarker, unsigned long iVertex, vector values) { + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + if (values.size() != nDim) { - SU2_MPI::Error("Size does not match nDim!", CURRENT_FUNCTION); + SU2_MPI::Error("Invalid number of dimensions !", CURRENT_FUNCTION); } - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - for (auto iDim = 0u; iDim < nDim; iDim++) { geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iDim]); } } -vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker) const { +vector> CDriverBase::GetMarkerDisplacements(unsigned short iMarker) const { const auto nVertex = GetNumberMarkerVertices(iMarker); - vector values; + + vector> values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - const auto value = GetMarkerDisplacements(iMarker, iVertex); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - values.push_back(values[iDim]); - } + values.push_back(GetMarkerDisplacements(iMarker, iVertex)); } return values; @@ -668,62 +675,60 @@ vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + vector values; for (auto iDim = 0u; iDim < nDim; iDim++) { - const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Disp(iPoint, iDim); - - values.push_back(SU2_TYPE::GetValue(value)); + if (config_container[ZONE_0]->GetDeform_Mesh()) { + values.push_back(SU2_TYPE::GetValue(solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Disp(iPoint, iDim))); + } + else { + values.push_back(0.0); + } } return values; } -void CDriverBase::SetMarkerDisplacements(unsigned short iMarker, vector values) { +void CDriverBase::SetMarkerDisplacements(unsigned short iMarker, vector> values) { if (!config_container[ZONE_0]->GetDeform_Mesh()) { - SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } const auto nVertex = GetNumberMarkerVertices(iMarker); - if (values.size() != nVertex*nDim) { - SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); + if (values.size() != nVertex) { + SU2_MPI::Error("Invalid number of marker vertices !", CURRENT_FUNCTION); } for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint, iDim, values[iVertex*nDim + iDim]); - } + SetMarkerDisplacements(iMarker, iVertex, values[iVertex]); } } void CDriverBase::SetMarkerDisplacements(unsigned short iMarker, unsigned long iVertex, vector values) { if (!config_container[ZONE_0]->GetDeform_Mesh()) { - SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } + + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + if (values.size() != nDim) { - SU2_MPI::Error("Size does not match nDim!", CURRENT_FUNCTION); + SU2_MPI::Error("Invalid number of dimensions !", CURRENT_FUNCTION); } - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - for (auto iDim = 0u; iDim < nDim; iDim++) { solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint, iDim, values[iDim]); } } -vector CDriverBase::GetMarkerVelocities(unsigned short iMarker) const { +vector> CDriverBase::GetMarkerVelocities(unsigned short iMarker) const { const auto nVertex = GetNumberMarkerVertices(iMarker); - vector values; + + vector> values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - const auto value = GetMarkerVelocities(iMarker, iVertex); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - values.push_back(values[iDim]); - } + values.push_back(GetMarkerVelocities(iMarker, iVertex)); } return values; @@ -731,62 +736,60 @@ vector CDriverBase::GetMarkerVelocities(unsigned short iMarker) c vector CDriverBase::GetMarkerVelocities(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + vector values; for (auto iDim = 0u; iDim < nDim; iDim++) { - const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Vel(iPoint, iDim); - - values.push_back(SU2_TYPE::GetValue(value)); + if (config_container[ZONE_0]->GetDeform_Mesh()) { + values.push_back(SU2_TYPE::GetValue(solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Vel(iPoint, iDim))); + } + else { + values.push_back(0.0); + } } return values; } -void CDriverBase::SetMarkerVelocities(unsigned short iMarker, vector values) { +void CDriverBase::SetMarkerVelocities(unsigned short iMarker, vector> values) { if (!config_container[ZONE_0]->GetDeform_Mesh()) { - SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } const auto nVertex = GetNumberMarkerVertices(iMarker); - if (values.size() != nVertex*nDim) { - SU2_MPI::Error("Size does not match nVertex * nDim!", CURRENT_FUNCTION); + if (values.size() != nVertex) { + SU2_MPI::Error("Invalid number of marker vertices !", CURRENT_FUNCTION); } for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint, iDim, values[iVertex*nDim + iDim]); - } + SetMarkerVelocities(iMarker, iVertex, values[iVertex]); } } void CDriverBase::SetMarkerVelocities(unsigned short iMarker, unsigned long iVertex, vector values) { if (!config_container[ZONE_0]->GetDeform_Mesh()) { - SU2_MPI::Error("Mesh solver is not defined!", CURRENT_FUNCTION); + SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } + + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + if (values.size() != nDim) { - SU2_MPI::Error("Size does not match nDim!", CURRENT_FUNCTION); + SU2_MPI::Error("Invalid number of dimensions !", CURRENT_FUNCTION); } - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - for (auto iDim = 0u; iDim < nDim; iDim++) { solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->SetBound_Disp(iPoint, iDim, values[iDim]); } } -vector CDriverBase::GetMarkerVertexNormals(unsigned short iMarker, bool normalize) const { +vector> CDriverBase::GetMarkerVertexNormals(unsigned short iMarker, bool normalize) const { const auto nVertex = GetNumberMarkerVertices(iMarker); - vector values; + + vector> values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - const auto value = GetMarkerVertexNormals(iMarker, normalize=normalize); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - values.push_back(value[iDim]); - } + values.push_back(GetMarkerVertexNormals(iMarker, iVertex, normalize=normalize)); } return values; diff --git a/SU2_PY/pySU2/pySU2.i b/SU2_PY/pySU2/pySU2.i index 0125ffd1e6b..08cf47042fb 100644 --- a/SU2_PY/pySU2/pySU2.i +++ b/SU2_PY/pySU2/pySU2.i @@ -66,10 +66,10 @@ namespace std { %template() vector; %template() vector; %template() vector>; - %template() vector; %template() vector; + %template() vector>; %template() vector; - %template() map; + %template() map; %template() map; } diff --git a/SU2_PY/pySU2/pySU2ad.i b/SU2_PY/pySU2/pySU2ad.i index a1f47b6bf2b..5f0ce8412eb 100644 --- a/SU2_PY/pySU2/pySU2ad.i +++ b/SU2_PY/pySU2/pySU2ad.i @@ -66,10 +66,10 @@ namespace std { %template() vector; %template() vector; %template() vector>; - %template() vector; %template() vector; + %template() vector>; %template() vector; - %template() map; + %template() map; %template() map; } From 5891d3e16e15bac721051788c3e069941f7fbd6a Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 7 Mar 2022 21:43:26 +0100 Subject: [PATCH 024/598] Fix small inconsistencies in previous commit --- Common/src/drivers/CDriverBase.cpp | 84 ++++++++++++++---------------- 1 file changed, 40 insertions(+), 44 deletions(-) diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index 8f2f74d0a99..e07a40652a9 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -329,30 +329,30 @@ unsigned long CDriverBase::GetNumberMarkerVertices(unsigned short iMarker) const unsigned long CDriverBase::GetNumberHaloVertices() const { const auto nPoint = GetNumberVertices(); - unsigned long nHaloVertices = 0; + unsigned long nHalo = 0; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { if (!(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint))) { - nHaloVertices += 1; + nHalo += 1; } } - return nHaloVertices; + return nHalo; } unsigned long CDriverBase::GetNumberMarkerHaloVertices(unsigned short iMarker) const { - const auto nVertex = GetNumberMarkerVertices(iMarker); // error-checking included - unsigned long nHaloVertices = 0; + const auto nVertex = GetNumberMarkerVertices(iMarker); + unsigned long nHalo = 0; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); if (!(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint))) { - nHaloVertices += 1; + nHalo += 1; } } - return nHaloVertices; + return nHalo; } vector CDriverBase::GetMarkerVertexIndex(unsigned short iMarker) const { @@ -408,7 +408,7 @@ vector CDriverBase::GetMarkerVertexIDs(unsigned short iMarker) co } unsigned long CDriverBase::GetMarkerVertexIDs(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); // includes error-checking + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetGlobalIndex(iPoint); } @@ -446,7 +446,7 @@ vector CDriverBase::GetMarkerVertexColors(unsigned short iMarker) } unsigned long CDriverBase::GetMarkerVertexColors(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); // includes error-checking + auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetColor(iPoint); } @@ -506,17 +506,16 @@ vector CDriverBase::GetInitialCoordinates(unsigned long iPoint) c SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); } - vector values; + vector values (nDim, 0.0); + + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + return values; + } for (auto iDim = 0u; iDim < nDim; iDim++) { const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetMesh_Coord(iPoint, iDim); - - if (!config_container[ZONE_0]->GetDeform_Mesh()) { - values.push_back(0.0); // mesh solver is not defined ! - } - else { - values.push_back(SU2_TYPE::GetValue(value)); - } + + values[iDim] = SU2_TYPE::GetValue(value); } return values; @@ -528,11 +527,7 @@ vector> CDriverBase::GetMarkerInitialCoordinates(unsigned vector> values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - const auto value = GetMarkerInitialCoordinates(iVertex); - - for (auto iDim = 0u; iDim < nDim; iDim++) { - values.push_back(value[iDim]); - } + values.push_back(GetMarkerInitialCoordinates(iMarker, iVertex)); } return values; @@ -541,17 +536,16 @@ vector> CDriverBase::GetMarkerInitialCoordinates(unsigned vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - vector values; + vector values(nDim, 0.0); + + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + return values; + } for (auto iDim = 0u; iDim < nDim; iDim++) { const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetMesh_Coord(iPoint, iDim); - if (!config_container[ZONE_0]->GetDeform_Mesh()) { - values.push_back(0.0); // mesh solver is not defined ! - } - else { - values.push_back(SU2_TYPE::GetValue(value)); - } + values[iDim] = SU2_TYPE::GetValue(value); } return values; @@ -676,15 +670,16 @@ vector> CDriverBase::GetMarkerDisplacements(unsigned short vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - vector values; + vector values (nDim, 0.0); + + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + return values; + } for (auto iDim = 0u; iDim < nDim; iDim++) { - if (config_container[ZONE_0]->GetDeform_Mesh()) { - values.push_back(SU2_TYPE::GetValue(solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Disp(iPoint, iDim))); - } - else { - values.push_back(0.0); - } + const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Disp(iPoint, iDim); + + values[iDim] = SU2_TYPE::GetValue(value); } return values; @@ -737,15 +732,16 @@ vector> CDriverBase::GetMarkerVelocities(unsigned short iM vector CDriverBase::GetMarkerVelocities(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - vector values; + vector values (nDim, 0.0); + + if (!config_container[ZONE_0]->GetDeform_Mesh()) { + return values; + } for (auto iDim = 0u; iDim < nDim; iDim++) { - if (config_container[ZONE_0]->GetDeform_Mesh()) { - values.push_back(SU2_TYPE::GetValue(solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Vel(iPoint, iDim))); - } - else { - values.push_back(0.0); - } + const su2double value = solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->GetNodes()->GetBound_Vel(iPoint, iDim); + + values[iDim] = SU2_TYPE::GetValue(value); } return values; From 59fdd2e86d14f264d92d6b610ee3331a0fe82140 Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 7 Mar 2022 22:22:25 +0100 Subject: [PATCH 025/598] Fix conditional output of FFD information --- SU2_DEF/src/drivers/CDeformationDriver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index ecca754838a..309e65377d2 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -534,7 +534,7 @@ void CDeformationDriver::Output() { (config_container[ZONE_0]->GetDesign_Variable(0) != ROTATE_GRID)) { /*--- Write the the free-form deformation boxes after deformation (if defined). ---*/ - if (true) { + if (!haveSurfaceDeformation) { if (rank == MASTER_NODE) cout << "No FFD information available." << endl; } else { From 4873aa2f46c76e744c482c3c0e655addc6fc608f Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 7 Mar 2022 23:25:20 +0100 Subject: [PATCH 026/598] Introduce 'main' Config and Geometry for Python API --- Common/include/drivers/CDriverBase.hpp | 8 +- Common/src/drivers/CDriverBase.cpp | 99 ++++++++++--------- SU2_CFD/src/drivers/CDriver.cpp | 10 +- SU2_DEF/src/drivers/CDeformationDriver.cpp | 7 ++ .../src/drivers/CDiscAdjDeformationDriver.cpp | 7 ++ 5 files changed, 79 insertions(+), 52 deletions(-) diff --git a/Common/include/drivers/CDriverBase.hpp b/Common/include/drivers/CDriverBase.hpp index 68aa0bd5956..19f0923e4b2 100644 --- a/Common/include/drivers/CDriverBase.hpp +++ b/Common/include/drivers/CDriverBase.hpp @@ -56,10 +56,11 @@ class CDriverBase { *nInst, /*!< \brief Total number of instances in the problem (per zone). */ **interface_types; /*!< \brief Type of coupling between the distinct (physical) zones.*/ - CConfig **config_container; /*!< \brief Definition of the particular problem. */ CConfig *driver_config; /*!< \brief Definition of the driver configuration. */ - COutput **output_container; /*!< \brief Pointer to the COutput class. */ COutput *driver_output; /*!< \brief Definition of the driver output. */ + + CConfig **config_container; /*!< \brief Definition of the particular problem. */ + COutput **output_container; /*!< \brief Pointer to the COutput class. */ CGeometry ****geometry_container; /*!< \brief Geometrical definition of the problem. */ CSolver *****solver_container; /*!< \brief Container vector with all the solutions. */ CNumerics ******numerics_container; /*!< \brief Description of the numerical method (the way in which the equations are solved). */ @@ -67,6 +68,9 @@ class CDriverBase { CVolumetricMovement ***grid_movement; /*!< \brief Volume grid movement classes of the problem. */ CFreeFormDefBox*** FFDBox; /*!< \brief FFD FFDBoxes of the problem. */ + CConfig *main_config; /*!< \brief Reference to the base (i.e. ZONE 0) configuration (used in the driver API). */ + CGeometry *main_geometry; /*!< \brief Reference to the base (i.E. ZONE, INST, MESH 0) geometry (used in the driver API). */ + public: /*! diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index e07a40652a9..01eccb23448 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -78,20 +78,23 @@ void CDriverBase::SetContainers_Null() { nInst[iZone] = 1; } - driver_config = nullptr; - driver_output = nullptr; + driver_config = nullptr; + driver_output = nullptr; + + main_config = nullptr; + main_geometry = nullptr; } unsigned short CDriverBase::GetNumberMarkers() const { - return config_container[ZONE_0]->GetnMarker_All(); + return main_config->GetnMarker_All(); } map CDriverBase::GetMarkerIndices() const { - const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); + const auto nMarker = main_config->GetnMarker_All(); map indexMap; for (auto iMarker = 0u; iMarker < nMarker; iMarker++) { - auto tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); + auto tag = main_config->GetMarker_All_TagBound(iMarker); indexMap[tag] = iMarker; } @@ -103,9 +106,9 @@ map CDriverBase::GetMarkerTypes() const { map typeMap; string type; - for (auto iMarker = 0u; iMarker < config_container[ZONE_0]->GetnMarker_All(); iMarker++) { - auto tag = config_container[ZONE_0]->GetMarker_All_TagBound(iMarker); - auto kindBC = config_container[ZONE_0]->GetMarker_All_KindBC(iMarker); + for (auto iMarker = 0u; iMarker < main_config->GetnMarker_All(); iMarker++) { + auto tag = main_config->GetMarker_All_TagBound(iMarker); + auto kindBC = main_config->GetMarker_All_KindBC(iMarker); switch(kindBC) { case EULER_WALL: @@ -143,10 +146,10 @@ map CDriverBase::GetMarkerTypes() const { vector CDriverBase::GetMarkerTags() const { vector tags; - const auto nMarker = config_container[ZONE_0]->GetnMarker_All(); + const auto nMarker = main_config->GetnMarker_All(); for(auto iMarker = 0u; iMarker < nMarker; iMarker++){ - tags.push_back(config_container[ZONE_0]->GetMarker_All_TagBound(iMarker)); + tags.push_back(main_config->GetMarker_All_TagBound(iMarker)); } return tags; @@ -154,21 +157,21 @@ vector CDriverBase::GetMarkerTags() const { vector CDriverBase::GetDeformableMarkerTags() const { vector tags; - const auto nMarker = config_container[ZONE_0]->GetnMarker_Deform_Mesh(); + const auto nMarker = main_config->GetnMarker_Deform_Mesh(); for (auto iMarker = 0u; iMarker < nMarker; iMarker++) { - tags.push_back(config_container[ZONE_0]->GetMarker_Deform_Mesh_TagBound(iMarker)); + tags.push_back(main_config->GetMarker_Deform_Mesh_TagBound(iMarker)); } return tags; } unsigned long CDriverBase::GetNumberDimensions() const { - return geometry_container[ZONE_0][INST_0][MESH_0]->GetnDim(); + return main_geometry->GetnDim(); } unsigned long CDriverBase::GetNumberElements() const { - return geometry_container[ZONE_0][INST_0][MESH_0]->GetnElem(); + return main_geometry->GetnElem(); } unsigned long CDriverBase::GetNumberMarkerElements(unsigned short iMarker) const { @@ -176,7 +179,7 @@ unsigned long CDriverBase::GetNumberMarkerElements(unsigned short iMarker) const SU2_MPI::Error("Marker index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->GetnElem_Bound(iMarker); + return main_geometry->GetnElem_Bound(iMarker); } vector CDriverBase::GetElementIDs() const { @@ -196,7 +199,7 @@ unsigned long CDriverBase::GetElementIDs(unsigned long iElem) const { SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetGlobalIndex(); + return main_geometry->elem[iElem]->GetGlobalIndex(); } vector CDriverBase::GetMarkerElementIDs(unsigned short iMarker) const { @@ -216,7 +219,7 @@ unsigned long CDriverBase::GetMarkerElementIDs(unsigned short iMarker, unsigned SU2_MPI::Error("Marker element index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetGlobalIndex(); + return main_geometry->bound[iMarker][iBound]->GetGlobalIndex(); } vector CDriverBase::GetElementColors() const { @@ -236,7 +239,7 @@ unsigned long CDriverBase::GetElementColors(unsigned long iElem) const { SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetColor(); + return main_geometry->elem[iElem]->GetColor(); } vector CDriverBase::GetMarkerElementColors(unsigned short iMarker) const { @@ -256,7 +259,7 @@ unsigned long CDriverBase::GetMarkerElementColors(unsigned short iMarker, unsign SU2_MPI::Error("Marker element index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetColor(); + return main_geometry->bound[iMarker][iBound]->GetColor(); } vector> CDriverBase::GetElementConnectivities() const { @@ -276,12 +279,12 @@ vector CDriverBase::GetElementConnectivities(unsigned long iElem) SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); } - unsigned short nNode = geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetnNodes(); + unsigned short nNode = main_geometry->elem[iElem]->GetnNodes(); vector values; for (auto iNode = 0u; iNode < nNode; iNode++) { - values.push_back(geometry_container[ZONE_0][INST_0][MESH_0]->elem[iElem]->GetNode(iNode)); + values.push_back(main_geometry->elem[iElem]->GetNode(iNode)); } return values; @@ -304,19 +307,19 @@ vector CDriverBase::GetMarkerElementConnectivities(unsigned short SU2_MPI::Error("Marker element index exceeds size.", CURRENT_FUNCTION); } - unsigned short nNode = geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetnNodes(); + unsigned short nNode = main_geometry->bound[iMarker][iBound]->GetnNodes(); vector values; for (auto iNode = 0u; iNode < nNode; iNode++) { - values.push_back(geometry_container[ZONE_0][INST_0][MESH_0]->bound[iMarker][iBound]->GetNode(iNode)); + values.push_back(main_geometry->bound[iMarker][iBound]->GetNode(iNode)); } return values; } unsigned long CDriverBase::GetNumberVertices() const { - return geometry_container[ZONE_0][INST_0][MESH_0]->GetnPoint(); + return main_geometry->GetnPoint(); } unsigned long CDriverBase::GetNumberMarkerVertices(unsigned short iMarker) const { @@ -324,7 +327,7 @@ unsigned long CDriverBase::GetNumberMarkerVertices(unsigned short iMarker) const SU2_MPI::Error("Marker index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->GetnVertex(iMarker); + return main_geometry->GetnVertex(iMarker); } unsigned long CDriverBase::GetNumberHaloVertices() const { @@ -332,7 +335,7 @@ unsigned long CDriverBase::GetNumberHaloVertices() const { unsigned long nHalo = 0; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - if (!(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint))) { + if (!(main_geometry->nodes->GetDomain(iPoint))) { nHalo += 1; } } @@ -347,7 +350,7 @@ unsigned long CDriverBase::GetNumberMarkerHaloVertices(unsigned short iMarker) c for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - if (!(geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint))) { + if (!(main_geometry->nodes->GetDomain(iPoint))) { nHalo += 1; } } @@ -392,7 +395,7 @@ unsigned long CDriverBase::GetVertexIDs(unsigned long iPoint) const { SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetGlobalIndex(iPoint); + return main_geometry->nodes->GetGlobalIndex(iPoint); } vector CDriverBase::GetMarkerVertexIDs(unsigned short iMarker) const { @@ -410,7 +413,7 @@ vector CDriverBase::GetMarkerVertexIDs(unsigned short iMarker) co unsigned long CDriverBase::GetMarkerVertexIDs(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetGlobalIndex(iPoint); + return main_geometry->nodes->GetGlobalIndex(iPoint); } vector CDriverBase::GetVertexColors() const { @@ -430,7 +433,7 @@ unsigned long CDriverBase::GetVertexColors(unsigned long iPoint) const { SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetColor(iPoint); + return main_geometry->nodes->GetColor(iPoint); } vector CDriverBase::GetMarkerVertexColors(unsigned short iMarker) const { @@ -448,7 +451,7 @@ vector CDriverBase::GetMarkerVertexColors(unsigned short iMarker) unsigned long CDriverBase::GetMarkerVertexColors(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetColor(iPoint); + return main_geometry->nodes->GetColor(iPoint); } vector CDriverBase::GetDomain() const { @@ -468,7 +471,7 @@ bool CDriverBase::GetDomain(unsigned long iPoint) const { SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); } - return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint); + return main_geometry->nodes->GetDomain(iPoint); } vector CDriverBase::GetMarkerDomain(unsigned short iMarker) const { @@ -486,7 +489,7 @@ vector CDriverBase::GetMarkerDomain(unsigned short iMarker) const { bool CDriverBase::GetMarkerDomain(unsigned short iMarker, unsigned long iVertex) const { auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - return geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetDomain(iPoint); + return main_geometry->nodes->GetDomain(iPoint); } vector> CDriverBase::GetInitialCoordinates() const { @@ -508,7 +511,7 @@ vector CDriverBase::GetInitialCoordinates(unsigned long iPoint) c vector values (nDim, 0.0); - if (!config_container[ZONE_0]->GetDeform_Mesh()) { + if (!main_config->GetDeform_Mesh()) { return values; } @@ -538,7 +541,7 @@ vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iM vector values(nDim, 0.0); - if (!config_container[ZONE_0]->GetDeform_Mesh()) { + if (!main_config->GetDeform_Mesh()) { return values; } @@ -571,7 +574,7 @@ vector CDriverBase::GetCoordinates(unsigned long iPoint) const { vector values; for (auto iDim = 0u; iDim < nDim; iDim++) { - const su2double value = geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetCoord(iPoint, iDim); + const su2double value = main_geometry->nodes->GetCoord(iPoint, iDim); values.push_back(SU2_TYPE::GetValue(value)); } @@ -597,7 +600,7 @@ vector CDriverBase::GetMarkerCoordinates(unsigned short iMarker, vector values; for (auto iDim = 0u; iDim < nDim; iDim++) { - const su2double value = geometry_container[ZONE_0][INST_0][MESH_0]->nodes->GetCoord(iPoint, iDim); + const su2double value = main_geometry->nodes->GetCoord(iPoint, iDim); values.push_back(SU2_TYPE::GetValue(value)); } @@ -627,7 +630,7 @@ void CDriverBase::SetCoordinates(unsigned long iPoint, vector val } for (auto iDim = 0u; iDim < nDim; iDim++) { - geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iDim]); + main_geometry->nodes->SetCoord(iPoint, iDim, values[iDim]); } } @@ -651,7 +654,7 @@ void CDriverBase::SetMarkerCoordinates(unsigned short iMarker, unsigned long iVe } for (auto iDim = 0u; iDim < nDim; iDim++) { - geometry_container[ZONE_0][INST_0][MESH_0]->nodes->SetCoord(iPoint, iDim, values[iDim]); + main_geometry->nodes->SetCoord(iPoint, iDim, values[iDim]); } } @@ -672,7 +675,7 @@ vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker vector values (nDim, 0.0); - if (!config_container[ZONE_0]->GetDeform_Mesh()) { + if (!main_config->GetDeform_Mesh()) { return values; } @@ -686,7 +689,7 @@ vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker } void CDriverBase::SetMarkerDisplacements(unsigned short iMarker, vector> values) { - if (!config_container[ZONE_0]->GetDeform_Mesh()) { + if (!main_config->GetDeform_Mesh()) { SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } @@ -702,7 +705,7 @@ void CDriverBase::SetMarkerDisplacements(unsigned short iMarker, vector values) { - if (!config_container[ZONE_0]->GetDeform_Mesh()) { + if (!main_config->GetDeform_Mesh()) { SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } @@ -734,7 +737,7 @@ vector CDriverBase::GetMarkerVelocities(unsigned short iMarker, u vector values (nDim, 0.0); - if (!config_container[ZONE_0]->GetDeform_Mesh()) { + if (!main_config->GetDeform_Mesh()) { return values; } @@ -748,7 +751,7 @@ vector CDriverBase::GetMarkerVelocities(unsigned short iMarker, u } void CDriverBase::SetMarkerVelocities(unsigned short iMarker, vector> values) { - if (!config_container[ZONE_0]->GetDeform_Mesh()) { + if (!main_config->GetDeform_Mesh()) { SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } @@ -764,7 +767,7 @@ void CDriverBase::SetMarkerVelocities(unsigned short iMarker, vector values) { - if (!config_container[ZONE_0]->GetDeform_Mesh()) { + if (!main_config->GetDeform_Mesh()) { SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } @@ -798,7 +801,7 @@ vector CDriverBase::GetMarkerVertexNormals(unsigned short iMarker vector values; - auto normal = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNormal(); + auto normal = main_geometry->vertex[iMarker][iVertex]->GetNormal(); auto area = GeometryToolbox::Norm(nDim, normal); for (auto iDim = 0u; iDim < nDim; iDim++) { @@ -814,6 +817,6 @@ vector CDriverBase::GetMarkerVertexNormals(unsigned short iMarker void CDriverBase::CommunicateMeshDisplacements(void) { - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->InitiateComms(geometry_container[ZONE_0][INST_0][MESH_0], config_container[ZONE_0], MESH_DISPLACEMENTS); - solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->CompleteComms(geometry_container[ZONE_0][INST_0][MESH_0], config_container[ZONE_0], MESH_DISPLACEMENTS); + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->InitiateComms(main_geometry, main_config, MESH_DISPLACEMENTS); + solver_container[ZONE_0][INST_0][MESH_0][MESH_SOL]->CompleteComms(main_geometry, main_config, MESH_DISPLACEMENTS); } diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 4bb2a8a7071..b649ddc751d 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -589,6 +589,7 @@ void CDriver::Input_Preprocessing(CConfig **&config, CConfig *&driver_config) { /*--- Set the MPI communicator ---*/ config[iZone]->SetMPICommunicator(SU2_MPI::GetComm()); + } @@ -599,7 +600,10 @@ void CDriver::Input_Preprocessing(CConfig **&config, CConfig *&driver_config) { config_container[iZone]->SetMultizone(driver_config, config_container); } } - + + /*--- Keep a reference to the main (ZONE 0) config ---*/ + main_config = config_container[ZONE_0]; + /*--- Determine whether or not the FEM solver is used, which decides the type of * geometry classes that are instantiated. Only adapted for single-zone problems ---*/ @@ -703,7 +707,9 @@ void CDriver::Geometrical_Preprocessing(CConfig* config, CGeometry **&geometry, geometry_container[iZone][iInst][iMesh]->ComputeSurf_Straightness(config_container[iZone], (iMesh==MESH_0) ); } - + + /*--- Keep a reference to the main (ZONE_0, INST_0, MESH_0) geometry ---*/ + main_geometry = geometry_container[ZONE_0][INST_0][MESH_0]; } void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geometry) { diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index 309e65377d2..2c577ed2c7f 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -140,6 +140,9 @@ void CDeformationDriver::Input_Preprocessing() { config_container[iZone]->SetMultizone(driver_config, config_container); } } + + /*--- Keep a reference to the main (ZONE 0) config ---*/ + main_config = config_container[ZONE_0]; } void CDeformationDriver::Geometrical_Preprocessing() { @@ -220,6 +223,10 @@ void CDeformationDriver::Geometrical_Preprocessing() { /*--- Get the number of dimensions ---*/ nDim = geometry_container[ZONE_0][INST_0][MESH_0]->GetnDim(); + + /*--- Keep a reference to the main (ZONE_0, INST_0, MESH_0) geometry ---*/ + main_geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + } void CDeformationDriver::Output_Preprocessing() { diff --git a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp index a91ade80097..94768b3c0e4 100644 --- a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp @@ -124,6 +124,9 @@ void CDiscAdjDeformationDriver::Input_Preprocessing() { config_container[iZone]->SetMultizone(driver_config, config_container); } } + + /*--- Keep a reference to the main (ZONE 0) config ---*/ + main_config = config_container[ZONE_0]; } void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { @@ -254,6 +257,10 @@ void CDiscAdjDeformationDriver::Geometrical_Preprocessing() { geometry_container[iZone][INST_0][MESH_0]->PreprocessP2PComms(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); } + + /*--- Keep a reference to the main (ZONE_0, INST_0, MESH_0) geometry ---*/ + main_geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + } void CDiscAdjDeformationDriver::Output_Preprocessing() { From 6aa8018695d37f754cbcd435685263855d334d69 Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 4 Apr 2022 22:23:32 +0200 Subject: [PATCH 027/598] Remove some functions and fix IDs in Get(Marker)?ElementConnectivities --- Common/include/drivers/CDriverBase.hpp | 56 --------------- Common/src/drivers/CDriverBase.cpp | 98 ++------------------------ SU2_CFD/src/drivers/CDriver.cpp | 20 ------ 3 files changed, 6 insertions(+), 168 deletions(-) diff --git a/Common/include/drivers/CDriverBase.hpp b/Common/include/drivers/CDriverBase.hpp index 19f0923e4b2..5a78918ec67 100644 --- a/Common/include/drivers/CDriverBase.hpp +++ b/Common/include/drivers/CDriverBase.hpp @@ -192,34 +192,6 @@ class CDriverBase { */ unsigned long GetMarkerElementIDs(unsigned short iMarker, unsigned long iBound) const; - /*! - * \brief Get the MPI colors for mesh elements. - * \return Element colors. - */ - vector GetElementColors() const; - - /*! - * \brief Get the MPI color for a mesh element. - * \param[in] iElem - Mesh element index. - * \return Element color. - */ - unsigned long GetElementColors(unsigned long iElem) const; - - /*! - * \brief Get the MPI colors for marker elements. - * \param[in] iMarker - Marker index. - * \return Element colors. - */ - vector GetMarkerElementColors(unsigned short iMarker) const; - - /*! - * \brief Get the MPI color for a marker element. - * \param[in] iMarker - Marker index. - * \param[in] iBound - Marker element index. - * \return Element color. - */ - unsigned long GetMarkerElementColors(unsigned short iMarker, unsigned long iBound) const; - /*! * \brief Get the table of vertex IDs belonging to the mesh elements. * \return Element connectivities (nElem, nNode) @@ -317,34 +289,6 @@ class CDriverBase { */ unsigned long GetMarkerVertexIDs(unsigned short iMarker, unsigned long iVertex) const; - /*! - * \brief Get the MPI colors of the mesh vertices. - * \return Vertex colors. - */ - vector GetVertexColors() const; - - /*! - * \brief Get the MPI color of a mesh vertex. - * \param[in] iPoint - Mesh vertex index. - * \return Vertex color. - */ - unsigned long GetVertexColors(unsigned long iPoint) const; - - /*! - * \brief Get the MPI colors of the marker vertices. - * \param[in] iMarker - Marker index. - * \return Vertex colors. - */ - vector GetMarkerVertexColors(unsigned short iMarker) const; - - /*! - * \brief Get the MPI color of a marker vertex. - * \param[in] iMarker - Marker index. - * \param[in] iVertex - Marker vertex index. - * \return Vertex color. - */ - unsigned long GetMarkerVertexColors(unsigned short iMarker, unsigned long iVertex) const; - /*! * \brief Get the halo flags of the mesh vertices. * \return Vertex domain flags. diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index 01eccb23448..5702cf51513 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -222,58 +222,6 @@ unsigned long CDriverBase::GetMarkerElementIDs(unsigned short iMarker, unsigned return main_geometry->bound[iMarker][iBound]->GetGlobalIndex(); } -vector CDriverBase::GetElementColors() const { - const auto nElem = GetNumberElements(); - - vector values; - - for (auto iElem = 0ul; iElem < nElem; iElem++) { - values.push_back(GetElementColors(iElem)); - } - - return values; -} - -unsigned long CDriverBase::GetElementColors(unsigned long iElem) const { - if (iElem >= GetNumberElements()) { - SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); - } - - return main_geometry->elem[iElem]->GetColor(); -} - -vector CDriverBase::GetMarkerElementColors(unsigned short iMarker) const { - const auto nBound = GetNumberMarkerElements(iMarker); - - vector values; - - for (auto iBound = 0ul; iBound < nBound; iBound++) { - values.push_back(GetMarkerElementColors(iMarker, iBound)); - } - - return values; -} - -unsigned long CDriverBase::GetMarkerElementColors(unsigned short iMarker, unsigned long iBound) const { - if (iBound >= GetNumberMarkerElements(iMarker)) { - SU2_MPI::Error("Marker element index exceeds size.", CURRENT_FUNCTION); - } - - return main_geometry->bound[iMarker][iBound]->GetColor(); -} - -vector> CDriverBase::GetElementConnectivities() const { - const auto nElem = GetNumberElements(); - - vector> values; - - for (auto iElem = 0ul; iElem < nElem; iElem++) { - values.push_back(GetElementConnectivities(iElem)); - } - - return values; -} - vector CDriverBase::GetElementConnectivities(unsigned long iElem) const { if (iElem >= GetNumberElements()) { SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); @@ -284,7 +232,9 @@ vector CDriverBase::GetElementConnectivities(unsigned long iElem) vector values; for (auto iNode = 0u; iNode < nNode; iNode++) { - values.push_back(main_geometry->elem[iElem]->GetNode(iNode)); + unsigned long iPoint = main_geometry->elem[iElem]->GetNode(iNode); + + values.push_back(main_geometry->nodes->GetGlobalIndex(iPoint)); } return values; @@ -312,7 +262,9 @@ vector CDriverBase::GetMarkerElementConnectivities(unsigned short vector values; for (auto iNode = 0u; iNode < nNode; iNode++) { - values.push_back(main_geometry->bound[iMarker][iBound]->GetNode(iNode)); + unsigned long iPoint = main_geometry->bound[iMarker][iBound]->GetNode(iNode); + + values.push_back(main_geometry->nodes->GetGlobalIndex(iPoint)); } return values; @@ -416,44 +368,6 @@ unsigned long CDriverBase::GetMarkerVertexIDs(unsigned short iMarker, unsigned l return main_geometry->nodes->GetGlobalIndex(iPoint); } -vector CDriverBase::GetVertexColors() const { - const auto nPoint = GetNumberVertices(); - - vector values; - - for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - values.push_back(GetVertexColors(iPoint)); - } - - return values; -} - -unsigned long CDriverBase::GetVertexColors(unsigned long iPoint) const { - if (iPoint >= GetNumberVertices()) { - SU2_MPI::Error("Vertex index exceeds size.", CURRENT_FUNCTION); - } - - return main_geometry->nodes->GetColor(iPoint); -} - -vector CDriverBase::GetMarkerVertexColors(unsigned short iMarker) const { - const auto nVertex = GetNumberMarkerVertices(iMarker); - - vector values; - - for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - values.push_back(GetMarkerVertexColors(iMarker, iVertex)); - } - - return values; -} - -unsigned long CDriverBase::GetMarkerVertexColors(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); - - return main_geometry->nodes->GetColor(iPoint); -} - vector CDriverBase::GetDomain() const { const auto nPoint = GetNumberVertices(); diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index e44a0e6781b..279470e0fcf 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -1139,26 +1139,6 @@ void CDriver::Inlet_Preprocessing(CSolver ***solver, CGeometry **geometry, string("Please set SPECIFIED_INLET_PROFILE= NO and try again."), CURRENT_FUNCTION); } - } else { - - /*--- Uniform inlets or python-customized inlets ---*/ - - /* --- Initialize quantities for inlet boundary - * This routine does not check if the python wrapper is being used to - * set custom boundary conditions. This is intentional; the - * default values for python custom BCs are initialized with the default - * values specified in the config (avoiding non physical values) --- */ - - for (unsigned short iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - for(unsigned short iMarker=0; iMarker < config->GetnMarker_All(); iMarker++) { - if (solver[iMesh][FLOW_SOL]) solver[iMesh][FLOW_SOL]->SetUniformInlet(config, iMarker); - if (solver[iMesh][TURB_SOL]) solver[iMesh][TURB_SOL]->SetUniformInlet(config, iMarker); - if (solver[iMesh][SPECIES_SOL]) solver[iMesh][SPECIES_SOL]->SetUniformInlet(config, iMarker); - } - } - - } - } void CDriver::Solver_Restart(CSolver ***solver, CGeometry **geometry, From 3f0247625a9510232edf439297d7295888c6a3ed Mon Sep 17 00:00:00 2001 From: aa-g Date: Mon, 11 Apr 2022 20:15:52 +0200 Subject: [PATCH 028/598] Fix small inconsistency in naming of Getters/Setters --- Common/include/drivers/CDriverBase.hpp | 4 +-- Common/src/drivers/CDriverBase.cpp | 38 +++++++++++++++++--------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Common/include/drivers/CDriverBase.hpp b/Common/include/drivers/CDriverBase.hpp index 5a78918ec67..1fa0d011ca2 100644 --- a/Common/include/drivers/CDriverBase.hpp +++ b/Common/include/drivers/CDriverBase.hpp @@ -251,7 +251,7 @@ class CDriverBase { * \param[in] iMarker - Marker index. * \return Mesh vertex indices. */ - vector GetMarkerVertexIndex(unsigned short iMarker) const; + vector GetMarkerVertexIndices(unsigned short iMarker) const; /*! * \brief Get the mesh vertex index of a marker vertex. @@ -259,7 +259,7 @@ class CDriverBase { * \param[in] iVertex - Marker vertex index. * \return Mesh vertex index. */ - unsigned long GetMarkerVertexIndex(unsigned short iMarker, unsigned long iVertex) const; + unsigned long GetMarkerVertexIndices(unsigned short iMarker, unsigned long iVertex) const; /*! * \brief Get the global IDs of the mesh vertices. diff --git a/Common/src/drivers/CDriverBase.cpp b/Common/src/drivers/CDriverBase.cpp index 5702cf51513..b778a6ab99b 100644 --- a/Common/src/drivers/CDriverBase.cpp +++ b/Common/src/drivers/CDriverBase.cpp @@ -222,6 +222,18 @@ unsigned long CDriverBase::GetMarkerElementIDs(unsigned short iMarker, unsigned return main_geometry->bound[iMarker][iBound]->GetGlobalIndex(); } +vector> CDriverBase::GetElementConnectivities() const { + const auto nElem = GetNumberElements(); + + vector> values; + + for (auto iElem = 0ul; iElem < nElem; iElem++) { + values.push_back(GetElementConnectivities(iElem)); + } + + return values; +} + vector CDriverBase::GetElementConnectivities(unsigned long iElem) const { if (iElem >= GetNumberElements()) { SU2_MPI::Error("Element index exceeds size.", CURRENT_FUNCTION); @@ -300,7 +312,7 @@ unsigned long CDriverBase::GetNumberMarkerHaloVertices(unsigned short iMarker) c unsigned long nHalo = 0; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); if (!(main_geometry->nodes->GetDomain(iPoint))) { nHalo += 1; @@ -310,19 +322,19 @@ unsigned long CDriverBase::GetNumberMarkerHaloVertices(unsigned short iMarker) c return nHalo; } -vector CDriverBase::GetMarkerVertexIndex(unsigned short iMarker) const { +vector CDriverBase::GetMarkerVertexIndices(unsigned short iMarker) const { const auto nVertex = GetNumberMarkerVertices(iMarker); vector values; for (auto iVertex = 0ul; iVertex < nVertex; iVertex++) { - values.push_back(GetMarkerVertexIndex(iMarker, iVertex)); + values.push_back(GetMarkerVertexIndices(iMarker, iVertex)); } return values; } -unsigned long CDriverBase::GetMarkerVertexIndex(unsigned short iMarker, unsigned long iVertex) const { +unsigned long CDriverBase::GetMarkerVertexIndices(unsigned short iMarker, unsigned long iVertex) const { if (iVertex >= GetNumberMarkerVertices(iMarker)) { SU2_MPI::Error("Marker vertex index exceeds size.", CURRENT_FUNCTION); } @@ -363,7 +375,7 @@ vector CDriverBase::GetMarkerVertexIDs(unsigned short iMarker) co } unsigned long CDriverBase::GetMarkerVertexIDs(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); return main_geometry->nodes->GetGlobalIndex(iPoint); } @@ -401,7 +413,7 @@ vector CDriverBase::GetMarkerDomain(unsigned short iMarker) const { } bool CDriverBase::GetMarkerDomain(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); return main_geometry->nodes->GetDomain(iPoint); } @@ -451,7 +463,7 @@ vector> CDriverBase::GetMarkerInitialCoordinates(unsigned } vector CDriverBase::GetMarkerInitialCoordinates(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); vector values(nDim, 0.0); @@ -509,7 +521,7 @@ vector> CDriverBase::GetMarkerCoordinates(unsigned short i } vector CDriverBase::GetMarkerCoordinates(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); vector values; @@ -561,7 +573,7 @@ void CDriverBase::SetMarkerCoordinates(unsigned short iMarker, vector values) { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); if (values.size() != nDim) { SU2_MPI::Error("Invalid number of dimensions !", CURRENT_FUNCTION); @@ -585,7 +597,7 @@ vector> CDriverBase::GetMarkerDisplacements(unsigned short } vector CDriverBase::GetMarkerDisplacements(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); vector values (nDim, 0.0); @@ -623,7 +635,7 @@ void CDriverBase::SetMarkerDisplacements(unsigned short iMarker, unsigned long i SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); if (values.size() != nDim) { SU2_MPI::Error("Invalid number of dimensions !", CURRENT_FUNCTION); @@ -647,7 +659,7 @@ vector> CDriverBase::GetMarkerVelocities(unsigned short iM } vector CDriverBase::GetMarkerVelocities(unsigned short iMarker, unsigned long iVertex) const { - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); vector values (nDim, 0.0); @@ -685,7 +697,7 @@ void CDriverBase::SetMarkerVelocities(unsigned short iMarker, unsigned long iVer SU2_MPI::Error("Mesh solver is not defined !", CURRENT_FUNCTION); } - auto iPoint = GetMarkerVertexIndex(iMarker, iVertex); + auto iPoint = GetMarkerVertexIndices(iMarker, iVertex); if (values.size() != nDim) { SU2_MPI::Error("Invalid number of dimensions !", CURRENT_FUNCTION); From 01bb85b8f9ef6f76e0a7a2757e87ebdde8a814cc Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Mon, 12 Sep 2022 16:03:56 +0200 Subject: [PATCH 029/598] Added MLP classes to numerics folder --- .../numerics/multilayer_perceptron/IOMap.hpp | 80 +++++ .../numerics/multilayer_perceptron/Layer.hpp | 63 ++++ .../multilayer_perceptron/LookUp_ANN.hpp | 131 +++++++ .../multilayer_perceptron/NeuralNetwork.hpp | 174 +++++++++ .../numerics/multilayer_perceptron/Neuron.hpp | 74 ++++ .../ReadNeuralNetwork.hpp | 74 ++++ SU2_CFD/obj/Makefile.am | 6 + SU2_CFD/src/meson.build | 8 +- .../numerics/multilayer_perceptron/IOMap.cpp | 60 ++++ .../numerics/multilayer_perceptron/Layer.cpp | 62 ++++ .../multilayer_perceptron/LookUp_ANN.cpp | 268 ++++++++++++++ .../multilayer_perceptron/NeuralNetwork.cpp | 332 ++++++++++++++++++ .../numerics/multilayer_perceptron/Neuron.cpp | 114 ++++++ .../ReadNeuralNetwork.cpp | 151 ++++++++ 14 files changed, 1596 insertions(+), 1 deletion(-) create mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp create mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/Layer.hpp create mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/LookUp_ANN.hpp create mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp create mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/Neuron.hpp create mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp create mode 100644 SU2_CFD/src/numerics/multilayer_perceptron/IOMap.cpp create mode 100644 SU2_CFD/src/numerics/multilayer_perceptron/Layer.cpp create mode 100644 SU2_CFD/src/numerics/multilayer_perceptron/LookUp_ANN.cpp create mode 100644 SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp create mode 100644 SU2_CFD/src/numerics/multilayer_perceptron/Neuron.cpp create mode 100644 SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp new file mode 100644 index 00000000000..66878762edb --- /dev/null +++ b/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp @@ -0,0 +1,80 @@ +/*! + * \file IOMap.hpp + * \brief Declaration of input-to-output mapping class for artifical neural networks + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "../../../../Common/include/CConfig.hpp" +#include "../../../../Common/include/linear_algebra/blas_structure.hpp" +#include "LookUp_ANN.hpp" + +using namespace std; +class LookUp_ANN; + +class IOMap +{ + private: + vector ANN_indices; + vector>> Input_Map; + vector>> Output_Map; + vector> input_indices; + public: + IOMap(){}; + IOMap(LookUp_ANN*ANN_collection, vector &inputs, vector &outputs); + ~IOMap(){}; + void Push_ANN_index(size_t i_ANN){ANN_indices.push_back(i_ANN);}; + void PairVariableswithANNs(LookUp_ANN * ANN_collection, vector &inputs, vector &outputs); + size_t GetNANNs(){return ANN_indices.size();} + size_t GetANNIndex(size_t i_Map){return ANN_indices[i_Map];} + size_t GetInputIndex(size_t i_Map, size_t iInput){return Input_Map[i_Map][iInput].first;} + size_t GetOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].first;} + vector> GetOutputMapping(size_t i_map){return Output_Map[i_map];} + vector> GetInputMapping(size_t i_map){return Input_Map[i_map];} + + vector GetANN_Inputs(size_t i_Map, vector&inputs){ + vector ANN_input; + ANN_input.resize(Input_Map[i_Map].size()); + + for(size_t iInput=0; iInput GetANN_Outputs(size_t i_Map, vector&outputs){ + vector ANN_output; + ANN_output.resize(Output_Map[i_Map].size()); + + for(size_t iOutput=0; iOutput. + */ +#pragma once + +#include +#include +#include +#include + +#include "../../../../Common/include/CConfig.hpp" +#include "Neuron.hpp" +#include "../../../../Common/include/linear_algebra/blas_structure.hpp" +using namespace std; + +class Layer +{ +private: + unsigned long number_of_neurons; + Neuron * neurons; + bool input; + string activation_type; +public: + Layer(); + Layer(unsigned long n_neurons); + void setNNeurons(unsigned long n_neurons); + unsigned long getNNeurons(){return number_of_neurons;}; + void sayhi(); + void setInput(bool def){input = def;}; + bool isInput(){return input;}; + void setValue(size_t i_neuron, su2double value){neurons[i_neuron].setValue(value);} + su2double getValue(size_t i_neuron){return neurons[i_neuron].getValue();} + void setBias(size_t i_neuron, su2double value){neurons[i_neuron].setBias(value);} + su2double getBias(size_t i_neuron){return neurons[i_neuron].getBias();} + su2double getdYdX(size_t i_neuron){return neurons[i_neuron].getGradient();} + string getActivationType(){return activation_type;} + ~Layer(){ + delete [] neurons; + }; +}; diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/LookUp_ANN.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/LookUp_ANN.hpp new file mode 100644 index 00000000000..9cab1a9204c --- /dev/null +++ b/SU2_CFD/include/numerics/multilayer_perceptron/LookUp_ANN.hpp @@ -0,0 +1,131 @@ +/*! + * \file LookUp_ANN.hpp + * \brief Declaration of artificial neural network interpolation class + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include "../../../../Common/include/CConfig.hpp" +#include "../../../../Common/include/linear_algebra/blas_structure.hpp" +#include "NeuralNetwork.hpp" +#include "IOMap.hpp" + +using namespace std; +class IOMap; + +class LookUp_ANN +{ + private: + int rank{0}; + vector NeuralNetworks; /*!< Vector containing all loaded neural networks. */ + + vector ANN_filenames; /*!< Filenames containing ANN architecture information. */ + + unsigned long number_of_variables; /*!< Number of loaded ANNs. */ + + /*! + * \brief Skip to certain flag in file. + * \param[in] file_stream - input stream of file + * \param[in] flag - line to search for + * \return line in file. + */ + string SkipToFlag(ifstream *file_stream, string flag); + + /*! + * \brief Load ANN architecture + * \param[in] ANN - pointer to target NeuralNetwork class + * \param[in] filename - filename containing ANN architecture information + */ + void GenerateANN(NeuralNetwork*ANN, string filename); + + /*! + * \brief Read ANN architecture input file + * \param[in] filename - filename containing ANN architecture information + */ + void ReadANNInputFile(string fileName); + + public: + + /*! + * \brief ANN collection class constructor + * \param[in] filename - filename containing list of ANN input files + */ + LookUp_ANN(string fileName); + + /*! + * \brief Evaluate loaded ANNs for given inputs and outputs + * \param[in] input_output_map - input-output map coupling desired inputs and outputs to loaded ANNs + * \param[in] inputs - input values + * \param[in] outputs - pointers to output variables + */ + void Predict_ANN(IOMap *input_output_map, vector &inputs, vector &outputs); + + ~LookUp_ANN(){for(size_t i_ANN=0; i_ANN &output_names, IOMap *input_output_map) const; + + /*! + * \brief Check if all output variables are present in the loaded ANNs + * \param[in] output_names - output variable names to check + * \param[in] input_output_map - pointer to input-output map to be checked + */ + bool Check_Use_of_Outputs(vector &output_names, IOMap *input_output_map) const; + + /*! + * \brief Check if all input variables are present in the loaded ANNs + * \param[in] input_names - input variable names to check + * \param[in] input_output_map - pointer to input-output map to be checked + */ + bool Check_Use_of_Inputs(vector &input_names, IOMap *input_output_map) const; + + /*! + * \brief Map variable names to ANN inputs or outputs + * \param[in] i_ANN - loaded ANN index + * \param[in] variable_names - variable names to map to ANN inputs or outputs + * \param[in] input - map to inputs (true) or outputs (false) + */ + vector> FindVariable_Indices(size_t i_ANN, vector variable_names, bool input) const; + +}; + diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp new file mode 100644 index 00000000000..682d673f5a6 --- /dev/null +++ b/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp @@ -0,0 +1,174 @@ +/*! + * \file NeuralNetwork.hpp + * \brief Declaration of the neural network class + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "../../../../Common/include/CConfig.hpp" +#include "../../../../Common/include/linear_algebra/blas_structure.hpp" +#include "Layer.hpp" + +using namespace std; +class Activation_Function { + private: + public: + Activation_Function(){}; + ~Activation_Function(){}; + inline virtual su2double run_activation_function(su2double x) {return 0.0;} +}; + +class Linear : public Activation_Function { + private: + public: + Linear() : Activation_Function() {}; + ~Linear(){}; + su2double run_activation_function(su2double x) final {return x;} +}; + +class Relu : public Activation_Function { + private: + public: + Relu() : Activation_Function() {}; + ~Relu(){}; + su2double run_activation_function(su2double x) final {return max(0.0, x);} +}; + +class SmoothSlope : public Activation_Function { + private: + su2double tanhx; + public: + SmoothSlope() : Activation_Function() {}; + ~SmoothSlope(){}; + su2double run_activation_function(su2double x) final {tanhx = tanh(x); return max(tanhx, x);} +}; + +class None : public Activation_Function { + private: + public: + None() : Activation_Function() {}; + ~None(){}; + su2double run_activation_function(su2double x) final {return 0.0;} +}; + +class NeuralNetwork +{ +private: + vector input_names; + vector output_names; + + unsigned long n_hidden_layers; + Layer *inputLayer; + Layer *outputLayer; + vector< Layer *> hiddenLayers; + vectortotal_layers; + + vector>> weights; + vector weights_mat; + vector> values; + + vector> input_norm; + vector> output_norm; + vector last_inputs; + + enum ENUM_ACTIVATION_FUNCTION { + NONE=0, + LINEAR=1, + RELU=2, + SMOOTH_SLOPE=3, + ELU = 4 + }; + ENUM_ACTIVATION_FUNCTION * activation_function_types; + vector activation_functions; + Activation_Function* current_activation_function; + //Activation_Function *activation_functions; +public: + NeuralNetwork(); + ~NeuralNetwork(){ + for(size_t i=0; isetBias(i_neuron, value);} + void setActivationFunction(unsigned long i_layer, string input); + void displayNetwork(); + void sizeWeights(); + void sizeInputs(unsigned long n_inputs){last_inputs.resize(n_inputs); for(unsigned long iInput=0; iInputgetNNeurons();} + unsigned long getNNeurons(unsigned long iLayer, unsigned long iNeuron){return weights.at(iLayer).at(iNeuron).size();} + + // su2double predict(su2double * X, size_t i_output); + // void predict(vector &inputs, vector &outputs); + void predict(vector &inputs, vector &outputs, su2double**doutputs_dinputs=nullptr); + + //void predict_new(vector &inputs, vector &outputs, su2double**doutputs_dinputs=nullptr); + + void SetInputNorm(unsigned long iInput, su2double input_min, su2double input_max){input_norm.at(iInput) = make_pair(input_min, input_max);} + void SetOutputNorm(unsigned long iOutput, su2double output_min, su2double output_max){output_norm.at(iOutput) = make_pair(output_min, output_max);} + + void PushOutputName(string input){output_names.push_back(input);} + void PushInputName(string input){input_names.push_back(input);} + + string GetInputName(size_t iInput){return input_names[iInput];} + string GetOutputName(size_t iOutput){return output_names[iOutput];} + + size_t GetnInputs(){return input_names.size();} + size_t GetnOutputs(){return output_names.size();} + + void SizeActivationFunctions(unsigned long n_layers){activation_function_types = new ENUM_ACTIVATION_FUNCTION[n_layers]; activation_functions.resize(4); + activation_functions[ENUM_ACTIVATION_FUNCTION::LINEAR] = new Linear(); + activation_functions[ENUM_ACTIVATION_FUNCTION::RELU] = new Relu(); + activation_functions[ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE] = new SmoothSlope(); + } + + su2double ComputeX(size_t iLayer, size_t iNeuron){ + su2double x; + x = total_layers[iLayer]->getBias(iNeuron); + size_t nNeurons_previous = total_layers[iLayer - 1]->getNNeurons(); + for(size_t jNeuron=0; jNeurongetValue(jNeuron); + } + return x; + } + // su2double run_activation_function(unsigned long iLayer, su2double x){return activation_functions[iLayer]->run_activation_function(x);} + //void SetActivationFunction(size_t iLayer, unsigned long function_index){activation_functions[iLayer] = ENUM_ACTIVATION_FUNCTION(function_index);} +}; + + + diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/Neuron.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/Neuron.hpp new file mode 100644 index 00000000000..12e1012b09a --- /dev/null +++ b/SU2_CFD/include/numerics/multilayer_perceptron/Neuron.hpp @@ -0,0 +1,74 @@ +/*! + * \file LookUp_ANN.hpp + * \brief Declaration of artificial neural network perceptron class + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include +#include +#include +#include + +#include "../../../../Common/include/CConfig.hpp" +#include "../../../../Common/include/linear_algebra/blas_structure.hpp" + +using namespace std; +class Neuron +{ +private: + string activation_type="SmoothSlope"; + unsigned long ActivationFunction{ENUM_ACTIVATION_FUNCTION::LINEAR}; + unsigned long i_neuron; + double value; + su2double dy_dx; + double bias{0}; + enum ENUM_ACTIVATION_FUNCTION { + NONE=0, + LINEAR=1, + RELU=2, + SMOOTH_SLOPE=3 + }; + +public: + Neuron(){}; + void setNumber(unsigned long input){i_neuron = input;} + unsigned long getNumber(){return i_neuron;} + //void setFunctionType(string input); + + //string getFunctionType(){return activation_type;} + //su2double activation_function(su2double x); + void setValue(su2double input){value = input;} + su2double getValue(){return value;} + + void setBias(su2double input){bias = input;} + su2double getBias(){return bias;} + + su2double getGradient(){return dy_dx;} + void setGradient(su2double input){dy_dx = input;} + //void SetActivationFunction(unsigned long input){ActivationFunction = input;} + + ~Neuron(){}; +}; + diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp new file mode 100644 index 00000000000..e33d267cbe2 --- /dev/null +++ b/SU2_CFD/include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp @@ -0,0 +1,74 @@ +/*! + * \file ReadNeuralNetwork.hpp + * \brief Declaration of MLP input file reader class + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include +#include +#include +#include + +#include "../../../../Common/include/CConfig.hpp" +#include "../../../../Common/include/linear_algebra/blas_structure.hpp" + +using namespace std; +class ReadNeuralNetwork { + private: + vector input_names; + vector output_names; + + string filename; + unsigned long n_layers; + vector n_neurons; + vector>> weights; + vector> biases; + vector activation_functions; + + vector> input_norm; + vector> output_norm; + public: + + ReadNeuralNetwork(string filename_in); + void ReadMLPFile(); + + string SkipToFlag(ifstream *file_stream, string flag); + + unsigned long GetNInputs(){return n_neurons.at(0);} + unsigned long GetNOutputs(){return n_neurons.at(n_layers - 1);} + + unsigned long GetNlayers(){return n_layers;} + unsigned long GetNneurons(size_t iLayer){return n_neurons.at(iLayer);} + double long GetWeight(size_t iLayer, size_t iNeuron, size_t jNeuron){return weights.at(iLayer).at(iNeuron).at(jNeuron);} + double long GetBias(size_t iLayer, size_t iNeuron){return biases.at(iLayer).at(iNeuron);} + pair GetInputNorm(size_t iInput){return input_norm.at(iInput);} + pair GetOutputNorm(size_t iOutput){return output_norm.at(iOutput);} + string GetActivationFunction(size_t iLayer){return activation_functions.at(iLayer);} + + string GetInputName(size_t iInput){return input_names.at(iInput);} + string GetOutputName(size_t iOutput){return output_names.at(iOutput);} + + ~ReadNeuralNetwork(){}; +}; \ No newline at end of file diff --git a/SU2_CFD/obj/Makefile.am b/SU2_CFD/obj/Makefile.am index 8d1e64e48cd..140433ec93a 100644 --- a/SU2_CFD/obj/Makefile.am +++ b/SU2_CFD/obj/Makefile.am @@ -116,6 +116,12 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/numerics/elasticity/CFEALinearElasticity.cpp \ ../src/numerics/elasticity/CFEANonlinearElasticity.cpp \ ../src/numerics/elasticity/nonlinear_models.cpp \ + ../src/numerics/multilayer_perceptron/LookUp_ANN.cpp \ + ../src/numerics/multilayer_perceptron/IOMap.cpp \ + ../src/numerics/multilayer_perceptron/NeuralNetwork.cpp \ + ../src/numerics/multilayer_perceptron/Neuron.cpp \ + ../src/numerics/multilayer_perceptron/Layer.cpp \ + ../src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp \ ../include/numerics_simd/CNumericsSIMD.cpp \ ../src/output/filewriter/CCSVFileWriter.cpp \ ../src/output/filewriter/CSTLFileWriter.cpp \ diff --git a/SU2_CFD/src/meson.build b/SU2_CFD/src/meson.build index 691db4e5b2d..6e730d80ffc 100644 --- a/SU2_CFD/src/meson.build +++ b/SU2_CFD/src/meson.build @@ -147,7 +147,13 @@ su2_cfd_src += files(['numerics/CNumerics.cpp', 'numerics/elasticity/CFEALinearElasticity.cpp', 'numerics/elasticity/CFEANonlinearElasticity.cpp', 'numerics/elasticity/nonlinear_models.cpp', - 'numerics/CGradSmoothing.cpp']) + 'numerics/CGradSmoothing.cpp', + 'numerics/multilayer_perceptron/LookUp_ANN.cpp', + 'numerics/multilayer_perceptron/IOMap.cpp', + 'numerics/multilayer_perceptron/NeuralNetwork.cpp', + 'numerics/multilayer_perceptron/Layer.cpp', + 'numerics/multilayer_perceptron/Neuron.cpp', + 'numerics/multilayer_perceptron/ReadNeuralNetwork.cpp']) su2_cfd_src += files(['../include/numerics_simd/CNumericsSIMD.cpp']) diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/IOMap.cpp b/SU2_CFD/src/numerics/multilayer_perceptron/IOMap.cpp new file mode 100644 index 00000000000..82d2faf1965 --- /dev/null +++ b/SU2_CFD/src/numerics/multilayer_perceptron/IOMap.cpp @@ -0,0 +1,60 @@ +/*! + * \file IOMap.cpp + * \brief Implementation of the input-output mapping class for the + * use of multi-layer perceptrons in SU2 + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#include "../../../include/numerics/multilayer_perceptron/LookUp_ANN.hpp" +#include "../../../include/numerics/multilayer_perceptron/IOMap.hpp" +#include +#include +#include +#include + +IOMap::IOMap(LookUp_ANN*ANN_collection, vector &inputs, vector &outputs){ + PairVariableswithANNs(ANN_collection, inputs, outputs); + if(outputs.size() > 0){ + ANN_collection->Check_Use_of_Inputs(inputs, this); + ANN_collection->Check_Use_of_Outputs(outputs, this); + ANN_collection->Check_Duplicate_Outputs(outputs, this); + } +} +void IOMap::PairVariableswithANNs(LookUp_ANN*ANN_collection, vector &inputs, vector &outputs){ + + bool isInput, isOutput,input_match; + for(size_t i_ANN=0; i_ANNGetNANNs(); i_ANN++){ + vector> Input_Indices = ANN_collection->FindVariable_Indices(i_ANN, inputs, true); + isInput = Input_Indices.size() > 0; + if(isInput){ + input_match = true; + vector> Output_Indices = ANN_collection->FindVariable_Indices(i_ANN, outputs, false); + isOutput = Output_Indices.size() > 0; + if(isOutput){ + ANN_indices.push_back(i_ANN); + Input_Map.push_back(Input_Indices); + Output_Map.push_back(Output_Indices); + } + } + } +} \ No newline at end of file diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/Layer.cpp b/SU2_CFD/src/numerics/multilayer_perceptron/Layer.cpp new file mode 100644 index 00000000000..b666e4547d3 --- /dev/null +++ b/SU2_CFD/src/numerics/multilayer_perceptron/Layer.cpp @@ -0,0 +1,62 @@ +/*! + * \file Layer.cpp + * \brief Implementation of the Layer class to be used in the NeuralNetwork + * class + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#include "../../../include/numerics/multilayer_perceptron/Layer.hpp" +#include +using namespace std; + +Layer::Layer() : Layer(1) {}; + +Layer::Layer(unsigned long n_neurons) : number_of_neurons{n_neurons}, input{false} +{ + neurons = new Neuron[n_neurons]; + for(size_t i=0; i. + */ +#include "../../../include/numerics/multilayer_perceptron/LookUp_ANN.hpp" +#include "../../../include/numerics/multilayer_perceptron/IOMap.hpp" +#include "../../../include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp" +#include +#include +#include +#include + +using namespace std; + +LookUp_ANN::LookUp_ANN(string inputFileName) +{ + + #ifdef HAVE_MPI + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + #endif + if(rank == MASTER_NODE) + cout << "Generating ANN collection" << endl; + + ReadANNInputFile(inputFileName); + for(size_t i_ANN=0; i_ANN> LookUp_ANN::FindVariable_Indices(size_t i_ANN, vector variable_names, bool input) const { + vector> variable_indices; + size_t nVar = input ? NeuralNetworks[i_ANN]->GetnInputs() : NeuralNetworks[i_ANN]->GetnOutputs(); + + for(size_t iVar=0; iVarGetInputName(iVar) : NeuralNetworks[i_ANN]->GetOutputName(iVar); + + if(variable_names.at(jVar).compare(ANN_varname) == 0){ + variable_indices.push_back(make_pair(jVar, iVar)); + //cout << variable_names[jVar] << " : " << jVar << " | " << ANN_varname << " : " << iVar << endl; + } + } + } + return variable_indices; +} + +void LookUp_ANN::Predict_ANN(IOMap *input_output_map, vector& inputs, vector& outputs){ + for(size_t i_map=0; i_mapGetNANNs(); i_map++){ + size_t i_ANN = input_output_map->GetANNIndex(i_map); + vector ANN_inputs = input_output_map->GetANN_Inputs(i_map, inputs); + vector ANN_outputs = input_output_map->GetANN_Outputs(i_map, outputs); + NeuralNetworks[i_ANN]->predict(ANN_inputs, ANN_outputs); + } +} +void LookUp_ANN::GenerateANN(NeuralNetwork * ANN, string fileName) +{ + ReadNeuralNetwork Reader = ReadNeuralNetwork(fileName); + + // Read MLP input file + Reader.ReadMLPFile(); + + // Generate basic layer architectures + ANN->defineInputLayer(Reader.GetNInputs()); + ANN->sizeInputs(Reader.GetNInputs()); + for(size_t iInput=0; iInputPushInputName(Reader.GetInputName(iInput)); + } + for(size_t iLayer=1; iLayerpush_hidden_layer(Reader.GetNneurons(iLayer)); + } + ANN->defineOutputLayer(Reader.GetNOutputs()); + for(size_t iOutput=0; iOutputPushOutputName(Reader.GetOutputName(iOutput)); + } + + // Size weights of each layer + ANN->sizeWeights(); + + // Define weights and activation functions + ANN->SizeActivationFunctions(ANN->getNWeightLayers()+1); + for(size_t i_layer = 0; i_layer < ANN->getNWeightLayers(); i_layer++){ + ANN->setActivationFunction(i_layer, Reader.GetActivationFunction(i_layer)); + for(size_t i_neuron=0; i_neuron < ANN->getNNeurons(i_layer); i_neuron++){ + for(size_t j_neuron=0; j_neurongetNNeurons(i_layer, i_neuron); j_neuron++){ + ANN->setWeight(i_layer, i_neuron, j_neuron, Reader.GetWeight(i_layer, i_neuron, j_neuron)); + } + } + + + } + ANN->setActivationFunction(ANN->getNWeightLayers(), Reader.GetActivationFunction(ANN->getNWeightLayers())); + + // Set neuron biases + for(size_t i_layer=0; i_layergetNWeightLayers()+1; i_layer++){ + for(size_t i_neuron=0; i_neurongetNNeurons(i_layer); i_neuron++){ + ANN->setBias(i_layer, i_neuron, Reader.GetBias(i_layer, i_neuron)); + } + } + + // Define input and output layer normalization values + for(unsigned long iInput=0; iInputSetInputNorm(iInput, Reader.GetInputNorm(iInput).first, Reader.GetInputNorm(iInput).second); + } + for(unsigned long iOutput=0; iOutputSetOutputNorm(iOutput, Reader.GetOutputNorm(iOutput).first, Reader.GetOutputNorm(iOutput).second); + } + +} +void LookUp_ANN::ReadANNInputFile(string inputFileName) +{ + ifstream file_stream; + istringstream stream_names_var; + istringstream stream_filenames; + file_stream.open(inputFileName.c_str(), ifstream::in); + + if (!file_stream.is_open()) { + SU2_MPI::Error(string("There is no MLP collection file file called ") + inputFileName, + CURRENT_FUNCTION); + } + + string line; + string word; + + line = SkipToFlag(&file_stream, "[number of MLP files]"); + getline(file_stream, line); + number_of_variables = stoul(line); + NeuralNetworks.resize(number_of_variables); + + line = SkipToFlag(&file_stream, "[MLP file names]"); + getline(file_stream, line); + stream_filenames.str(line); + while(stream_filenames){ + stream_filenames >> word; + ANN_filenames.push_back(word); + } + ANN_filenames.pop_back(); +} +string LookUp_ANN::SkipToFlag(ifstream *file_stream, string flag) { + string line; + getline(*file_stream, line); + + while (line.compare(flag) != 0 && !(*file_stream).eof()) { + getline(*file_stream, line); + } + + if ((*file_stream).eof()) + SU2_MPI::Error("Flag not found in file", CURRENT_FUNCTION); + + return line; +} + + +bool LookUp_ANN::Check_Duplicate_Outputs(vector &output_names, IOMap *input_output_map) const { + unsigned short n_occurances; + bool duplicate{false}; + vector duplicate_variables; + for(size_t i_Output =0; i_Output < output_names.size(); i_Output++){ + n_occurances = 0; + for(size_t i_map=0; i_mapGetNANNs(); i_map++){ + size_t i_ANN = input_output_map->GetANNIndex(i_map); + vector> output_map = input_output_map->GetOutputMapping(i_map); + for(size_t j_Output=0; j_Output 1){ + duplicate_variables.push_back(output_names[i_Output]); + duplicate = true; + } + } + if(duplicate){ + string message{"Variables "}; + for(size_t iVar=0; iVar &input_names, IOMap *input_output_map) const { +unsigned short n_inputs = input_names.size(); +vector missing_inputs; +bool inputs_are_present{true}; +for(size_t iInput=0; iInputGetNANNs(); i_map++){ + size_t i_ANN = input_output_map->GetANNIndex(i_map); + vector> input_map = input_output_map->GetInputMapping(i_map); + for(size_t jInput=0; jInput 0){ + string message{"Inputs "}; + for(size_t iVar=0; iVar &output_names, IOMap * input_output_map) const { + /* Check wether all output variables are in the loaded MLPs */ + + vector missing_outputs; + bool outputs_are_present{true}; + /* Looping over the target outputs */ + for(size_t iOutput=0; iOutputGetNANNs(); i_map++){ + size_t i_ANN = input_output_map->GetANNIndex(i_map); + vector> output_map = input_output_map->GetOutputMapping(i_map); + + /* Looping over the outputs of the output map of the current ANN */ + for(size_t jOutput=0; jOutput 0){ + string message{"Outputs "}; + for(size_t iVar=0; iVar. + */ +#include "../../../include/numerics/multilayer_perceptron/NeuralNetwork.hpp" +#include "../../../include/numerics/multilayer_perceptron/Layer.hpp" +#include +#include "../../../include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp" +#include "../../../Common/include/toolboxes/geometry_toolbox.hpp" +using namespace std; + + +void NeuralNetwork::predict(vector &inputs, vector&outputs, su2double**doutputs_dinputs){ + su2double x, x_norm, y, y_norm, tanx; + size_t iNeuron, jNeuron, iLayer, nNeurons_current, nNeurons_previous; + bool same_point{true}; + for(iNeuron=0; iNeurongetNNeurons(); iNeuron++){ + x_norm = (inputs[iNeuron] - input_norm[iNeuron].first)/(input_norm[iNeuron].second - input_norm[iNeuron].first); + if(abs(x_norm - inputLayer->getValue(iNeuron)) > 0) same_point = false; + inputLayer->setValue(iNeuron, x_norm); + } + if(!same_point){ + for(iLayer=1; iLayergetNNeurons(); + nNeurons_previous = total_layers[iLayer - 1]->getNNeurons(); + + + switch (activation_function_types[iLayer]) + { + case ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE: + for(iNeuron=0; iNeuron 0 ? x : tanh(x); + total_layers[iLayer]->setValue(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::ELU: + for(iNeuron=0; iNeuron 0 ? x : (exp(x) - 1); + total_layers[iLayer]->setValue(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::LINEAR: + for(iNeuron=0; iNeuronsetValue(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::RELU: + for(iNeuron=0; iNeuron 0.0 ? x : 0.0; + total_layers[iLayer]->setValue(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::NONE: + for(iNeuron=0; iNeuronsetValue(iNeuron, y); + } + break; + default: + break; + } + + } + } + for(iNeuron=0; iNeurongetNNeurons(); iNeuron++){ + y_norm = outputLayer->getValue(iNeuron); + y = y_norm*(output_norm[iNeuron].second - output_norm[iNeuron].first) + output_norm[iNeuron].first; + + // Setting output value + *outputs[iNeuron] = y; + } +} +// void NeuralNetwork::predict(vector &inputs, vector&outputs, su2double**doutputs_dinputs){ +// // Evaluate the MLP based on the inputs. In case a pointer to the output gradient is provided, the partial +// // derivatives of the outputs with respect to the inputs are evaluated as well. + +// su2double *y_values_old, // Perceptron values of the previous layer +// *y_values_new, // Perceptron values of the current layer +// **dy_dx_old, // Derivatives of the previous layer +// **dy_dx_new; // Derivatives of the current layer + +// su2double x, // Perceptron input +// x_norm, // Normalized MLP input +// y, // Perceptron output +// y_norm; // Normalized MLP output + +// size_t n_inputs{inputLayer->getNNeurons()}; // Number of inputs + +// bool compute_gradient = (doutputs_dinputs != nullptr); // Gradient computation option + +// // Stepping though the MLP layers, communicating the output from the previous layer to the next. +// // TODO: make this recursive to increase performance and code simplification +// for(size_t iLayer=0; iLayer < total_layers.size(); iLayer++){ + +// // In case the input layer is called, input normalization is applied. +// if(total_layers.at(iLayer)->isInput()){ +// // Generating an array for the input layer preceptron values. +// y_values_old = new su2double[total_layers.at(iLayer)->getNNeurons()]; + +// if(compute_gradient) +// dy_dx_old = new su2double*[total_layers.at(iLayer)->getNNeurons()]; + +// for(size_t iNeuron=0; iNeurongetNNeurons(); iNeuron++){ +// // Normalizing the inputs +// x_norm = (inputs[iNeuron] - input_norm.at(iNeuron).first)/(input_norm.at(iNeuron).second - input_norm.at(iNeuron).first); + +// // Set perceptron values of input layer. +// total_layers.at(iLayer)->setValue(iNeuron, x_norm); +// y_values_old[iNeuron] = x_norm; + +// if(compute_gradient){ +// dy_dx_old[iNeuron] = new su2double[n_inputs]; +// for(size_t jInput=0; jInputgetNNeurons()]; + +// if(compute_gradient) +// dy_dx_new = new su2double*[total_layers.at(iLayer)->getNNeurons()]; + +// for(size_t iNeuron=0; iNeurongetNNeurons(); iNeuron++){ +// // Multiplying the weights and output values of the previous layer to generate the current perceptron input +// x = GeometryToolbox::DotProduct(total_layers.at(iLayer-1)->getNNeurons(), y_values_old, weights_mat[iLayer-1][iNeuron]); + +// // Generating the perceptron output +// y = total_layers.at(iLayer)->activation_function(iNeuron, x); + +// // Storing perceptron output +// total_layers.at(iLayer)->setValue(iNeuron, y); +// y_values_new[iNeuron] = y; + +// if(compute_gradient){ +// dy_dx_new[iNeuron] = new su2double[n_inputs]; +// for(size_t jInput=0; jInput < n_inputs; jInput++) dy_dx_new[iNeuron][jInput] = 0.0; + +// for(size_t jNeuron=0; jNeurongetNNeurons(); jNeuron++){ +// for(size_t jInput=0; jInputgetNNeurons(); jInput++){ +// dy_dx_new[iNeuron][jInput] += total_layers.at(iLayer)->getdYdX(iNeuron) * weights_mat[iLayer-1][iNeuron][jNeuron] * dy_dx_old[jNeuron][jInput]; +// } +// } +// } + +// } +// // Resetting pointer to previous layer outputs +// delete y_values_old; +// y_values_old = y_values_new; + +// if(compute_gradient){ +// for(size_t jNeuron=0; jNeurongetNNeurons(); jNeuron++){ +// delete [] dy_dx_old[jNeuron]; +// } +// delete [] dy_dx_old; +// dy_dx_old = dy_dx_new; +// } +// } +// } +// delete y_values_old; + +// // Dimensionalize the MLP outputs and gradients +// for(size_t iOutput=0; iOutputgetNNeurons(); iOutput++){ + +// // Dimensionalize the outputs +// y_norm = outputLayer->getValue(iOutput); +// y = y_norm*(output_norm.at(iOutput).second - output_norm.at(iOutput).first) + output_norm.at(iOutput).first; + +// // Setting output value +// *outputs.at(iOutput) = y; + +// if(compute_gradient){ +// for(size_t iInput=0; iInputsetInput(true); + input_norm.resize(n_neurons); +} + +void NeuralNetwork::defineOutputLayer(unsigned long n_neurons){ + //cout << "Creating an output layer with " << n_neurons << " neurons. "<< endl; + outputLayer = new Layer(n_neurons); + output_norm.resize(n_neurons); +} + +void NeuralNetwork::push_hidden_layer(unsigned long n_neurons){ + Layer *newLayer = new Layer(n_neurons); + //cout << "Creating a hidden layer with " << n_neurons << " neurons. "<< endl; + hiddenLayers.push_back(newLayer); + n_hidden_layers ++; +} + +void NeuralNetwork::sizeWeights(){ + unsigned long i_layer{0}; + weights.resize(n_hidden_layers + 1); + weights.at(i_layer).resize(inputLayer->getNNeurons()); + Layer * previouslayer = inputLayer; + + if(n_hidden_layers != 0){ + for(size_t i_hidden_layer=0; i_hidden_layer < n_hidden_layers; i_hidden_layer++){ + for(size_t i_neuron=0; i_neuron < previouslayer->getNNeurons(); i_neuron++){ + weights.at(i_layer).at(i_neuron).resize(hiddenLayers.at(i_hidden_layer)->getNNeurons()); + } + previouslayer = hiddenLayers.at(i_hidden_layer); + i_layer ++; + weights.at(i_layer).resize(previouslayer->getNNeurons()); + } + } + for(size_t i_neuron=0; i_neuron < previouslayer->getNNeurons(); i_neuron++){ + weights.at(i_layer).at(i_neuron).resize(outputLayer->getNNeurons()); + } + + total_layers.resize(n_hidden_layers + 2); + total_layers.at(0) = inputLayer; + for(size_t iLayer=0; iLayergetNNeurons(), inputLayer->getNNeurons()); + for(size_t iLayer=1; iLayergetNNeurons(), hiddenLayers[iLayer-1]->getNNeurons()); + } + weights_mat[n_hidden_layers].resize(outputLayer->getNNeurons(), hiddenLayers[n_hidden_layers-1]->getNNeurons()); + +} + +void NeuralNetwork::setWeight(unsigned long i_layer, unsigned long i_neuron, unsigned long j_neuron, su2double value){ + //weights.at(i_layer).at(i_neuron).at(j_neuron) = value; + weights_mat[i_layer][j_neuron][i_neuron] = value; +} +void NeuralNetwork::displayNetwork(){ + cout << "Input layer: " << inputLayer->getNNeurons() << " neurons, Activation Function: " << inputLayer->getActivationType() << endl; + for(size_t i=0; igetNNeurons(); i++){ + for(size_t j=0; jgetNNeurons(); j++){ + cout << weights_mat[0][i][j] << " "; + } + su2double thingy[] = {1, 1, 1}; + cout << GeometryToolbox::DotProduct(inputLayer->getNNeurons(), weights_mat[0][i], thingy) << endl; + cout << endl; + } + for(size_t i_layer=0; i_layer < hiddenLayers.size(); i_layer++){ + cout << "Hidden layer " << i_layer + 1 << ": " << hiddenLayers.at(i_layer)->getNNeurons() << " neurons, Activation Function: " << hiddenLayers.at(i_layer) ->getActivationType() << endl; + for(size_t i=0; igetNNeurons() <<" neurons, Activation Function: " << outputLayer->getActivationType() << endl; +} + +void NeuralNetwork::setActivationFunction(unsigned long i_layer, string input) +{ + if(input.compare("linear") == 0){ + //activation_functions[i_layer] = new Linear(); + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::LINEAR; + return; + } + if(input.compare("relu") == 0){ + //activation_functions[i_layer] = new Relu(); + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::RELU; + return; + } + if((input.compare("smooth_slope") == 0)){ + //activation_functions[i_layer] = new SmoothSlope(); + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE; + return; + } + if((input.compare("elu") == 0)){ + //activation_functions[i_layer] = new SmoothSlope(); + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::ELU; + return; + } + if(input.compare("none") == 0){ + //activation_functions[i_layer] = new None(); + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::NONE; + return; + } + //total_layers.at(i_layer)->setActivationFunction(input); + return; +} diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/Neuron.cpp b/SU2_CFD/src/numerics/multilayer_perceptron/Neuron.cpp new file mode 100644 index 00000000000..4fbef6a462e --- /dev/null +++ b/SU2_CFD/src/numerics/multilayer_perceptron/Neuron.cpp @@ -0,0 +1,114 @@ +/*! + * \file Neuron.cpp + * \brief Implementation of the neuron class to be used within the + * Layer class as a part of the NeuralNetwork class. + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#include "../../../include/numerics/multilayer_perceptron/Neuron.hpp" +#include +#include +#include + +using namespace std; +// Neuron::Neuron() +// { +// } + +// su2double Neuron::activation_function(su2double x) +// { +// x += bias; +// su2double tanx; +// switch(ActivationFunction){ +// case ENUM_ACTIVATION_FUNCTION::LINEAR: +// dy_dx = 1; +// return x; +// break; +// case ENUM_ACTIVATION_FUNCTION::RELU: +// if(x > 0.0){ +// dy_dx = 1.0; +// return x; +// }else{ +// dy_dx = 0.0; +// return 0.0; +// } +// break; +// case ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE: +// tanx = tanh(x); +// if(tanx > x){ +// dy_dx = 4.0 / pow((exp(-x) + exp(x)), 2); +// return tanx; +// }else{ +// dy_dx = 1.0; +// return x; +// } +// break; +// default: +// SU2_MPI::Error(string("Unknown activation function type: ")+activation_type, +// CURRENT_FUNCTION); +// return 0.0; +// break; +// } +// // if(activation_type.compare("smooth_slope") == 0){ +// // su2double tanx = tanh(x); +// // if(tanx > x){ +// // dy_dx = 4.0 / pow((exp(-x) + exp(x)), 2); +// // return tanx; +// // }else{ +// // dy_dx = 1.0; +// // return x; +// // } + +// // } +// // if(activation_type.compare("linear") == 0){ +// // dy_dx = 1.0; +// // return x; +// // } +// // if(activation_type.compare("relu") == 0){ +// // su2double zero{0.0}; +// // if(x > zero){ +// // dy_dx = 1.0; +// // return x; +// // }else{ +// // dy_dx = 0.0; +// // return zero; +// // } +// // } + +// // SU2_MPI::Error(string("Unknown activation function type: ")+activation_type, +// // CURRENT_FUNCTION); + +// // return x; +// } + +// void Neuron::setFunctionType(string input){ +// activation_type = input; + +// if(input.compare("smooth_slope") == 0) ActivationFunction = ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE; return; + +// if(input.compare("linear") == 0) ActivationFunction = ENUM_ACTIVATION_FUNCTION::LINEAR; return; + +// if(input.compare("relu") == 0) ActivationFunction = ENUM_ACTIVATION_FUNCTION::RELU; return; + +// if(input.compare("none") == 0) ActivationFunction = ENUM_ACTIVATION_FUNCTION::NONE; return; +// } \ No newline at end of file diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp b/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp new file mode 100644 index 00000000000..5c137397bb8 --- /dev/null +++ b/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp @@ -0,0 +1,151 @@ +/*! + * \file ReadNeuralNetwork.cpp + * \brief Implementation of the reader class to read .mlp input files + * used to set up multi-layer perceptrons. + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#include "../../../include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp" +using namespace std; + +ReadNeuralNetwork::ReadNeuralNetwork(string filename_in){ + filename = filename_in; +}; + +void ReadNeuralNetwork::ReadMLPFile(){ + ifstream file_stream; + file_stream.open(filename.c_str(), ifstream::in); + if (!file_stream.is_open()) { + SU2_MPI::Error(string("There is no MLP file file called ") + filename, + CURRENT_FUNCTION); + } + + string line, word; + double input_min, input_max, output_min, output_max; + + line = SkipToFlag(&file_stream, "[number of layers]"); + getline(file_stream, line); + n_layers = stoul(line); + n_neurons.resize(n_layers); + biases.resize(n_layers); + weights.resize(n_layers-1); + activation_functions.resize(n_layers); + line = SkipToFlag(&file_stream, "[neurons per layer]"); + for(size_t iLayer=0; iLayer> word; + activation_functions.at(iLayer) = word; + } + + line = SkipToFlag(&file_stream, "[input names]"); + for(size_t iInput=0; iInput < n_neurons.at(0); iInput++){ + getline(file_stream, line); + input_names.push_back(line); + } + + line = SkipToFlag(&file_stream, "[input normalization]"); + for(size_t iInput=0; iInput> word; + input_min = stold(word); + input_norm_stream >> word; + input_max = stold(word); + input_norm.at(iInput) = make_pair(input_min, input_max); + } + + line = SkipToFlag(&file_stream, "[output names]"); + for(size_t iOutput=0; iOutput < n_neurons.at(n_neurons.size()-1); iOutput++){ + getline(file_stream, line); + output_names.push_back(line); + } + + line = SkipToFlag(&file_stream, "[output normalization]"); + for(size_t iOutput=0; iOutput> word; + output_min = stold(word); + output_norm_stream >> word; + output_max = stold(word); + output_norm.at(iOutput) = make_pair(output_min, output_max); + } + + line = SkipToFlag(&file_stream, "[weights per layer]"); + for(size_t iLayer=0; iLayer> word; + weights.at(iLayer).at(iNeuron).at(jNeuron) = stold(word); + } + } + getline(file_stream, line); + } + + line = SkipToFlag(&file_stream, "[biases per layer]"); + for(size_t iLayer=0; iLayer> word; + biases.at(iLayer).at(iNeuron) = stold(word); + } + } + + + +} + +string ReadNeuralNetwork::SkipToFlag(ifstream *file_stream, string flag) { + string line; + getline(*file_stream, line); + + while (line.compare(flag) != 0 && !(*file_stream).eof()) { + getline(*file_stream, line); + } + + if ((*file_stream).eof()) + cout << "line not in file!" << endl; + + return line; +} \ No newline at end of file From f5d0267d47a8a235c4e3e026ca6faba0806507e2 Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Tue, 13 Sep 2022 11:58:30 +0200 Subject: [PATCH 030/598] Added error checking in MLP file reader and fixed bug with input-output mapping preventing single, specific outputs from MLP's to be evaluated --- .../numerics/multilayer_perceptron/IOMap.hpp | 3 + .../multilayer_perceptron/NeuralNetwork.hpp | 4 +- .../multilayer_perceptron/LookUp_ANN.cpp | 6 +- .../multilayer_perceptron/NeuralNetwork.cpp | 119 +-------- .../ReadNeuralNetwork.cpp | 234 +++++++++++++----- 5 files changed, 192 insertions(+), 174 deletions(-) diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp index 66878762edb..2e2f14b1d75 100644 --- a/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp +++ b/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp @@ -56,6 +56,9 @@ class IOMap size_t GetANNIndex(size_t i_Map){return ANN_indices[i_Map];} size_t GetInputIndex(size_t i_Map, size_t iInput){return Input_Map[i_Map][iInput].first;} size_t GetOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].first;} + size_t GetANNOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].second;} + size_t GetNMappedOutputs(size_t i_Map){return Output_Map[i_Map].size();} + vector> GetOutputMapping(size_t i_map){return Output_Map[i_map];} vector> GetInputMapping(size_t i_map){return Input_Map[i_map];} diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp index 682d673f5a6..a5cb8beeffa 100644 --- a/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp +++ b/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp @@ -98,6 +98,7 @@ class NeuralNetwork vector> input_norm; vector> output_norm; vector last_inputs; + su2double* ANN_outputs; enum ENUM_ACTIVATION_FUNCTION { NONE=0, @@ -135,7 +136,7 @@ class NeuralNetwork // su2double predict(su2double * X, size_t i_output); // void predict(vector &inputs, vector &outputs); - void predict(vector &inputs, vector &outputs, su2double**doutputs_dinputs=nullptr); + void predict(vector &inputs); //void predict_new(vector &inputs, vector &outputs, su2double**doutputs_dinputs=nullptr); @@ -151,6 +152,7 @@ class NeuralNetwork size_t GetnInputs(){return input_names.size();} size_t GetnOutputs(){return output_names.size();} + su2double GetANN_Output(size_t iOutput){return ANN_outputs[iOutput];} void SizeActivationFunctions(unsigned long n_layers){activation_function_types = new ENUM_ACTIVATION_FUNCTION[n_layers]; activation_functions.resize(4); activation_functions[ENUM_ACTIVATION_FUNCTION::LINEAR] = new Linear(); activation_functions[ENUM_ACTIVATION_FUNCTION::RELU] = new Relu(); diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/LookUp_ANN.cpp b/SU2_CFD/src/numerics/multilayer_perceptron/LookUp_ANN.cpp index 26c4c02e645..3999cf47ba7 100644 --- a/SU2_CFD/src/numerics/multilayer_perceptron/LookUp_ANN.cpp +++ b/SU2_CFD/src/numerics/multilayer_perceptron/LookUp_ANN.cpp @@ -76,8 +76,10 @@ void LookUp_ANN::Predict_ANN(IOMap *input_output_map, vector& inputs, for(size_t i_map=0; i_mapGetNANNs(); i_map++){ size_t i_ANN = input_output_map->GetANNIndex(i_map); vector ANN_inputs = input_output_map->GetANN_Inputs(i_map, inputs); - vector ANN_outputs = input_output_map->GetANN_Outputs(i_map, outputs); - NeuralNetworks[i_ANN]->predict(ANN_inputs, ANN_outputs); + NeuralNetworks[i_ANN]->predict(ANN_inputs); + for(size_t i=0; i < input_output_map->GetNMappedOutputs(i_map); i++){ + *outputs[input_output_map->GetOutputIndex(i_map, i)] = NeuralNetworks[i_ANN]->GetANN_Output(input_output_map->GetANNOutputIndex(i_map, i)); + } } } void LookUp_ANN::GenerateANN(NeuralNetwork * ANN, string fileName) diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp b/SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp index 2cfa5a165d6..2ece6768c59 100644 --- a/SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp +++ b/SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp @@ -33,7 +33,7 @@ using namespace std; -void NeuralNetwork::predict(vector &inputs, vector&outputs, su2double**doutputs_dinputs){ +void NeuralNetwork::predict(vector &inputs){ su2double x, x_norm, y, y_norm, tanx; size_t iNeuron, jNeuron, iLayer, nNeurons_current, nNeurons_previous; bool same_point{true}; @@ -95,121 +95,9 @@ void NeuralNetwork::predict(vector &inputs, vector&output y = y_norm*(output_norm[iNeuron].second - output_norm[iNeuron].first) + output_norm[iNeuron].first; // Setting output value - *outputs[iNeuron] = y; + ANN_outputs[iNeuron] = y; } } -// void NeuralNetwork::predict(vector &inputs, vector&outputs, su2double**doutputs_dinputs){ -// // Evaluate the MLP based on the inputs. In case a pointer to the output gradient is provided, the partial -// // derivatives of the outputs with respect to the inputs are evaluated as well. - -// su2double *y_values_old, // Perceptron values of the previous layer -// *y_values_new, // Perceptron values of the current layer -// **dy_dx_old, // Derivatives of the previous layer -// **dy_dx_new; // Derivatives of the current layer - -// su2double x, // Perceptron input -// x_norm, // Normalized MLP input -// y, // Perceptron output -// y_norm; // Normalized MLP output - -// size_t n_inputs{inputLayer->getNNeurons()}; // Number of inputs - -// bool compute_gradient = (doutputs_dinputs != nullptr); // Gradient computation option - -// // Stepping though the MLP layers, communicating the output from the previous layer to the next. -// // TODO: make this recursive to increase performance and code simplification -// for(size_t iLayer=0; iLayer < total_layers.size(); iLayer++){ - -// // In case the input layer is called, input normalization is applied. -// if(total_layers.at(iLayer)->isInput()){ -// // Generating an array for the input layer preceptron values. -// y_values_old = new su2double[total_layers.at(iLayer)->getNNeurons()]; - -// if(compute_gradient) -// dy_dx_old = new su2double*[total_layers.at(iLayer)->getNNeurons()]; - -// for(size_t iNeuron=0; iNeurongetNNeurons(); iNeuron++){ -// // Normalizing the inputs -// x_norm = (inputs[iNeuron] - input_norm.at(iNeuron).first)/(input_norm.at(iNeuron).second - input_norm.at(iNeuron).first); - -// // Set perceptron values of input layer. -// total_layers.at(iLayer)->setValue(iNeuron, x_norm); -// y_values_old[iNeuron] = x_norm; - -// if(compute_gradient){ -// dy_dx_old[iNeuron] = new su2double[n_inputs]; -// for(size_t jInput=0; jInputgetNNeurons()]; - -// if(compute_gradient) -// dy_dx_new = new su2double*[total_layers.at(iLayer)->getNNeurons()]; - -// for(size_t iNeuron=0; iNeurongetNNeurons(); iNeuron++){ -// // Multiplying the weights and output values of the previous layer to generate the current perceptron input -// x = GeometryToolbox::DotProduct(total_layers.at(iLayer-1)->getNNeurons(), y_values_old, weights_mat[iLayer-1][iNeuron]); - -// // Generating the perceptron output -// y = total_layers.at(iLayer)->activation_function(iNeuron, x); - -// // Storing perceptron output -// total_layers.at(iLayer)->setValue(iNeuron, y); -// y_values_new[iNeuron] = y; - -// if(compute_gradient){ -// dy_dx_new[iNeuron] = new su2double[n_inputs]; -// for(size_t jInput=0; jInput < n_inputs; jInput++) dy_dx_new[iNeuron][jInput] = 0.0; - -// for(size_t jNeuron=0; jNeurongetNNeurons(); jNeuron++){ -// for(size_t jInput=0; jInputgetNNeurons(); jInput++){ -// dy_dx_new[iNeuron][jInput] += total_layers.at(iLayer)->getdYdX(iNeuron) * weights_mat[iLayer-1][iNeuron][jNeuron] * dy_dx_old[jNeuron][jInput]; -// } -// } -// } - -// } -// // Resetting pointer to previous layer outputs -// delete y_values_old; -// y_values_old = y_values_new; - -// if(compute_gradient){ -// for(size_t jNeuron=0; jNeurongetNNeurons(); jNeuron++){ -// delete [] dy_dx_old[jNeuron]; -// } -// delete [] dy_dx_old; -// dy_dx_old = dy_dx_new; -// } -// } -// } -// delete y_values_old; - -// // Dimensionalize the MLP outputs and gradients -// for(size_t iOutput=0; iOutputgetNNeurons(); iOutput++){ - -// // Dimensionalize the outputs -// y_norm = outputLayer->getValue(iOutput); -// y = y_norm*(output_norm.at(iOutput).second - output_norm.at(iOutput).first) + output_norm.at(iOutput).first; - -// // Setting output value -// *outputs.at(iOutput) = y; - -// if(compute_gradient){ -// for(size_t iInput=0; iInputgetNNeurons(), hiddenLayers[n_hidden_layers-1]->getNNeurons()); -} + ANN_outputs = new su2double[outputLayer->getNNeurons()]; +} void NeuralNetwork::setWeight(unsigned long i_layer, unsigned long i_neuron, unsigned long j_neuron, su2double value){ //weights.at(i_layer).at(i_neuron).at(j_neuron) = value; diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp b/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp index 5c137397bb8..13d0b64a14f 100644 --- a/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp +++ b/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp @@ -42,71 +42,193 @@ void ReadNeuralNetwork::ReadMLPFile(){ string line, word; double input_min, input_max, output_min, output_max; + bool eoHeader{false}, found_layercount{false}, found_input_names{false}, found_output_names{false}; - line = SkipToFlag(&file_stream, "[number of layers]"); - getline(file_stream, line); - n_layers = stoul(line); - n_neurons.resize(n_layers); - biases.resize(n_layers); - weights.resize(n_layers-1); - activation_functions.resize(n_layers); - line = SkipToFlag(&file_stream, "[neurons per layer]"); - for(size_t iLayer=0; iLayer"); + + while(getline(file_stream, line) && !eoHeader){ + if(line.compare("[number of layers]") == 0){ + getline(file_stream, line); + n_layers = stoul(line); + n_neurons.resize(n_layers); + biases.resize(n_layers); + weights.resize(n_layers-1); + activation_functions.resize(n_layers); + + found_layercount = true; } - } - input_norm.resize(n_neurons.at(0)); - output_norm.resize(n_neurons.at(n_neurons.size()-1)); + if(line.compare("[neurons per layer]") == 0){ + if(!found_layercount){ + SU2_MPI::Error("No layer count provided before defining neuron count per layer", CURRENT_FUNCTION); + } + // Loop over layer count and size neuron count and bias count per layer accordingly + for(size_t iLayer=0; iLayer> word; - activation_functions.at(iLayer) = word; - } + // Size output normalization according to number of outputs + output_norm.resize(n_neurons.at(n_neurons.size()-1)); + // Set default output normalization + for(size_t iNeuron=0; iNeuron> word; + activation_functions.at(iLayer) = word; + } + } - line = SkipToFlag(&file_stream, "[input normalization]"); - for(size_t iInput=0; iInput> word; - input_min = stold(word); - input_norm_stream >> word; - input_max = stold(word); - input_norm.at(iInput) = make_pair(input_min, input_max); - } + if(line.compare("[input names]") == 0){ + found_input_names = true; + unsigned short j{1}; + getline(file_stream, line); + while(line.compare("") != 0){ + input_names.push_back(line); + getline(file_stream, line); + } - line = SkipToFlag(&file_stream, "[output names]"); - for(size_t iOutput=0; iOutput < n_neurons.at(n_neurons.size()-1); iOutput++){ - getline(file_stream, line); - output_names.push_back(line); - } + if(input_names.size() != n_neurons.at(0)){ + SU2_MPI::Error("Number of input variable names inconsistent with number of MLP inputs", CURRENT_FUNCTION); + } + } - line = SkipToFlag(&file_stream, "[output normalization]"); - for(size_t iOutput=0; iOutput> word; - output_min = stold(word); - output_norm_stream >> word; - output_max = stold(word); - output_norm.at(iOutput) = make_pair(output_min, output_max); + if(line.compare("[input normalization]") == 0){ + for(size_t iInput=0; iInput> word; + input_min = stold(word); + input_norm_stream >> word; + input_max = stold(word); + input_norm.at(iInput) = make_pair(input_min, input_max); + } + } + } + + if(line.compare("[output names]") == 0){ + found_output_names = true; + getline(file_stream, line); + while(line.compare("") != 0){ + output_names.push_back(line); + getline(file_stream, line); + } + + if(output_names.size() != (n_neurons.at(n_neurons.size()-1))){ + SU2_MPI::Error("Number of output variable names inconsistent with number of MLP outputs", CURRENT_FUNCTION); + } + } + + if(line.compare("[output normalization]") == 0){ + for(size_t iOutput=0; iOutput> word; + output_min = stold(word); + output_norm_stream >> word; + output_max = stold(word); + output_norm.at(iOutput) = make_pair(output_min, output_max); + } + } + } + + if(line.compare("") == 0){ + eoHeader = true; + } + } + if(!found_input_names){ + SU2_MPI::Error("No MLP input variable names provided", CURRENT_FUNCTION); } + if(!found_output_names){ + SU2_MPI::Error("No MLP output variable names provided", CURRENT_FUNCTION); + } + + + // line = SkipToFlag(&file_stream, "[number of layers]"); + // getline(file_stream, line); + // n_layers = stoul(line); + // n_neurons.resize(n_layers); + // biases.resize(n_layers); + // weights.resize(n_layers-1); + // activation_functions.resize(n_layers); + // line = SkipToFlag(&file_stream, "[neurons per layer]"); + // for(size_t iLayer=0; iLayer> word; + // activation_functions.at(iLayer) = word; + // } + + // line = SkipToFlag(&file_stream, "[input names]"); + // for(size_t iInput=0; iInput < n_neurons.at(0); iInput++){ + // getline(file_stream, line); + // input_names.push_back(line); + // } + + // line = SkipToFlag(&file_stream, "[input normalization]"); + // for(size_t iInput=0; iInput> word; + // input_min = stold(word); + // input_norm_stream >> word; + // input_max = stold(word); + // input_norm.at(iInput) = make_pair(input_min, input_max); + // } + + // line = SkipToFlag(&file_stream, "[output names]"); + // for(size_t iOutput=0; iOutput < n_neurons.at(n_neurons.size()-1); iOutput++){ + // getline(file_stream, line); + // output_names.push_back(line); + // } + + // line = SkipToFlag(&file_stream, "[output normalization]"); + // for(size_t iOutput=0; iOutput> word; + // output_min = stold(word); + // output_norm_stream >> word; + // output_max = stold(word); + // output_norm.at(iOutput) = make_pair(output_min, output_max); + // } line = SkipToFlag(&file_stream, "[weights per layer]"); for(size_t iLayer=0; iLayer Date: Thu, 15 Sep 2022 14:07:14 +0200 Subject: [PATCH 031/598] Moved MLP classes to separate library in its own namespace. Added a template CFluidModel class using MLPs for lookups as well --- .../multilayer_perceptron/CIOMap.hpp | 87 +++++++++++ .../multilayer_perceptron/CLayer.hpp | 135 ++++++++++++++++++ .../multilayer_perceptron/CLookUp_ANN.hpp | 36 ++--- .../multilayer_perceptron/CNeuralNetwork.hpp | 94 ++++-------- .../multilayer_perceptron/CNeuron.hpp | 113 +++++++++++++++ .../CReadNeuralNetwork.hpp | 16 ++- Common/lib/Makefile.am | 6 + Common/src/toolboxes/meson.build | 8 ++ .../multilayer_perceptron/CIOMap.cpp | 13 +- .../multilayer_perceptron/CLayer.cpp | 26 +--- .../multilayer_perceptron/CLookUp_ANN.cpp | 34 +++-- .../multilayer_perceptron/CNeuralNetwork.cpp | 67 +++++---- .../multilayer_perceptron/CNeuron.cpp | 33 +++++ .../CReadNeuralNetwork.cpp | 90 +++--------- SU2_CFD/include/fluid/CMLPGas_Template.hpp | 102 +++++++++++++ .../numerics/multilayer_perceptron/IOMap.hpp | 83 ----------- .../numerics/multilayer_perceptron/Layer.hpp | 63 -------- .../numerics/multilayer_perceptron/Neuron.hpp | 74 ---------- SU2_CFD/obj/Makefile.am | 7 +- SU2_CFD/src/fluid/CMLPGas_Template.cpp | 125 ++++++++++++++++ SU2_CFD/src/meson.build | 11 +- .../numerics/multilayer_perceptron/Neuron.cpp | 114 --------------- 22 files changed, 748 insertions(+), 589 deletions(-) create mode 100644 Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp create mode 100644 Common/include/toolboxes/multilayer_perceptron/CLayer.hpp rename SU2_CFD/include/numerics/multilayer_perceptron/LookUp_ANN.hpp => Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp (79%) rename SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp => Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp (59%) create mode 100644 Common/include/toolboxes/multilayer_perceptron/CNeuron.hpp rename SU2_CFD/include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp => Common/include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp (90%) rename SU2_CFD/src/numerics/multilayer_perceptron/IOMap.cpp => Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp (82%) rename SU2_CFD/src/numerics/multilayer_perceptron/Layer.cpp => Common/src/toolboxes/multilayer_perceptron/CLayer.cpp (67%) rename SU2_CFD/src/numerics/multilayer_perceptron/LookUp_ANN.cpp => Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp (87%) rename SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp => Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp (77%) create mode 100644 Common/src/toolboxes/multilayer_perceptron/CNeuron.cpp rename SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp => Common/src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp (71%) create mode 100644 SU2_CFD/include/fluid/CMLPGas_Template.hpp delete mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp delete mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/Layer.hpp delete mode 100644 SU2_CFD/include/numerics/multilayer_perceptron/Neuron.hpp create mode 100644 SU2_CFD/src/fluid/CMLPGas_Template.cpp delete mode 100644 SU2_CFD/src/numerics/multilayer_perceptron/Neuron.cpp diff --git a/Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp b/Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp new file mode 100644 index 00000000000..f0ef33fefed --- /dev/null +++ b/Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp @@ -0,0 +1,87 @@ +/*! + * \file CIOMap.hpp + * \brief Declaration of input-to-output mapping class for artifical neural networks + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include +#include +#include +#include +#include +#include +#include "../../CConfig.hpp" +#include "../../linear_algebra/blas_structure.hpp" +#include "CLookUp_ANN.hpp" + +using namespace std; +namespace MLPToolbox +{ + + class CLookUp_ANN; + + class CIOMap + { + private: + vector ANN_indices; + vector>> Input_Map; + vector>> Output_Map; + vector> input_indices; + public: + CIOMap(){}; + CIOMap(CLookUp_ANN*ANN_collection, vector &inputs, vector &outputs); + ~CIOMap(){}; + void Push_ANN_index(size_t i_ANN){ANN_indices.push_back(i_ANN);}; + void PairVariableswithANNs(CLookUp_ANN * ANN_collection, vector &inputs, vector &outputs); + size_t GetNANNs(){return ANN_indices.size();} + size_t GetANNIndex(size_t i_Map){return ANN_indices[i_Map];} + size_t GetInputIndex(size_t i_Map, size_t iInput){return Input_Map[i_Map][iInput].first;} + size_t GetOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].first;} + size_t GetANNOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].second;} + size_t GetNMappedOutputs(size_t i_Map){return Output_Map[i_Map].size();} + + vector> GetOutputMapping(size_t i_map){return Output_Map[i_map];} + vector> GetInputMapping(size_t i_map){return Input_Map[i_map];} + + vector GetANN_Inputs(size_t i_Map, vector&inputs){ + vector ANN_input; + ANN_input.resize(Input_Map[i_Map].size()); + + for(size_t iInput=0; iInput GetANN_Outputs(size_t i_Map, vector&outputs){ + vector ANN_output; + ANN_output.resize(Output_Map[i_Map].size()); + + for(size_t iOutput=0; iOutput. + */ +#pragma once + +#include +#include +#include +#include + +#include "../../CConfig.hpp" +#include "CNeuron.hpp" +#include "../../linear_algebra/blas_structure.hpp" +using namespace std; + +namespace MLPToolbox{ +class CLayer +{ +private: + unsigned long number_of_neurons; /*!< Neuron count in current layer */ + CNeuron * neurons; /*!< Array of neurons in current layer */ + bool is_input; /*!< Input layer identifyer */ + string activation_type; /*!< Activation function type applied to the current layer*/ +public: + CLayer(); + CLayer(unsigned long n_neurons); + + /*! + * \brief Set current layer neuron count + * \param[in] n_neurons - Number of neurons in this layer + */ + void setNNeurons(unsigned long n_neurons); + + /*! + * \brief Get the current layer neuron count + * \return Neuron count + */ + unsigned long getNNeurons() const {return number_of_neurons;}; + + /*! + * \brief Define current layer as input layer + * \param[in] input - input layer identifyer + */ + void setInput(bool def){is_input = def;}; + + /*! + * \brief Get input layer identifyer + * \return input layer identifyer + */ + bool isInput() const {return is_input;}; + + /*! + * \brief Set the output value of a neuron in the layer + * \param[in] i_neuron - Neuron index + * \param[in] output_value - Activation function output + */ + void setOutput(size_t i_neuron, su2double value){neurons[i_neuron].setOutput(value);} + + /*! + * \brief Get the output value of a neuron in the layer + * \param[in] i_neuron - Neuron index + * \return Neuron output value + */ + su2double getOutput(size_t i_neuron) const {return neurons[i_neuron].getOutput();} + + /*! + * \brief Set the input value of a neuron in the layer + * \param[in] i_neuron - Neuron index + * \param[in] input_value - Activation function input + */ + void setInput(size_t i_neuron, su2double value){neurons[i_neuron].setInput(value);} + + /*! + * \brief Get the input value of a neuron in the layer + * \param[in] i_neuron - Neuron index + * \return Neuron input value + */ + su2double getInput(size_t i_neuron) const {return neurons[i_neuron].getInput();} + + /*! + * \brief Set the bias value of a neuron in the layer + * \param[in] i_neuron - Neuron index + * \param[in] bias_value - Bias value + */ + void setBias(size_t i_neuron, su2double value){neurons[i_neuron].setBias(value);} + + /*! + * \brief Get the bias value of a neuron in the layer + * \param[in] i_neuron - Neuron index + * \return Neuron bias value + */ + su2double getBias(size_t i_neuron){return neurons[i_neuron].getBias();} + + /*! + * \brief Get the output-input gradient of a neuron in the layer + * \param[in] i_neuron - Neuron index + * \return Gradient of neuron output wrt input + */ + su2double getdYdX(size_t i_neuron){return neurons[i_neuron].getGradient();} + + /*! + * \brief Get the activation function name applied to this layer + * \return name of the activation function + */ + string getActivationType(){return activation_type;} + + ~CLayer(){ + delete [] neurons; + }; +}; + +} diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/LookUp_ANN.hpp b/Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp similarity index 79% rename from SU2_CFD/include/numerics/multilayer_perceptron/LookUp_ANN.hpp rename to Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp index 9cab1a9204c..3b7a0baaf02 100644 --- a/SU2_CFD/include/numerics/multilayer_perceptron/LookUp_ANN.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp @@ -1,5 +1,5 @@ /*! - * \file LookUp_ANN.hpp + * \file CLookUp_ANN.hpp * \brief Declaration of artificial neural network interpolation class * \author E. Bunschoten * \version 7.4.0 "Blackbird" @@ -33,19 +33,21 @@ #include #include #include -#include "../../../../Common/include/CConfig.hpp" -#include "../../../../Common/include/linear_algebra/blas_structure.hpp" -#include "NeuralNetwork.hpp" -#include "IOMap.hpp" +#include "../../CConfig.hpp" +#include "../../linear_algebra/blas_structure.hpp" +#include "CNeuralNetwork.hpp" +#include "CIOMap.hpp" using namespace std; -class IOMap; -class LookUp_ANN +namespace MLPToolbox{ +class CIOMap; + +class CLookUp_ANN { private: int rank{0}; - vector NeuralNetworks; /*!< Vector containing all loaded neural networks. */ + vector NeuralNetworks; /*!< Vector containing all loaded neural networks. */ vector ANN_filenames; /*!< Filenames containing ANN architecture information. */ @@ -64,7 +66,7 @@ class LookUp_ANN * \param[in] ANN - pointer to target NeuralNetwork class * \param[in] filename - filename containing ANN architecture information */ - void GenerateANN(NeuralNetwork*ANN, string filename); + void GenerateANN(CNeuralNetwork*ANN, string filename); /*! * \brief Read ANN architecture input file @@ -78,7 +80,7 @@ class LookUp_ANN * \brief ANN collection class constructor * \param[in] filename - filename containing list of ANN input files */ - LookUp_ANN(string fileName); + CLookUp_ANN(string fileName); /*! * \brief Evaluate loaded ANNs for given inputs and outputs @@ -86,9 +88,9 @@ class LookUp_ANN * \param[in] inputs - input values * \param[in] outputs - pointers to output variables */ - void Predict_ANN(IOMap *input_output_map, vector &inputs, vector &outputs); + void Predict_ANN(CIOMap *input_output_map, vector &inputs, vector &outputs); - ~LookUp_ANN(){for(size_t i_ANN=0; i_ANN &output_names, IOMap *input_output_map) const; + bool Check_Duplicate_Outputs(vector &output_names, CIOMap *input_output_map) const; /*! * \brief Check if all output variables are present in the loaded ANNs * \param[in] output_names - output variable names to check * \param[in] input_output_map - pointer to input-output map to be checked */ - bool Check_Use_of_Outputs(vector &output_names, IOMap *input_output_map) const; + bool Check_Use_of_Outputs(vector &output_names, CIOMap *input_output_map) const; /*! * \brief Check if all input variables are present in the loaded ANNs * \param[in] input_names - input variable names to check * \param[in] input_output_map - pointer to input-output map to be checked */ - bool Check_Use_of_Inputs(vector &input_names, IOMap *input_output_map) const; + bool Check_Use_of_Inputs(vector &input_names, CIOMap *input_output_map) const; /*! * \brief Map variable names to ANN inputs or outputs @@ -129,3 +131,5 @@ class LookUp_ANN }; +} + diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp similarity index 59% rename from SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp rename to Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp index a5cb8beeffa..6e54cd363a8 100644 --- a/SU2_CFD/include/numerics/multilayer_perceptron/NeuralNetwork.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp @@ -1,5 +1,5 @@ /*! - * \file NeuralNetwork.hpp + * \file CNeuralNetwork.hpp * \brief Declaration of the neural network class * \author E. Bunschoten * \version 7.4.0 "Blackbird" @@ -33,71 +33,34 @@ #include #include -#include "../../../../Common/include/CConfig.hpp" -#include "../../../../Common/include/linear_algebra/blas_structure.hpp" -#include "Layer.hpp" +#include "../../CConfig.hpp" +#include "../../linear_algebra/blas_structure.hpp" +#include "CLayer.hpp" using namespace std; -class Activation_Function { - private: - public: - Activation_Function(){}; - ~Activation_Function(){}; - inline virtual su2double run_activation_function(su2double x) {return 0.0;} -}; - -class Linear : public Activation_Function { - private: - public: - Linear() : Activation_Function() {}; - ~Linear(){}; - su2double run_activation_function(su2double x) final {return x;} -}; - -class Relu : public Activation_Function { - private: - public: - Relu() : Activation_Function() {}; - ~Relu(){}; - su2double run_activation_function(su2double x) final {return max(0.0, x);} -}; - -class SmoothSlope : public Activation_Function { - private: - su2double tanhx; - public: - SmoothSlope() : Activation_Function() {}; - ~SmoothSlope(){}; - su2double run_activation_function(su2double x) final {tanhx = tanh(x); return max(tanhx, x);} -}; - -class None : public Activation_Function { - private: - public: - None() : Activation_Function() {}; - ~None(){}; - su2double run_activation_function(su2double x) final {return 0.0;} -}; - -class NeuralNetwork +namespace MLPToolbox{ +class CNeuralNetwork { private: - vector input_names; - vector output_names; + vector input_names, + output_names; unsigned long n_hidden_layers; - Layer *inputLayer; - Layer *outputLayer; - vector< Layer *> hiddenLayers; - vectortotal_layers; + + CLayer *inputLayer, + *outputLayer; + + vector hiddenLayers, + total_layers; vector>> weights; vector weights_mat; vector> values; - vector> input_norm; - vector> output_norm; + vector> input_norm, + output_norm; vector last_inputs; + su2double* ANN_outputs; enum ENUM_ACTIVATION_FUNCTION { @@ -108,15 +71,14 @@ class NeuralNetwork ELU = 4 }; ENUM_ACTIVATION_FUNCTION * activation_function_types; - vector activation_functions; - Activation_Function* current_activation_function; - //Activation_Function *activation_functions; + public: - NeuralNetwork(); - ~NeuralNetwork(){ + CNeuralNetwork(); + ~CNeuralNetwork(){ for(size_t i=0; igetNNeurons();} unsigned long getNNeurons(unsigned long iLayer, unsigned long iNeuron){return weights.at(iLayer).at(iNeuron).size();} - // su2double predict(su2double * X, size_t i_output); - // void predict(vector &inputs, vector &outputs); void predict(vector &inputs); - //void predict_new(vector &inputs, vector &outputs, su2double**doutputs_dinputs=nullptr); void SetInputNorm(unsigned long iInput, su2double input_min, su2double input_max){input_norm.at(iInput) = make_pair(input_min, input_max);} void SetOutputNorm(unsigned long iOutput, su2double output_min, su2double output_max){output_norm.at(iOutput) = make_pair(output_min, output_max);} @@ -153,10 +112,7 @@ class NeuralNetwork size_t GetnOutputs(){return output_names.size();} su2double GetANN_Output(size_t iOutput){return ANN_outputs[iOutput];} - void SizeActivationFunctions(unsigned long n_layers){activation_function_types = new ENUM_ACTIVATION_FUNCTION[n_layers]; activation_functions.resize(4); - activation_functions[ENUM_ACTIVATION_FUNCTION::LINEAR] = new Linear(); - activation_functions[ENUM_ACTIVATION_FUNCTION::RELU] = new Relu(); - activation_functions[ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE] = new SmoothSlope(); + void SizeActivationFunctions(unsigned long n_layers){activation_function_types = new ENUM_ACTIVATION_FUNCTION[n_layers]; } su2double ComputeX(size_t iLayer, size_t iNeuron){ @@ -164,13 +120,13 @@ class NeuralNetwork x = total_layers[iLayer]->getBias(iNeuron); size_t nNeurons_previous = total_layers[iLayer - 1]->getNNeurons(); for(size_t jNeuron=0; jNeurongetValue(jNeuron); + x += weights_mat[iLayer - 1][iNeuron][jNeuron] * total_layers[iLayer-1]->getOutput(jNeuron); } return x; } - // su2double run_activation_function(unsigned long iLayer, su2double x){return activation_functions[iLayer]->run_activation_function(x);} - //void SetActivationFunction(size_t iLayer, unsigned long function_index){activation_functions[iLayer] = ENUM_ACTIVATION_FUNCTION(function_index);} }; +} + diff --git a/Common/include/toolboxes/multilayer_perceptron/CNeuron.hpp b/Common/include/toolboxes/multilayer_perceptron/CNeuron.hpp new file mode 100644 index 00000000000..fed140d4457 --- /dev/null +++ b/Common/include/toolboxes/multilayer_perceptron/CNeuron.hpp @@ -0,0 +1,113 @@ +/*! + * \file CNeuron.hpp + * \brief Declaration of artificial neural network perceptron class + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#pragma once + +#include +#include +#include +#include + +#include "../../CConfig.hpp" +#include "../../linear_algebra/blas_structure.hpp" + +using namespace std; +namespace MLPToolbox{ +class CNeuron +{ +private: + unsigned long i_neuron; /*!< Neuron identification number */ + su2double output{0}, /*!< Output value of the current neuron */ + input{0}, /*!< Input value of the current neuron */ + doutput_dinput{0}, /*!< Gradient of output with respect to input */ + bias{0}; /*!< Bias value at current neuron */ + +public: + CNeuron(){}; + + /*! + * \brief Set neuron identification number + * \param[in] input - Identification number + */ + void setNumber(unsigned long input){i_neuron = input;} + + /*! + * \brief Get neuron identification number + * \return Identification number + */ + unsigned long getNumber() const {return i_neuron;} + + /*! + * \brief Set neuron output value + * \param[in] input - activation function output value + */ + void setOutput(su2double input){output = input;} + + /*! + * \brief Get neuron output value + * \return Output value + */ + su2double getOutput() const {return output;} + + /*! + * \brief Set neuron input value + * \param[in] input - activation function input value + */ + void setInput(su2double x){input = x;} + + /*! + * \brief Get neuron input value + * \return input value + */ + su2double getInput() const {return input;} + + /*! + * \brief Set neuron bias + * \param[in] input - bias value + */ + void setBias(su2double input){bias = input;} + + /*! + * \brief Get neuron bias value + * \return bias value + */ + su2double getBias() const {return bias;} + + /*! + * \brief Set neuron output gradient with respect to its input value + * \param[in] input - Derivative of activation function with respect to input + */ + void setGradient(su2double input){doutput_dinput = input;} + + /*! + * \brief Get neuron output gradient with respect to input value + * \return output gradient wrt input value + */ + su2double getGradient() const {return doutput_dinput;} +}; + +} + diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp b/Common/include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp similarity index 90% rename from SU2_CFD/include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp rename to Common/include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp index e33d267cbe2..d471e42d939 100644 --- a/SU2_CFD/include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp @@ -1,5 +1,5 @@ /*! - * \file ReadNeuralNetwork.hpp + * \file CReadNeuralNetwork.hpp * \brief Declaration of MLP input file reader class * \author E. Bunschoten * \version 7.4.0 "Blackbird" @@ -31,11 +31,12 @@ #include #include -#include "../../../../Common/include/CConfig.hpp" -#include "../../../../Common/include/linear_algebra/blas_structure.hpp" +#include "../../CConfig.hpp" +#include "../../linear_algebra/blas_structure.hpp" using namespace std; -class ReadNeuralNetwork { +namespace MLPToolbox{ +class CReadNeuralNetwork { private: vector input_names; vector output_names; @@ -51,7 +52,7 @@ class ReadNeuralNetwork { vector> output_norm; public: - ReadNeuralNetwork(string filename_in); + CReadNeuralNetwork(string filename_in); void ReadMLPFile(); string SkipToFlag(ifstream *file_stream, string flag); @@ -70,5 +71,6 @@ class ReadNeuralNetwork { string GetInputName(size_t iInput){return input_names.at(iInput);} string GetOutputName(size_t iOutput){return output_names.at(iOutput);} - ~ReadNeuralNetwork(){}; -}; \ No newline at end of file + ~CReadNeuralNetwork(){}; +}; +} diff --git a/Common/lib/Makefile.am b/Common/lib/Makefile.am index af2046cf826..c938e931966 100644 --- a/Common/lib/Makefile.am +++ b/Common/lib/Makefile.am @@ -128,6 +128,12 @@ lib_sources = \ ../src/toolboxes/MMS/CRinglebSolution.cpp \ ../src/toolboxes/MMS/CTGVSolution.cpp \ ../src/toolboxes/MMS/CUserDefinedSolution.cpp \ + ../src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp\ + ../src/toolboxes/multilayer_perceptron/CIOMap.cpp\ + ../src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp\ + ../src/toolboxes/multilayer_perceptron/CLayer.cpp\ + ../src/toolboxes/multilayer_perceptron/CNeuron.cpp\ + ../src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp\ ../src/linear_algebra/CSysVector.cpp \ ../src/linear_algebra/CSysMatrix.cpp \ ../src/linear_algebra/CSysSolve.cpp \ diff --git a/Common/src/toolboxes/meson.build b/Common/src/toolboxes/meson.build index d95ffad5992..d6441390a57 100644 --- a/Common/src/toolboxes/meson.build +++ b/Common/src/toolboxes/meson.build @@ -5,3 +5,11 @@ common_src += files(['CLinearPartitioner.cpp', 'CSymmetricMatrix.cpp']) subdir('MMS') + +common_src += files(['multilayer_perceptron/CLookUp_ANN.cpp', + 'multilayer_perceptron/CIOMap.cpp', + 'multilayer_perceptron/CNeuralNetwork.cpp', + 'multilayer_perceptron/CLayer.cpp', + 'multilayer_perceptron/CNeuron.cpp', + 'multilayer_perceptron/CReadNeuralNetwork.cpp']) + diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/IOMap.cpp b/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp similarity index 82% rename from SU2_CFD/src/numerics/multilayer_perceptron/IOMap.cpp rename to Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp index 82d2faf1965..d6bba0ce8b2 100644 --- a/SU2_CFD/src/numerics/multilayer_perceptron/IOMap.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp @@ -1,5 +1,5 @@ /*! - * \file IOMap.cpp + * \file CIOMap.cpp * \brief Implementation of the input-output mapping class for the * use of multi-layer perceptrons in SU2 * \author E. Bunschoten @@ -25,14 +25,14 @@ * You should have received a copy of the GNU Lesser General Public * License along with SU2. If not, see . */ -#include "../../../include/numerics/multilayer_perceptron/LookUp_ANN.hpp" -#include "../../../include/numerics/multilayer_perceptron/IOMap.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CIOMap.hpp" #include #include #include #include -IOMap::IOMap(LookUp_ANN*ANN_collection, vector &inputs, vector &outputs){ +MLPToolbox::CIOMap::CIOMap(CLookUp_ANN*ANN_collection, vector &inputs, vector &outputs){ PairVariableswithANNs(ANN_collection, inputs, outputs); if(outputs.size() > 0){ ANN_collection->Check_Use_of_Inputs(inputs, this); @@ -40,14 +40,13 @@ IOMap::IOMap(LookUp_ANN*ANN_collection, vector &inputs, vector & ANN_collection->Check_Duplicate_Outputs(outputs, this); } } -void IOMap::PairVariableswithANNs(LookUp_ANN*ANN_collection, vector &inputs, vector &outputs){ +void MLPToolbox::CIOMap::PairVariableswithANNs(CLookUp_ANN*ANN_collection, vector &inputs, vector &outputs){ - bool isInput, isOutput,input_match; + bool isInput, isOutput; for(size_t i_ANN=0; i_ANNGetNANNs(); i_ANN++){ vector> Input_Indices = ANN_collection->FindVariable_Indices(i_ANN, inputs, true); isInput = Input_Indices.size() > 0; if(isInput){ - input_match = true; vector> Output_Indices = ANN_collection->FindVariable_Indices(i_ANN, outputs, false); isOutput = Output_Indices.size() > 0; if(isOutput){ diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/Layer.cpp b/Common/src/toolboxes/multilayer_perceptron/CLayer.cpp similarity index 67% rename from SU2_CFD/src/numerics/multilayer_perceptron/Layer.cpp rename to Common/src/toolboxes/multilayer_perceptron/CLayer.cpp index b666e4547d3..74f1e702063 100644 --- a/SU2_CFD/src/numerics/multilayer_perceptron/Layer.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CLayer.cpp @@ -1,5 +1,5 @@ /*! - * \file Layer.cpp + * \file CLayer.cpp * \brief Implementation of the Layer class to be used in the NeuralNetwork * class * \author E. Bunschoten @@ -25,38 +25,26 @@ * You should have received a copy of the GNU Lesser General Public * License along with SU2. If not, see . */ -#include "../../../include/numerics/multilayer_perceptron/Layer.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CLayer.hpp" #include using namespace std; -Layer::Layer() : Layer(1) {}; +MLPToolbox::CLayer::CLayer() : CLayer(1) {}; -Layer::Layer(unsigned long n_neurons) : number_of_neurons{n_neurons}, input{false} +MLPToolbox::CLayer::CLayer(unsigned long n_neurons) : number_of_neurons{n_neurons}, is_input{false} { - neurons = new Neuron[n_neurons]; + neurons = new CNeuron[n_neurons]; for(size_t i=0; i. */ -#include "../../../include/numerics/multilayer_perceptron/LookUp_ANN.hpp" -#include "../../../include/numerics/multilayer_perceptron/IOMap.hpp" -#include "../../../include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CIOMap.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp" #include #include #include @@ -35,7 +35,7 @@ using namespace std; -LookUp_ANN::LookUp_ANN(string inputFileName) +MLPToolbox::CLookUp_ANN::CLookUp_ANN(string inputFileName) { #ifdef HAVE_MPI @@ -47,7 +47,7 @@ LookUp_ANN::LookUp_ANN(string inputFileName) ReadANNInputFile(inputFileName); for(size_t i_ANN=0; i_ANN> LookUp_ANN::FindVariable_Indices(size_t i_ANN, vector variable_names, bool input) const { +vector> MLPToolbox::CLookUp_ANN::FindVariable_Indices(size_t i_ANN, vector variable_names, bool input) const { vector> variable_indices; size_t nVar = input ? NeuralNetworks[i_ANN]->GetnInputs() : NeuralNetworks[i_ANN]->GetnOutputs(); @@ -72,7 +72,7 @@ vector> LookUp_ANN::FindVariable_Indices(size_t i_ANN, vect return variable_indices; } -void LookUp_ANN::Predict_ANN(IOMap *input_output_map, vector& inputs, vector& outputs){ +void MLPToolbox::CLookUp_ANN::Predict_ANN(CIOMap *input_output_map, vector& inputs, vector& outputs){ for(size_t i_map=0; i_mapGetNANNs(); i_map++){ size_t i_ANN = input_output_map->GetANNIndex(i_map); vector ANN_inputs = input_output_map->GetANN_Inputs(i_map, inputs); @@ -82,9 +82,9 @@ void LookUp_ANN::Predict_ANN(IOMap *input_output_map, vector& inputs, } } } -void LookUp_ANN::GenerateANN(NeuralNetwork * ANN, string fileName) +void MLPToolbox::CLookUp_ANN::GenerateANN(CNeuralNetwork * ANN, string fileName) { - ReadNeuralNetwork Reader = ReadNeuralNetwork(fileName); + CReadNeuralNetwork Reader = CReadNeuralNetwork(fileName); // Read MLP input file Reader.ReadMLPFile(); @@ -136,7 +136,8 @@ void LookUp_ANN::GenerateANN(NeuralNetwork * ANN, string fileName) } } -void LookUp_ANN::ReadANNInputFile(string inputFileName) + +void MLPToolbox::CLookUp_ANN::ReadANNInputFile(string inputFileName) { ifstream file_stream; istringstream stream_names_var; @@ -165,7 +166,7 @@ void LookUp_ANN::ReadANNInputFile(string inputFileName) } ANN_filenames.pop_back(); } -string LookUp_ANN::SkipToFlag(ifstream *file_stream, string flag) { +string MLPToolbox::CLookUp_ANN::SkipToFlag(ifstream *file_stream, string flag) { string line; getline(*file_stream, line); @@ -180,7 +181,7 @@ string LookUp_ANN::SkipToFlag(ifstream *file_stream, string flag) { } -bool LookUp_ANN::Check_Duplicate_Outputs(vector &output_names, IOMap *input_output_map) const { +bool MLPToolbox::CLookUp_ANN::Check_Duplicate_Outputs(vector &output_names, CIOMap *input_output_map) const { unsigned short n_occurances; bool duplicate{false}; vector duplicate_variables; @@ -208,14 +209,12 @@ bool LookUp_ANN::Check_Duplicate_Outputs(vector &output_names, IOMap *in } -bool LookUp_ANN::Check_Use_of_Inputs(vector &input_names, IOMap *input_output_map) const { -unsigned short n_inputs = input_names.size(); +bool MLPToolbox::CLookUp_ANN::Check_Use_of_Inputs(vector &input_names, CIOMap *input_output_map) const { vector missing_inputs; bool inputs_are_present{true}; for(size_t iInput=0; iInputGetNANNs(); i_map++){ - size_t i_ANN = input_output_map->GetANNIndex(i_map); vector> input_map = input_output_map->GetInputMapping(i_map); for(size_t jInput=0; jInput 0){ return inputs_are_present; } -bool LookUp_ANN::Check_Use_of_Outputs(vector &output_names, IOMap * input_output_map) const { +bool MLPToolbox::CLookUp_ANN::Check_Use_of_Outputs(vector &output_names, CIOMap * input_output_map) const { /* Check wether all output variables are in the loaded MLPs */ vector missing_outputs; @@ -248,7 +247,6 @@ bool LookUp_ANN::Check_Use_of_Outputs(vector &output_names, IOMap * inpu /* Looping over all the selected ANNs */ for(size_t i_map=0; i_map < input_output_map->GetNANNs(); i_map++){ - size_t i_ANN = input_output_map->GetANNIndex(i_map); vector> output_map = input_output_map->GetOutputMapping(i_map); /* Looping over the outputs of the output map of the current ANN */ diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp b/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp similarity index 77% rename from SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp rename to Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp index 2ece6768c59..b4344662613 100644 --- a/SU2_CFD/src/numerics/multilayer_perceptron/NeuralNetwork.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp @@ -1,5 +1,5 @@ /*! - * \file NeuralNetwork.cpp + * \file CNeuralNetwork.cpp * \brief Implementation of the NeuralNetwork class to be used * for evaluation of multi-layer perceptrons. * \author E. Bunschoten @@ -25,63 +25,65 @@ * You should have received a copy of the GNU Lesser General Public * License along with SU2. If not, see . */ -#include "../../../include/numerics/multilayer_perceptron/NeuralNetwork.hpp" -#include "../../../include/numerics/multilayer_perceptron/Layer.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CLayer.hpp" #include -#include "../../../include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp" -#include "../../../Common/include/toolboxes/geometry_toolbox.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp" using namespace std; -void NeuralNetwork::predict(vector &inputs){ +void MLPToolbox::CNeuralNetwork::predict(vector &inputs){ su2double x, x_norm, y, y_norm, tanx; size_t iNeuron, jNeuron, iLayer, nNeurons_current, nNeurons_previous; bool same_point{true}; for(iNeuron=0; iNeurongetNNeurons(); iNeuron++){ x_norm = (inputs[iNeuron] - input_norm[iNeuron].first)/(input_norm[iNeuron].second - input_norm[iNeuron].first); - if(abs(x_norm - inputLayer->getValue(iNeuron)) > 0) same_point = false; - inputLayer->setValue(iNeuron, x_norm); + if(abs(x_norm - inputLayer->getOutput(iNeuron)) > 0) same_point = false; + inputLayer->setOutput(iNeuron, x_norm); } if(!same_point){ for(iLayer=1; iLayergetNNeurons(); nNeurons_previous = total_layers[iLayer - 1]->getNNeurons(); - + for(iNeuron=0; iNeuronsetInput(iNeuron, x); + } switch (activation_function_types[iLayer]) { case ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE: for(iNeuron=0; iNeurongetInput(iNeuron); y = x > 0 ? x : tanh(x); - total_layers[iLayer]->setValue(iNeuron, y); + total_layers[iLayer]->setOutput(iNeuron, y); } break; case ENUM_ACTIVATION_FUNCTION::ELU: for(iNeuron=0; iNeurongetInput(iNeuron); y = x > 0 ? x : (exp(x) - 1); - total_layers[iLayer]->setValue(iNeuron, y); + total_layers[iLayer]->setOutput(iNeuron, y); } break; case ENUM_ACTIVATION_FUNCTION::LINEAR: for(iNeuron=0; iNeurongetInput(iNeuron); y = x; - total_layers[iLayer]->setValue(iNeuron, y); + total_layers[iLayer]->setOutput(iNeuron, y); } break; case ENUM_ACTIVATION_FUNCTION::RELU: for(iNeuron=0; iNeurongetInput(iNeuron); y = x > 0.0 ? x : 0.0; - total_layers[iLayer]->setValue(iNeuron, y); + total_layers[iLayer]->setOutput(iNeuron, y); } break; case ENUM_ACTIVATION_FUNCTION::NONE: for(iNeuron=0; iNeuronsetValue(iNeuron, y); + total_layers[iLayer]->setOutput(iNeuron, y); } break; default: @@ -91,7 +93,7 @@ void NeuralNetwork::predict(vector &inputs){ } } for(iNeuron=0; iNeurongetNNeurons(); iNeuron++){ - y_norm = outputLayer->getValue(iNeuron); + y_norm = outputLayer->getOutput(iNeuron); y = y_norm*(output_norm[iNeuron].second - output_norm[iNeuron].first) + output_norm[iNeuron].first; // Setting output value @@ -99,38 +101,38 @@ void NeuralNetwork::predict(vector &inputs){ } } -NeuralNetwork::NeuralNetwork(){ +MLPToolbox::CNeuralNetwork::CNeuralNetwork(){ inputLayer = nullptr; outputLayer = nullptr; n_hidden_layers = 0; } -void NeuralNetwork::defineInputLayer(unsigned long n_neurons){ +void MLPToolbox::CNeuralNetwork::defineInputLayer(unsigned long n_neurons){ //cout << "Creating an input layer with " << n_neurons << " neurons. "<< endl; - inputLayer = new Layer(n_neurons); + inputLayer = new CLayer(n_neurons); inputLayer->setInput(true); input_norm.resize(n_neurons); } -void NeuralNetwork::defineOutputLayer(unsigned long n_neurons){ +void MLPToolbox::CNeuralNetwork::defineOutputLayer(unsigned long n_neurons){ //cout << "Creating an output layer with " << n_neurons << " neurons. "<< endl; - outputLayer = new Layer(n_neurons); + outputLayer = new CLayer(n_neurons); output_norm.resize(n_neurons); } -void NeuralNetwork::push_hidden_layer(unsigned long n_neurons){ - Layer *newLayer = new Layer(n_neurons); +void MLPToolbox::CNeuralNetwork::push_hidden_layer(unsigned long n_neurons){ + CLayer *newLayer = new CLayer(n_neurons); //cout << "Creating a hidden layer with " << n_neurons << " neurons. "<< endl; hiddenLayers.push_back(newLayer); n_hidden_layers ++; } -void NeuralNetwork::sizeWeights(){ +void MLPToolbox::CNeuralNetwork::sizeWeights(){ unsigned long i_layer{0}; weights.resize(n_hidden_layers + 1); weights.at(i_layer).resize(inputLayer->getNNeurons()); - Layer * previouslayer = inputLayer; + CLayer * previouslayer = inputLayer; if(n_hidden_layers != 0){ for(size_t i_hidden_layer=0; i_hidden_layer < n_hidden_layers; i_hidden_layer++){ @@ -163,19 +165,16 @@ void NeuralNetwork::sizeWeights(){ ANN_outputs = new su2double[outputLayer->getNNeurons()]; } -void NeuralNetwork::setWeight(unsigned long i_layer, unsigned long i_neuron, unsigned long j_neuron, su2double value){ +void MLPToolbox::CNeuralNetwork::setWeight(unsigned long i_layer, unsigned long i_neuron, unsigned long j_neuron, su2double value){ //weights.at(i_layer).at(i_neuron).at(j_neuron) = value; weights_mat[i_layer][j_neuron][i_neuron] = value; } -void NeuralNetwork::displayNetwork(){ +void MLPToolbox::CNeuralNetwork::displayNetwork(){ cout << "Input layer: " << inputLayer->getNNeurons() << " neurons, Activation Function: " << inputLayer->getActivationType() << endl; for(size_t i=0; igetNNeurons(); i++){ for(size_t j=0; jgetNNeurons(); j++){ cout << weights_mat[0][i][j] << " "; } - su2double thingy[] = {1, 1, 1}; - cout << GeometryToolbox::DotProduct(inputLayer->getNNeurons(), weights_mat[0][i], thingy) << endl; - cout << endl; } for(size_t i_layer=0; i_layer < hiddenLayers.size(); i_layer++){ cout << "Hidden layer " << i_layer + 1 << ": " << hiddenLayers.at(i_layer)->getNNeurons() << " neurons, Activation Function: " << hiddenLayers.at(i_layer) ->getActivationType() << endl; @@ -189,7 +188,7 @@ void NeuralNetwork::displayNetwork(){ cout << "Output layer: "<getNNeurons() <<" neurons, Activation Function: " << outputLayer->getActivationType() << endl; } -void NeuralNetwork::setActivationFunction(unsigned long i_layer, string input) +void MLPToolbox::CNeuralNetwork::setActivationFunction(unsigned long i_layer, string input) { if(input.compare("linear") == 0){ //activation_functions[i_layer] = new Linear(); diff --git a/Common/src/toolboxes/multilayer_perceptron/CNeuron.cpp b/Common/src/toolboxes/multilayer_perceptron/CNeuron.cpp new file mode 100644 index 00000000000..f52bdb007f2 --- /dev/null +++ b/Common/src/toolboxes/multilayer_perceptron/CNeuron.cpp @@ -0,0 +1,33 @@ +/*! + * \file CNeuron.cpp + * \brief Implementation of the neuron class to be used within the + * Layer class as a part of the NeuralNetwork class. + * \author E. Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ +#include "../../../include/toolboxes/multilayer_perceptron/CNeuron.hpp" +#include +#include +#include + +using namespace std; \ No newline at end of file diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp b/Common/src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp similarity index 71% rename from SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp rename to Common/src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp index 13d0b64a14f..8c34674e260 100644 --- a/SU2_CFD/src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp @@ -25,18 +25,18 @@ * You should have received a copy of the GNU Lesser General Public * License along with SU2. If not, see . */ -#include "../../../include/numerics/multilayer_perceptron/ReadNeuralNetwork.hpp" +#include "../../../include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp" using namespace std; -ReadNeuralNetwork::ReadNeuralNetwork(string filename_in){ +MLPToolbox::CReadNeuralNetwork::CReadNeuralNetwork(string filename_in){ filename = filename_in; }; -void ReadNeuralNetwork::ReadMLPFile(){ +void MLPToolbox::CReadNeuralNetwork::ReadMLPFile(){ ifstream file_stream; file_stream.open(filename.c_str(), ifstream::in); if (!file_stream.is_open()) { - SU2_MPI::Error(string("There is no MLP file file called ") + filename, + SU2_MPI::Error(string("There is no MLP file called ") + filename, CURRENT_FUNCTION); } @@ -44,9 +44,13 @@ void ReadNeuralNetwork::ReadMLPFile(){ double input_min, input_max, output_min, output_max; bool eoHeader{false}, found_layercount{false}, found_input_names{false}, found_output_names{false}; + /* Read general architecture information from file header */ + line = SkipToFlag(&file_stream, "
"); while(getline(file_stream, line) && !eoHeader){ + + /* Read layer count */ if(line.compare("[number of layers]") == 0){ getline(file_stream, line); n_layers = stoul(line); @@ -58,7 +62,10 @@ void ReadNeuralNetwork::ReadMLPFile(){ found_layercount = true; } + /* Set number of neurons for each layer */ if(line.compare("[neurons per layer]") == 0){ + + /* In case layer count was not yet provided, return an error */ if(!found_layercount){ SU2_MPI::Error("No layer count provided before defining neuron count per layer", CURRENT_FUNCTION); } @@ -86,6 +93,7 @@ void ReadNeuralNetwork::ReadMLPFile(){ for(size_t iNeuron=0; iNeuron> word; - // activation_functions.at(iLayer) = word; - // } - - // line = SkipToFlag(&file_stream, "[input names]"); - // for(size_t iInput=0; iInput < n_neurons.at(0); iInput++){ - // getline(file_stream, line); - // input_names.push_back(line); - // } - - // line = SkipToFlag(&file_stream, "[input normalization]"); - // for(size_t iInput=0; iInput> word; - // input_min = stold(word); - // input_norm_stream >> word; - // input_max = stold(word); - // input_norm.at(iInput) = make_pair(input_min, input_max); - // } - - // line = SkipToFlag(&file_stream, "[output names]"); - // for(size_t iOutput=0; iOutput < n_neurons.at(n_neurons.size()-1); iOutput++){ - // getline(file_stream, line); - // output_names.push_back(line); - // } - - // line = SkipToFlag(&file_stream, "[output normalization]"); - // for(size_t iOutput=0; iOutput> word; - // output_min = stold(word); - // output_norm_stream >> word; - // output_max = stold(word); - // output_norm.at(iOutput) = make_pair(output_min, output_max); - // } - + /* Read weights for each layer */ line = SkipToFlag(&file_stream, "[weights per layer]"); for(size_t iLayer=0; iLayer. + */ + +#pragma once + +#include "CFluidModel.hpp" +#include "../../../Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp" +/*! + * \class CMLPGas_Template + * \brief Template class for fluid model definition using multi-layer perceptrons for + * fluid dynamic state definition. + * \author: E.Bunschoten. + */ +class CMLPGas_Template : public CFluidModel { + protected: + su2double Gamma{0.0}; /*!< \brief Ratio of Specific Heats. */ + su2double Gamma_Minus_One{0.0}; /*!< \brief Ratio of Specific Heats Minus One. */ + su2double Gas_Constant{0.0}; /*!< \brief Gas Constant. */ + bool ComputeEntropy{true}; /*!< \brief Whether or not to compute entropy. */ + + string ann_input_filename; + MLPToolbox::CLookUp_ANN * lookup_ann; + vector mlp_input_names, lookup_names; + vector lookup_data; + + MLPToolbox::CIOMap * iomap_rhoe; + vector input_names_rhoe, + output_names_rhoe; + vector outputs_rhoe; + + MLPToolbox::CIOMap * iomap_PT; + vector input_names_PT, + output_names_PT; + vector outputs_PT; + + MLPToolbox::CIOMap * iomap_Prho; + vector input_names_Prho, + output_names_Prho; + vector outputs_Prho; + + void MapInputs_to_Outputs(); + + public: + /*! + * \brief Constructor of the class. + */ + CMLPGas_Template(su2double gamma, su2double R, bool CompEntropy = true); + + ~CMLPGas_Template(); + /*! + * \brief Set the Dimensionless State using Density and Internal Energy + * \param[in] rho - first thermodynamic variable. + * \param[in] e - second thermodynamic variable. + */ + void SetTDState_rhoe(su2double rho, su2double e) override; + + /*! + * \brief Set the Dimensionless State using Pressure and Temperature + * \param[in] P - first thermodynamic variable. + * \param[in] T - second thermodynamic variable. + */ + void SetTDState_PT(su2double P, su2double T) override; + + /*! + * \brief Set the Dimensionless State using Pressure and Density + * \param[in] P - first thermodynamic variable. + * \param[in] rho - second thermodynamic variable. + */ + void SetTDState_Prho(su2double P, su2double rho) override; + + /*! + * \brief Set the Dimensionless Internal Energy using Pressure and Density + * \param[in] P - first thermodynamic variable. + * \param[in] rho - second thermodynamic variable. + */ + void SetEnergy_Prho(su2double P, su2double rho) override; +}; diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp deleted file mode 100644 index 2e2f14b1d75..00000000000 --- a/SU2_CFD/include/numerics/multilayer_perceptron/IOMap.hpp +++ /dev/null @@ -1,83 +0,0 @@ -/*! - * \file IOMap.hpp - * \brief Declaration of input-to-output mapping class for artifical neural networks - * \author E. Bunschoten - * \version 7.4.0 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ -#pragma once - -#include -#include -#include -#include -#include -#include -#include "../../../../Common/include/CConfig.hpp" -#include "../../../../Common/include/linear_algebra/blas_structure.hpp" -#include "LookUp_ANN.hpp" - -using namespace std; -class LookUp_ANN; - -class IOMap -{ - private: - vector ANN_indices; - vector>> Input_Map; - vector>> Output_Map; - vector> input_indices; - public: - IOMap(){}; - IOMap(LookUp_ANN*ANN_collection, vector &inputs, vector &outputs); - ~IOMap(){}; - void Push_ANN_index(size_t i_ANN){ANN_indices.push_back(i_ANN);}; - void PairVariableswithANNs(LookUp_ANN * ANN_collection, vector &inputs, vector &outputs); - size_t GetNANNs(){return ANN_indices.size();} - size_t GetANNIndex(size_t i_Map){return ANN_indices[i_Map];} - size_t GetInputIndex(size_t i_Map, size_t iInput){return Input_Map[i_Map][iInput].first;} - size_t GetOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].first;} - size_t GetANNOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].second;} - size_t GetNMappedOutputs(size_t i_Map){return Output_Map[i_Map].size();} - - vector> GetOutputMapping(size_t i_map){return Output_Map[i_map];} - vector> GetInputMapping(size_t i_map){return Input_Map[i_map];} - - vector GetANN_Inputs(size_t i_Map, vector&inputs){ - vector ANN_input; - ANN_input.resize(Input_Map[i_Map].size()); - - for(size_t iInput=0; iInput GetANN_Outputs(size_t i_Map, vector&outputs){ - vector ANN_output; - ANN_output.resize(Output_Map[i_Map].size()); - - for(size_t iOutput=0; iOutput. - */ -#pragma once - -#include -#include -#include -#include - -#include "../../../../Common/include/CConfig.hpp" -#include "Neuron.hpp" -#include "../../../../Common/include/linear_algebra/blas_structure.hpp" -using namespace std; - -class Layer -{ -private: - unsigned long number_of_neurons; - Neuron * neurons; - bool input; - string activation_type; -public: - Layer(); - Layer(unsigned long n_neurons); - void setNNeurons(unsigned long n_neurons); - unsigned long getNNeurons(){return number_of_neurons;}; - void sayhi(); - void setInput(bool def){input = def;}; - bool isInput(){return input;}; - void setValue(size_t i_neuron, su2double value){neurons[i_neuron].setValue(value);} - su2double getValue(size_t i_neuron){return neurons[i_neuron].getValue();} - void setBias(size_t i_neuron, su2double value){neurons[i_neuron].setBias(value);} - su2double getBias(size_t i_neuron){return neurons[i_neuron].getBias();} - su2double getdYdX(size_t i_neuron){return neurons[i_neuron].getGradient();} - string getActivationType(){return activation_type;} - ~Layer(){ - delete [] neurons; - }; -}; diff --git a/SU2_CFD/include/numerics/multilayer_perceptron/Neuron.hpp b/SU2_CFD/include/numerics/multilayer_perceptron/Neuron.hpp deleted file mode 100644 index 12e1012b09a..00000000000 --- a/SU2_CFD/include/numerics/multilayer_perceptron/Neuron.hpp +++ /dev/null @@ -1,74 +0,0 @@ -/*! - * \file LookUp_ANN.hpp - * \brief Declaration of artificial neural network perceptron class - * \author E. Bunschoten - * \version 7.4.0 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ -#pragma once - -#include -#include -#include -#include - -#include "../../../../Common/include/CConfig.hpp" -#include "../../../../Common/include/linear_algebra/blas_structure.hpp" - -using namespace std; -class Neuron -{ -private: - string activation_type="SmoothSlope"; - unsigned long ActivationFunction{ENUM_ACTIVATION_FUNCTION::LINEAR}; - unsigned long i_neuron; - double value; - su2double dy_dx; - double bias{0}; - enum ENUM_ACTIVATION_FUNCTION { - NONE=0, - LINEAR=1, - RELU=2, - SMOOTH_SLOPE=3 - }; - -public: - Neuron(){}; - void setNumber(unsigned long input){i_neuron = input;} - unsigned long getNumber(){return i_neuron;} - //void setFunctionType(string input); - - //string getFunctionType(){return activation_type;} - //su2double activation_function(su2double x); - void setValue(su2double input){value = input;} - su2double getValue(){return value;} - - void setBias(su2double input){bias = input;} - su2double getBias(){return bias;} - - su2double getGradient(){return dy_dx;} - void setGradient(su2double input){dy_dx = input;} - //void SetActivationFunction(unsigned long input){ActivationFunction = input;} - - ~Neuron(){}; -}; - diff --git a/SU2_CFD/obj/Makefile.am b/SU2_CFD/obj/Makefile.am index 140433ec93a..361d69d5af9 100644 --- a/SU2_CFD/obj/Makefile.am +++ b/SU2_CFD/obj/Makefile.am @@ -57,6 +57,7 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/fluid/CNEMOGas.cpp \ ../src/fluid/CSU2TCLib.cpp \ ../src/fluid/CMutationTCLib.cpp \ + ../src/fluid/CMLPGas.cpp \ ../src/integration/CIntegration.cpp \ ../src/integration/CSingleGridIntegration.cpp \ ../src/integration/CMultiGridIntegration.cpp \ @@ -116,12 +117,6 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/numerics/elasticity/CFEALinearElasticity.cpp \ ../src/numerics/elasticity/CFEANonlinearElasticity.cpp \ ../src/numerics/elasticity/nonlinear_models.cpp \ - ../src/numerics/multilayer_perceptron/LookUp_ANN.cpp \ - ../src/numerics/multilayer_perceptron/IOMap.cpp \ - ../src/numerics/multilayer_perceptron/NeuralNetwork.cpp \ - ../src/numerics/multilayer_perceptron/Neuron.cpp \ - ../src/numerics/multilayer_perceptron/Layer.cpp \ - ../src/numerics/multilayer_perceptron/ReadNeuralNetwork.cpp \ ../include/numerics_simd/CNumericsSIMD.cpp \ ../src/output/filewriter/CCSVFileWriter.cpp \ ../src/output/filewriter/CSTLFileWriter.cpp \ diff --git a/SU2_CFD/src/fluid/CMLPGas_Template.cpp b/SU2_CFD/src/fluid/CMLPGas_Template.cpp new file mode 100644 index 00000000000..44e00c5ec8d --- /dev/null +++ b/SU2_CFD/src/fluid/CMLPGas_Template.cpp @@ -0,0 +1,125 @@ +/*! + * \file CMLPGas_Template.cpp + * \brief Source of the data-driven fluid model class using + * multilayer perceptrons for data regression + * \author E.Bunschoten + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../include/fluid/CMLPGas_Template.hpp" + +CMLPGas_Template::CMLPGas_Template(su2double gamma, su2double R, bool CompEntropy) : CFluidModel() { + Gamma = gamma; + Gamma_Minus_One = Gamma - 1.0; + Gas_Constant = R; + Cp = Gamma / Gamma_Minus_One * Gas_Constant; + Cv = Cp - R; + + ComputeEntropy = CompEntropy; + + /* Define a CLookUp_ANN object to allow for data regression */ + ann_input_filename = "MLP_collection.mlp"; + lookup_ann = new MLPToolbox::CLookUp_ANN(ann_input_filename); + + /* Map MLP inputs to outputs for each look-up operation*/ + MapInputs_to_Outputs(); +} + +CMLPGas_Template::~CMLPGas_Template(){ + delete iomap_rhoe; + delete iomap_PT; + delete iomap_Prho; + delete lookup_ann; +} +void CMLPGas_Template::MapInputs_to_Outputs(){ + + input_names_rhoe.push_back("rho"); + input_names_rhoe.push_back("e"); + + output_names_rhoe.push_back("Temperature"); + outputs_rhoe.push_back(&Temperature); + output_names_rhoe.push_back("Pressure"); + outputs_rhoe.push_back(&Pressure); + output_names_rhoe.push_back("SoundSpeed2"); + outputs_rhoe.push_back(&SoundSpeed2); + output_names_rhoe.push_back("dPdrho_e"); + outputs_rhoe.push_back(&dPdrho_e); + output_names_rhoe.push_back("dPde_rho"); + outputs_rhoe.push_back(&dPde_rho); + output_names_rhoe.push_back("dTdrho_e"); + outputs_rhoe.push_back(&dTdrho_e); + output_names_rhoe.push_back("dTde_rho"); + outputs_rhoe.push_back(&dTde_rho); + output_names_rhoe.push_back("Entropy"); + outputs_rhoe.push_back(&Entropy); + + iomap_rhoe = new MLPToolbox::CIOMap(lookup_ann, input_names_rhoe, output_names_rhoe); + + input_names_PT.push_back("P"); + input_names_PT.push_back("T"); + + output_names_PT.push_back("rho"); + outputs_PT.push_back(&Density); + output_names_PT.push_back("e"); + outputs_PT.push_back(&StaticEnergy); + + iomap_PT = new MLPToolbox::CIOMap(lookup_ann, input_names_PT, output_names_PT); + + input_names_Prho.push_back("P"); + input_names_Prho.push_back("rho"); + + output_names_Prho.push_back("e"); + outputs_Prho.push_back(&StaticEnergy); + iomap_Prho = new MLPToolbox::CIOMap(lookup_ann, input_names_Prho, output_names_Prho); +} + +void CMLPGas_Template::SetTDState_rhoe(su2double rho, su2double e) { + vector ann_inputs; + ann_inputs.push_back(rho); + ann_inputs.push_back(e); + lookup_ann->Predict_ANN(iomap_rhoe, ann_inputs, outputs_rhoe); +} + +void CMLPGas_Template::SetTDState_PT(su2double P, su2double T) { + vector ann_inputs; + ann_inputs.push_back(P); + ann_inputs.push_back(T); + lookup_ann->Predict_ANN(iomap_PT, ann_inputs, outputs_PT); + + SetTDState_rhoe(Density, StaticEnergy); +} + +void CMLPGas_Template::SetTDState_Prho(su2double P, su2double rho) { + vector ann_inputs; + ann_inputs.push_back(P); + ann_inputs.push_back(rho); + lookup_ann->Predict_ANN(iomap_Prho, ann_inputs, outputs_Prho); + SetTDState_rhoe(rho, StaticEnergy); +} + +void CMLPGas_Template::SetEnergy_Prho(su2double P, su2double rho) { + vector ann_inputs; + ann_inputs.push_back(P); + ann_inputs.push_back(rho); + lookup_ann->Predict_ANN(iomap_Prho, ann_inputs, outputs_Prho); +} diff --git a/SU2_CFD/src/meson.build b/SU2_CFD/src/meson.build index 6e730d80ffc..e477f80b2b6 100644 --- a/SU2_CFD/src/meson.build +++ b/SU2_CFD/src/meson.build @@ -10,7 +10,8 @@ su2_cfd_src += files(['fluid/CFluidModel.cpp', 'fluid/CVanDerWaalsGas.cpp', 'fluid/CNEMOGas.cpp', 'fluid/CMutationTCLib.cpp', - 'fluid/CSU2TCLib.cpp']) + 'fluid/CSU2TCLib.cpp', + 'fluid/CMLPGas.cpp']) su2_cfd_src += files(['output/COutputFactory.cpp', 'output/CAdjElasticityOutput.cpp', @@ -147,13 +148,7 @@ su2_cfd_src += files(['numerics/CNumerics.cpp', 'numerics/elasticity/CFEALinearElasticity.cpp', 'numerics/elasticity/CFEANonlinearElasticity.cpp', 'numerics/elasticity/nonlinear_models.cpp', - 'numerics/CGradSmoothing.cpp', - 'numerics/multilayer_perceptron/LookUp_ANN.cpp', - 'numerics/multilayer_perceptron/IOMap.cpp', - 'numerics/multilayer_perceptron/NeuralNetwork.cpp', - 'numerics/multilayer_perceptron/Layer.cpp', - 'numerics/multilayer_perceptron/Neuron.cpp', - 'numerics/multilayer_perceptron/ReadNeuralNetwork.cpp']) + 'numerics/CGradSmoothing.cpp']) su2_cfd_src += files(['../include/numerics_simd/CNumericsSIMD.cpp']) diff --git a/SU2_CFD/src/numerics/multilayer_perceptron/Neuron.cpp b/SU2_CFD/src/numerics/multilayer_perceptron/Neuron.cpp deleted file mode 100644 index 4fbef6a462e..00000000000 --- a/SU2_CFD/src/numerics/multilayer_perceptron/Neuron.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/*! - * \file Neuron.cpp - * \brief Implementation of the neuron class to be used within the - * Layer class as a part of the NeuralNetwork class. - * \author E. Bunschoten - * \version 7.4.0 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * SU2 is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with SU2. If not, see . - */ -#include "../../../include/numerics/multilayer_perceptron/Neuron.hpp" -#include -#include -#include - -using namespace std; -// Neuron::Neuron() -// { -// } - -// su2double Neuron::activation_function(su2double x) -// { -// x += bias; -// su2double tanx; -// switch(ActivationFunction){ -// case ENUM_ACTIVATION_FUNCTION::LINEAR: -// dy_dx = 1; -// return x; -// break; -// case ENUM_ACTIVATION_FUNCTION::RELU: -// if(x > 0.0){ -// dy_dx = 1.0; -// return x; -// }else{ -// dy_dx = 0.0; -// return 0.0; -// } -// break; -// case ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE: -// tanx = tanh(x); -// if(tanx > x){ -// dy_dx = 4.0 / pow((exp(-x) + exp(x)), 2); -// return tanx; -// }else{ -// dy_dx = 1.0; -// return x; -// } -// break; -// default: -// SU2_MPI::Error(string("Unknown activation function type: ")+activation_type, -// CURRENT_FUNCTION); -// return 0.0; -// break; -// } -// // if(activation_type.compare("smooth_slope") == 0){ -// // su2double tanx = tanh(x); -// // if(tanx > x){ -// // dy_dx = 4.0 / pow((exp(-x) + exp(x)), 2); -// // return tanx; -// // }else{ -// // dy_dx = 1.0; -// // return x; -// // } - -// // } -// // if(activation_type.compare("linear") == 0){ -// // dy_dx = 1.0; -// // return x; -// // } -// // if(activation_type.compare("relu") == 0){ -// // su2double zero{0.0}; -// // if(x > zero){ -// // dy_dx = 1.0; -// // return x; -// // }else{ -// // dy_dx = 0.0; -// // return zero; -// // } -// // } - -// // SU2_MPI::Error(string("Unknown activation function type: ")+activation_type, -// // CURRENT_FUNCTION); - -// // return x; -// } - -// void Neuron::setFunctionType(string input){ -// activation_type = input; - -// if(input.compare("smooth_slope") == 0) ActivationFunction = ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE; return; - -// if(input.compare("linear") == 0) ActivationFunction = ENUM_ACTIVATION_FUNCTION::LINEAR; return; - -// if(input.compare("relu") == 0) ActivationFunction = ENUM_ACTIVATION_FUNCTION::RELU; return; - -// if(input.compare("none") == 0) ActivationFunction = ENUM_ACTIVATION_FUNCTION::NONE; return; -// } \ No newline at end of file From 9e32ee0672289517ad7a3172b75e025b255eae44 Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Thu, 15 Sep 2022 14:14:51 +0200 Subject: [PATCH 032/598] fixed build bug --- SU2_CFD/obj/Makefile.am | 2 +- SU2_CFD/src/meson.build | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SU2_CFD/obj/Makefile.am b/SU2_CFD/obj/Makefile.am index 361d69d5af9..5ba91fd0d4e 100644 --- a/SU2_CFD/obj/Makefile.am +++ b/SU2_CFD/obj/Makefile.am @@ -57,7 +57,7 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/fluid/CNEMOGas.cpp \ ../src/fluid/CSU2TCLib.cpp \ ../src/fluid/CMutationTCLib.cpp \ - ../src/fluid/CMLPGas.cpp \ + ../src/fluid/CMLPGas_Template.cpp \ ../src/integration/CIntegration.cpp \ ../src/integration/CSingleGridIntegration.cpp \ ../src/integration/CMultiGridIntegration.cpp \ diff --git a/SU2_CFD/src/meson.build b/SU2_CFD/src/meson.build index e477f80b2b6..9d81ec13f71 100644 --- a/SU2_CFD/src/meson.build +++ b/SU2_CFD/src/meson.build @@ -11,7 +11,7 @@ su2_cfd_src += files(['fluid/CFluidModel.cpp', 'fluid/CNEMOGas.cpp', 'fluid/CMutationTCLib.cpp', 'fluid/CSU2TCLib.cpp', - 'fluid/CMLPGas.cpp']) + 'fluid/CMLPGas_Template.cpp']) su2_cfd_src += files(['output/COutputFactory.cpp', 'output/CAdjElasticityOutput.cpp', From b233278084092bf9fe26077b6f829cc763e7d981 Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Thu, 15 Sep 2022 14:27:38 +0200 Subject: [PATCH 033/598] Fixed unused-variable error --- Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp b/Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp index 331e08c11c7..f63e57038a7 100644 --- a/Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp @@ -188,7 +188,6 @@ bool MLPToolbox::CLookUp_ANN::Check_Duplicate_Outputs(vector &output_nam for(size_t i_Output =0; i_Output < output_names.size(); i_Output++){ n_occurances = 0; for(size_t i_map=0; i_mapGetNANNs(); i_map++){ - size_t i_ANN = input_output_map->GetANNIndex(i_map); vector> output_map = input_output_map->GetOutputMapping(i_map); for(size_t j_Output=0; j_Output Date: Thu, 15 Sep 2022 14:44:28 +0200 Subject: [PATCH 034/598] Fixed unused-variable error --- Common/src/toolboxes/multilayer_perceptron/CLayer.cpp | 2 +- .../src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Common/src/toolboxes/multilayer_perceptron/CLayer.cpp b/Common/src/toolboxes/multilayer_perceptron/CLayer.cpp index 74f1e702063..b53a397fbd5 100644 --- a/Common/src/toolboxes/multilayer_perceptron/CLayer.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CLayer.cpp @@ -29,7 +29,7 @@ #include using namespace std; -MLPToolbox::CLayer::CLayer() : CLayer(1) {}; +MLPToolbox::CLayer::CLayer() : CLayer(1) {} MLPToolbox::CLayer::CLayer(unsigned long n_neurons) : number_of_neurons{n_neurons}, is_input{false} { diff --git a/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp b/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp index b4344662613..496ac851048 100644 --- a/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp @@ -33,8 +33,8 @@ using namespace std; void MLPToolbox::CNeuralNetwork::predict(vector &inputs){ - su2double x, x_norm, y, y_norm, tanx; - size_t iNeuron, jNeuron, iLayer, nNeurons_current, nNeurons_previous; + su2double x, x_norm, y, y_norm; + size_t iNeuron, iLayer, nNeurons_current; bool same_point{true}; for(iNeuron=0; iNeurongetNNeurons(); iNeuron++){ x_norm = (inputs[iNeuron] - input_norm[iNeuron].first)/(input_norm[iNeuron].second - input_norm[iNeuron].first); @@ -44,7 +44,6 @@ void MLPToolbox::CNeuralNetwork::predict(vector &inputs){ if(!same_point){ for(iLayer=1; iLayergetNNeurons(); - nNeurons_previous = total_layers[iLayer - 1]->getNNeurons(); for(iNeuron=0; iNeuron Date: Mon, 26 Sep 2022 10:59:15 +0200 Subject: [PATCH 035/598] Added more comments to CIOMap and CLookUp_ANN classes --- .../multilayer_perceptron/CIOMap.hpp | 171 ++++++++++++++---- .../multilayer_perceptron/CLayer.hpp | 17 +- .../multilayer_perceptron/CLookUp_ANN.hpp | 38 ++-- .../multilayer_perceptron/CNeuralNetwork.hpp | 52 +++--- .../multilayer_perceptron/CNeuron.hpp | 3 +- .../CReadNeuralNetwork.hpp | 43 +++-- .../multilayer_perceptron/CIOMap.cpp | 45 +++-- .../multilayer_perceptron/CLookUp_ANN.cpp | 18 +- .../multilayer_perceptron/CNeuralNetwork.cpp | 132 +++++++++----- SU2_CFD/src/fluid/CPengRobinson.cpp | 51 ++++++ 10 files changed, 395 insertions(+), 175 deletions(-) diff --git a/Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp b/Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp index f0ef33fefed..8d0c97aa696 100644 --- a/Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp @@ -32,56 +32,157 @@ #include #include #include -#include "../../CConfig.hpp" #include "../../linear_algebra/blas_structure.hpp" #include "CLookUp_ANN.hpp" -using namespace std; namespace MLPToolbox { class CLookUp_ANN; class CIOMap + /*! + *\class CIOMap + *\brief This class is used by the CLookUp_ANN class to assign user-defined inputs + * and outputs to loaded multi-layer perceptrons. When a look-up operation is called + * with a specific CIOMap, the multi-layer perceptrons are evaluated with input and + * output variables coinciding with the desired input and output variable names. + * + * + * For example, in a custom, data-driven fluid model, MLP's are used for thermodynamic state + * definition. There are three MLP's loaded. MLP_1 predicts temperature and specific heat + * based on density and energy. MLP_2 predicts pressure and speed of sound based on density and + * energy as well. MLP_3 predicts density and energy based on pressure and temperature. + * During a certain look-up operation in the CFluidModel, temperature, speed of sound and pressure + * are needed for a given density and energy. What the CIOMap does is to point to MLP_1 for + * temperature evalutation, and to MLP_2 for pressure and speed of sound evaluation. MLP_3 is + * not considered, as the respective inputs and outputs don't match with the function call + * inputs and outputs. + * + * call variables: MLP inputs: MLP outputs: call outputs: + * + * 2--> energy --| |--> temperature --> 1 + * |--> MLP_1 --| + * 1:density 1--> density --| |--> c_p 1:temperature + * 2:energy 2:speed of sound + * 1--> density --| |--> pressure --> 3 3:pressure + * |--> MLP_2 --| + * 2--> energy --| |--> speed of sound --> 2 + * + * pressure --| |--> density + * |--> MLP_3 --| + * temperature --| |--> energy + * + * + * \author E.Bunschoten + */ + { private: - vector ANN_indices; - vector>> Input_Map; - vector>> Output_Map; - vector> input_indices; - public: - CIOMap(){}; - CIOMap(CLookUp_ANN*ANN_collection, vector &inputs, vector &outputs); - ~CIOMap(){}; - void Push_ANN_index(size_t i_ANN){ANN_indices.push_back(i_ANN);}; - void PairVariableswithANNs(CLookUp_ANN * ANN_collection, vector &inputs, vector &outputs); - size_t GetNANNs(){return ANN_indices.size();} - size_t GetANNIndex(size_t i_Map){return ANN_indices[i_Map];} - size_t GetInputIndex(size_t i_Map, size_t iInput){return Input_Map[i_Map][iInput].first;} - size_t GetOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].first;} - size_t GetANNOutputIndex(size_t i_Map, size_t iOutput){return Output_Map[i_Map][iOutput].second;} - size_t GetNMappedOutputs(size_t i_Map){return Output_Map[i_Map].size();} - - vector> GetOutputMapping(size_t i_map){return Output_Map[i_map];} - vector> GetInputMapping(size_t i_map){return Input_Map[i_map];} + std::vector MLP_indices; /*!< Loaded MLP index */ + + std::vector>> + Input_Map, /*!< Mapping of call variable inputs to matching MLP inputs */ + Output_Map; /*!< Mapping of call variable outputs to matching MLP outputs */ + + std::vector> input_indices; /*!< */ - vector GetANN_Inputs(size_t i_Map, vector&inputs){ - vector ANN_input; - ANN_input.resize(Input_Map[i_Map].size()); + public: - for(size_t iInput=0; iInput GetANN_Outputs(size_t i_Map, vector&outputs){ - vector ANN_output; - ANN_output.resize(Output_Map[i_Map].size()); + /*! + * \brief CIOMap class constructor; + * \param[in] MLP_collection - Pointer to CLookUp_ANN class for which the input-output amap is to be created + * \param[in] inputs - Input names for the call function. These should match with at least one of the MLP inputs. + * \param[in] outputs - Output names for the call function. These should match with at least one of the MLP outputs. + */ + CIOMap(CLookUp_ANN*MLP_collection, std::vector &inputs, std::vector &outputs); + + /*! + * \brief Set MLP index in IO map + * \param[in] i_MLP - loaded MLP index + */ + void Push_MLP_index(std::size_t i_MLP){MLP_indices.push_back(i_MLP);}; + + /*! + * \brief Pair call inputs and outputs with the inputs and outputs of + the loaded MLPs + * \param[in] MLP_collection - pointer to MLP collection class + * \param[in] inputs - vector with call input variable names + * \param[in] outputs - vector with call output variable names + */ + void PairVariableswithMLPs(CLookUp_ANN * MLP_collection, std::vector &inputs, std::vector &outputs); + + /*! + * \brief Get the number of MLPs in the current IO map + * \return number of MLPs with matching inputs and output(s) + */ + std::size_t GetNMLPs() const {return MLP_indices.size();} + + /*! + * \brief Get the loaded MLP index + * \return MLP index + */ + std::size_t GetMLPIndex(std::size_t i_Map) const {return MLP_indices[i_Map];} + + /*! + * \brief Get the call input variable index + * \param[in] i_Map - input-output mapping index of the IO map + * \param[in] i_Input - input index of the call input variable + * \return MLP input variable index + */ + std::size_t GetInputIndex(std::size_t i_Map, std::size_t i_Input) const {return Input_Map[i_Map][i_Input].first;} + + /*! + * \brief Get the call output variable index + * \param[in] i_Map - input-output mapping index of the IO map + * \param[in] i_Output - output index of the call input variable + * \return call variable output index + */ + std::size_t GetOutputIndex(std::size_t i_Map, std::size_t i_Output) const {return Output_Map[i_Map][i_Output].first;} + + /*! + * \brief Get the MLP output variable index + * \param[in] i_Map - input-output mapping index of the IO map + * \param[in] i_Output - output index of the call input variable + * \return MLP output variable index + */ + std::size_t GetMLPOutputIndex(std::size_t i_Map, std::size_t i_Output) const {return Output_Map[i_Map][i_Output].second;} + + /*! + * \brief Get the number of matching output variables between the call and MLP outputs + * \param[in] i_Map - input-output mapping index of the IO map + * \return Number of matching variables between the loaded MLP and call variables + */ + std::size_t GetNMappedOutputs(std::size_t i_Map) const {return Output_Map[i_Map].size();} + + /*! + * \brief Get the mapping of MLP outputs matching to call outputs + * \param[in] i_Map - input-output mapping index of the IO map + * \return Mapping of MLP output variables to call variables + */ + std::vector> GetOutputMapping(std::size_t i_map) const {return Output_Map[i_map];} + + /*! + * \brief Get the mapping of MLP inputs to call inputs + * \param[in] i_Map - input-output mapping index of the IO map + * \return Mapping of MLP input variables to call inputs + */ + std::vector> GetInputMapping(std::size_t i_map) const{return Input_Map[i_map];} + + /*! + * \brief Get the mapped inputs for the MLP at i_Map + * \param[in] i_Map - input-output mapping index of the IO map + * \param[in] inputs - call inputs + * \return Vector with call inputs in the correct order of the loaded MLP + */ + std::vector GetMLP_Inputs(std::size_t i_Map, std::vector&inputs) const { + std::vector MLP_input; + MLP_input.resize(Input_Map[i_Map].size()); - for(size_t iOutput=0; iOutput NeuralNetworks; /*!< Vector containing all loaded neural networks. */ + std::vector NeuralNetworks; /*!< std::vector containing all loaded neural networks. */ - vector ANN_filenames; /*!< Filenames containing ANN architecture information. */ + std::vector ANN_filenames; /*!< Filenames containing ANN architecture information. */ unsigned long number_of_variables; /*!< Number of loaded ANNs. */ @@ -59,20 +67,20 @@ class CLookUp_ANN * \param[in] flag - line to search for * \return line in file. */ - string SkipToFlag(ifstream *file_stream, string flag); + std::string SkipToFlag(ifstream *file_stream, std::string flag); /*! * \brief Load ANN architecture * \param[in] ANN - pointer to target NeuralNetwork class * \param[in] filename - filename containing ANN architecture information */ - void GenerateANN(CNeuralNetwork*ANN, string filename); + void GenerateANN(CNeuralNetwork*ANN, std::string filename); /*! * \brief Read ANN architecture input file * \param[in] filename - filename containing ANN architecture information */ - void ReadANNInputFile(string fileName); + void ReadANNInputFile(std::string fileName); public: @@ -80,7 +88,7 @@ class CLookUp_ANN * \brief ANN collection class constructor * \param[in] filename - filename containing list of ANN input files */ - CLookUp_ANN(string fileName); + CLookUp_ANN(std::string fileName); /*! * \brief Evaluate loaded ANNs for given inputs and outputs @@ -88,9 +96,9 @@ class CLookUp_ANN * \param[in] inputs - input values * \param[in] outputs - pointers to output variables */ - void Predict_ANN(CIOMap *input_output_map, vector &inputs, vector &outputs); + void Predict_ANN(CIOMap *input_output_map, std::vector &inputs, std::vector &outputs); - ~CLookUp_ANN(){for(size_t i_ANN=0; i_ANN &output_names, CIOMap *input_output_map) const; + bool Check_Duplicate_Outputs(std::vector &output_names, CIOMap *input_output_map) const; /*! * \brief Check if all output variables are present in the loaded ANNs * \param[in] output_names - output variable names to check * \param[in] input_output_map - pointer to input-output map to be checked */ - bool Check_Use_of_Outputs(vector &output_names, CIOMap *input_output_map) const; + bool Check_Use_of_Outputs(std::vector &output_names, CIOMap *input_output_map) const; /*! * \brief Check if all input variables are present in the loaded ANNs * \param[in] input_names - input variable names to check * \param[in] input_output_map - pointer to input-output map to be checked */ - bool Check_Use_of_Inputs(vector &input_names, CIOMap *input_output_map) const; + bool Check_Use_of_Inputs(std::vector &input_names, CIOMap *input_output_map) const; /*! * \brief Map variable names to ANN inputs or outputs @@ -127,7 +135,7 @@ class CLookUp_ANN * \param[in] variable_names - variable names to map to ANN inputs or outputs * \param[in] input - map to inputs (true) or outputs (false) */ - vector> FindVariable_Indices(size_t i_ANN, vector variable_names, bool input) const; + std::vector> FindVariable_Indices(std::size_t i_ANN, std::vector variable_names, bool input) const; }; diff --git a/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp index 6e54cd363a8..a7d1cfba5e4 100644 --- a/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp @@ -37,12 +37,11 @@ #include "../../linear_algebra/blas_structure.hpp" #include "CLayer.hpp" -using namespace std; namespace MLPToolbox{ class CNeuralNetwork { private: - vector input_names, + std::vector input_names, output_names; unsigned long n_hidden_layers; @@ -50,16 +49,16 @@ class CNeuralNetwork CLayer *inputLayer, *outputLayer; - vector hiddenLayers, + std::vector hiddenLayers, total_layers; - vector>> weights; - vector weights_mat; - vector> values; + //std::vector>> weights; + std::vector weights_mat; + std::vector> values; - vector> input_norm, + std::vector> input_norm, output_norm; - vector last_inputs; + std::vector last_inputs; su2double* ANN_outputs; @@ -68,14 +67,19 @@ class CNeuralNetwork LINEAR=1, RELU=2, SMOOTH_SLOPE=3, - ELU = 4 + ELU = 4, + GELU = 5, + SELU = 6, + SIGMOID = 7, + SWISH = 8, + TANH = 9 }; ENUM_ACTIVATION_FUNCTION * activation_function_types; public: CNeuralNetwork(); ~CNeuralNetwork(){ - for(size_t i=0; isetBias(i_neuron, value);} - void setActivationFunction(unsigned long i_layer, string input); + void setActivationFunction(unsigned long i_layer, std::string input); void displayNetwork(); void sizeWeights(); void sizeInputs(unsigned long n_inputs){last_inputs.resize(n_inputs); for(unsigned long iInput=0; iInputgetNNeurons();} - unsigned long getNNeurons(unsigned long iLayer, unsigned long iNeuron){return weights.at(iLayer).at(iNeuron).size();} + //unsigned long getNNeurons(unsigned long iLayer, unsigned long iNeuron){return weights.at(iLayer).at(iNeuron).size();} - void predict(vector &inputs); + void predict(std::vector &inputs); void SetInputNorm(unsigned long iInput, su2double input_min, su2double input_max){input_norm.at(iInput) = make_pair(input_min, input_max);} void SetOutputNorm(unsigned long iOutput, su2double output_min, su2double output_max){output_norm.at(iOutput) = make_pair(output_min, output_max);} - void PushOutputName(string input){output_names.push_back(input);} - void PushInputName(string input){input_names.push_back(input);} + void PushOutputName(std::string input){output_names.push_back(input);} + void PushInputName(std::string input){input_names.push_back(input);} - string GetInputName(size_t iInput){return input_names[iInput];} - string GetOutputName(size_t iOutput){return output_names[iOutput];} + std::string GetInputName(std::size_t iInput){return input_names[iInput];} + std::string GetOutputName(std::size_t iOutput){return output_names[iOutput];} - size_t GetnInputs(){return input_names.size();} - size_t GetnOutputs(){return output_names.size();} + std::size_t GetnInputs(){return input_names.size();} + std::size_t GetnOutputs(){return output_names.size();} - su2double GetANN_Output(size_t iOutput){return ANN_outputs[iOutput];} + su2double GetANN_Output(std::size_t iOutput){return ANN_outputs[iOutput];} void SizeActivationFunctions(unsigned long n_layers){activation_function_types = new ENUM_ACTIVATION_FUNCTION[n_layers]; } - su2double ComputeX(size_t iLayer, size_t iNeuron){ + su2double ComputeX(std::size_t iLayer, std::size_t iNeuron){ su2double x; x = total_layers[iLayer]->getBias(iNeuron); - size_t nNeurons_previous = total_layers[iLayer - 1]->getNNeurons(); - for(size_t jNeuron=0; jNeurongetNNeurons(); + for(std::size_t jNeuron=0; jNeurongetOutput(jNeuron); } return x; diff --git a/Common/include/toolboxes/multilayer_perceptron/CNeuron.hpp b/Common/include/toolboxes/multilayer_perceptron/CNeuron.hpp index fed140d4457..3e1cefd1d6f 100644 --- a/Common/include/toolboxes/multilayer_perceptron/CNeuron.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CNeuron.hpp @@ -32,9 +32,8 @@ #include #include "../../CConfig.hpp" -#include "../../linear_algebra/blas_structure.hpp" +//#include "../../linear_algebra/blas_structure.hpp" -using namespace std; namespace MLPToolbox{ class CNeuron { diff --git a/Common/include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp b/Common/include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp index d471e42d939..7921023762b 100644 --- a/Common/include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CReadNeuralNetwork.hpp @@ -30,46 +30,45 @@ #include #include #include - +#include #include "../../CConfig.hpp" -#include "../../linear_algebra/blas_structure.hpp" -using namespace std; namespace MLPToolbox{ + class CReadNeuralNetwork { private: - vector input_names; - vector output_names; + std::vector input_names; + std::vector output_names; - string filename; + std::string filename; unsigned long n_layers; - vector n_neurons; - vector>> weights; - vector> biases; - vector activation_functions; + std::vector n_neurons; + std::vector>> weights; + std::vector> biases; + std::vector activation_functions; - vector> input_norm; - vector> output_norm; + std::vector> input_norm; + std::vector> output_norm; public: - CReadNeuralNetwork(string filename_in); + CReadNeuralNetwork(std::string filename_in); void ReadMLPFile(); - string SkipToFlag(ifstream *file_stream, string flag); + std::string SkipToFlag(std::ifstream *file_stream, std::string flag); unsigned long GetNInputs(){return n_neurons.at(0);} unsigned long GetNOutputs(){return n_neurons.at(n_layers - 1);} unsigned long GetNlayers(){return n_layers;} - unsigned long GetNneurons(size_t iLayer){return n_neurons.at(iLayer);} - double long GetWeight(size_t iLayer, size_t iNeuron, size_t jNeuron){return weights.at(iLayer).at(iNeuron).at(jNeuron);} - double long GetBias(size_t iLayer, size_t iNeuron){return biases.at(iLayer).at(iNeuron);} - pair GetInputNorm(size_t iInput){return input_norm.at(iInput);} - pair GetOutputNorm(size_t iOutput){return output_norm.at(iOutput);} - string GetActivationFunction(size_t iLayer){return activation_functions.at(iLayer);} + unsigned long GetNneurons(std::size_t iLayer){return n_neurons.at(iLayer);} + su2double GetWeight(std::size_t iLayer, std::size_t iNeuron, std::size_t jNeuron){return weights.at(iLayer).at(iNeuron).at(jNeuron);} + su2double GetBias(std::size_t iLayer, std::size_t iNeuron){return biases.at(iLayer).at(iNeuron);} + std::pair GetInputNorm(std::size_t iInput){return input_norm.at(iInput);} + std::pair GetOutputNorm(std::size_t iOutput){return output_norm.at(iOutput);} + std::string GetActivationFunction(std::size_t iLayer){return activation_functions.at(iLayer);} - string GetInputName(size_t iInput){return input_names.at(iInput);} - string GetOutputName(size_t iOutput){return output_names.at(iOutput);} + std::string GetInputName(std::size_t iInput){return input_names.at(iInput);} + std::string GetOutputName(std::size_t iOutput){return output_names.at(iOutput);} ~CReadNeuralNetwork(){}; }; diff --git a/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp b/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp index d6bba0ce8b2..789988af101 100644 --- a/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp @@ -32,25 +32,48 @@ #include #include -MLPToolbox::CIOMap::CIOMap(CLookUp_ANN*ANN_collection, vector &inputs, vector &outputs){ - PairVariableswithANNs(ANN_collection, inputs, outputs); +MLPToolbox::CIOMap::CIOMap(CLookUp_ANN*MLP_collection, vector &inputs, vector &outputs){ + /* Generate an input-output map given a set of call inputs and call outputs. These inputs are + mapped to the inputs of the loaded MLPs in the MLP_collection object. The call outputs are + then matched to the MLPs with matching inputs. + */ + PairVariableswithMLPs(MLP_collection, inputs, outputs); + + // Perform checks on input-output validity if(outputs.size() > 0){ - ANN_collection->Check_Use_of_Inputs(inputs, this); - ANN_collection->Check_Use_of_Outputs(outputs, this); - ANN_collection->Check_Duplicate_Outputs(outputs, this); + // Check wether all call inputs are used + MLP_collection->Check_Use_of_Inputs(inputs, this); + + // Check wether all call outputs are present in the MLP collection + MLP_collection->Check_Use_of_Outputs(outputs, this); + + // Check wether there are any duplicates in the MLP outputs + MLP_collection->Check_Duplicate_Outputs(outputs, this); } } -void MLPToolbox::CIOMap::PairVariableswithANNs(CLookUp_ANN*ANN_collection, vector &inputs, vector &outputs){ - +void MLPToolbox::CIOMap::PairVariableswithMLPs(CLookUp_ANN*MLP_collection, vector &inputs, vector &outputs){ + /* + In this function, the call inputs and outputs are matched to those within the MLP collection. + */ bool isInput, isOutput; - for(size_t i_ANN=0; i_ANNGetNANNs(); i_ANN++){ - vector> Input_Indices = ANN_collection->FindVariable_Indices(i_ANN, inputs, true); + + // Looping over the loaded MLPs to check wether the MLP inputs match with the call inputs + for(size_t i_MLP=0; i_MLPGetNANNs(); i_MLP++){ + + // Mapped call inputs to MLP inputs + vector> Input_Indices = MLP_collection->FindVariable_Indices(i_MLP, inputs, true); isInput = Input_Indices.size() > 0; + if(isInput){ - vector> Output_Indices = ANN_collection->FindVariable_Indices(i_ANN, outputs, false); + // Only when the MLP inputs match with a portion of the call inputs are the output variable checks performed + + vector> Output_Indices = MLP_collection->FindVariable_Indices(i_MLP, outputs, false); isOutput = Output_Indices.size() > 0; + if(isOutput){ - ANN_indices.push_back(i_ANN); + + // Update input and output mapping if both inputs and outputs match + MLP_indices.push_back(i_MLP); Input_Map.push_back(Input_Indices); Output_Map.push_back(Output_Indices); } diff --git a/Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp b/Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp index f63e57038a7..4642a8a9bd4 100644 --- a/Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CLookUp_ANN.cpp @@ -73,12 +73,12 @@ vector> MLPToolbox::CLookUp_ANN::FindVariable_Indices(size_ } void MLPToolbox::CLookUp_ANN::Predict_ANN(CIOMap *input_output_map, vector& inputs, vector& outputs){ - for(size_t i_map=0; i_mapGetNANNs(); i_map++){ - size_t i_ANN = input_output_map->GetANNIndex(i_map); - vector ANN_inputs = input_output_map->GetANN_Inputs(i_map, inputs); + for(size_t i_map=0; i_mapGetNMLPs(); i_map++){ + size_t i_ANN = input_output_map->GetMLPIndex(i_map); + vector ANN_inputs = input_output_map->GetMLP_Inputs(i_map, inputs); NeuralNetworks[i_ANN]->predict(ANN_inputs); for(size_t i=0; i < input_output_map->GetNMappedOutputs(i_map); i++){ - *outputs[input_output_map->GetOutputIndex(i_map, i)] = NeuralNetworks[i_ANN]->GetANN_Output(input_output_map->GetANNOutputIndex(i_map, i)); + *outputs[input_output_map->GetOutputIndex(i_map, i)] = NeuralNetworks[i_ANN]->GetANN_Output(input_output_map->GetMLPOutputIndex(i_map, i)); } } } @@ -111,7 +111,7 @@ void MLPToolbox::CLookUp_ANN::GenerateANN(CNeuralNetwork * ANN, string fileName) for(size_t i_layer = 0; i_layer < ANN->getNWeightLayers(); i_layer++){ ANN->setActivationFunction(i_layer, Reader.GetActivationFunction(i_layer)); for(size_t i_neuron=0; i_neuron < ANN->getNNeurons(i_layer); i_neuron++){ - for(size_t j_neuron=0; j_neurongetNNeurons(i_layer, i_neuron); j_neuron++){ + for(size_t j_neuron=0; j_neurongetNNeurons(i_layer+1); j_neuron++){ ANN->setWeight(i_layer, i_neuron, j_neuron, Reader.GetWeight(i_layer, i_neuron, j_neuron)); } } @@ -175,7 +175,7 @@ string MLPToolbox::CLookUp_ANN::SkipToFlag(ifstream *file_stream, string flag) { } if ((*file_stream).eof()) - SU2_MPI::Error("Flag not found in file", CURRENT_FUNCTION); + SU2_MPI::Error("Flag " + flag + " not found in file", CURRENT_FUNCTION); return line; } @@ -187,7 +187,7 @@ bool MLPToolbox::CLookUp_ANN::Check_Duplicate_Outputs(vector &output_nam vector duplicate_variables; for(size_t i_Output =0; i_Output < output_names.size(); i_Output++){ n_occurances = 0; - for(size_t i_map=0; i_mapGetNANNs(); i_map++){ + for(size_t i_map=0; i_mapGetNMLPs(); i_map++){ vector> output_map = input_output_map->GetOutputMapping(i_map); for(size_t j_Output=0; j_Output missing_inputs; bool inputs_are_present{true}; for(size_t iInput=0; iInputGetNANNs(); i_map++){ + for(size_t i_map=0; i_map < input_output_map->GetNMLPs(); i_map++){ vector> input_map = input_output_map->GetInputMapping(i_map); for(size_t jInput=0; jInput &output_names, bool found_output{false}; /* Looping over all the selected ANNs */ - for(size_t i_map=0; i_map < input_output_map->GetNANNs(); i_map++){ + for(size_t i_map=0; i_map < input_output_map->GetNMLPs(); i_map++){ vector> output_map = input_output_map->GetOutputMapping(i_map); /* Looping over the outputs of the output map of the current ANN */ diff --git a/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp b/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp index 496ac851048..ebc712e15e5 100644 --- a/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CNeuralNetwork.cpp @@ -42,6 +42,8 @@ void MLPToolbox::CNeuralNetwork::predict(vector &inputs){ inputLayer->setOutput(iNeuron, x_norm); } if(!same_point){ + su2double alpha=1.67326324; + su2double lambda=1.05070098; for(iLayer=1; iLayergetNNeurons(); @@ -54,14 +56,22 @@ void MLPToolbox::CNeuralNetwork::predict(vector &inputs){ case ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE: for(iNeuron=0; iNeurongetInput(iNeuron); - y = x > 0 ? x : tanh(x); + if(x > 0){ + y = x; + }else{ + y = tanh(x); + } total_layers[iLayer]->setOutput(iNeuron, y); } break; case ENUM_ACTIVATION_FUNCTION::ELU: for(iNeuron=0; iNeurongetInput(iNeuron); - y = x > 0 ? x : (exp(x) - 1); + if(x > 0){ + y = x; + }else{ + y = exp(x) - 1; + } total_layers[iLayer]->setOutput(iNeuron, y); } break; @@ -75,7 +85,52 @@ void MLPToolbox::CNeuralNetwork::predict(vector &inputs){ case ENUM_ACTIVATION_FUNCTION::RELU: for(iNeuron=0; iNeurongetInput(iNeuron); - y = x > 0.0 ? x : 0.0; + if(x > 0){ + y = x; + }else{ + y = 0.0; + } + total_layers[iLayer]->setOutput(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::SWISH: + for(iNeuron=0; iNeurongetInput(iNeuron); + y = x / (1 + exp(-x)); + total_layers[iLayer]->setOutput(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::TANH: + for(iNeuron=0; iNeurongetInput(iNeuron); + y = tanh(x); + total_layers[iLayer]->setOutput(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::SIGMOID: + for(iNeuron=0; iNeurongetInput(iNeuron); + y = 1.0/(1 + exp(-x)); + total_layers[iLayer]->setOutput(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::SELU: + for(iNeuron=0; iNeurongetInput(iNeuron); + if(x > 0.0){ + y = lambda * x; + }else{ + y = lambda * alpha * (exp(x) - 1); + } + total_layers[iLayer]->setOutput(iNeuron, y); + } + break; + case ENUM_ACTIVATION_FUNCTION::GELU: + + for(iNeuron=0; iNeurongetInput(iNeuron); + + y = 0.5 * x * (1 + tanh(sqrt(2 / PI_NUMBER) * (x + 0.044715 * pow(x, 3)))); total_layers[iLayer]->setOutput(iNeuron, y); } break; @@ -108,45 +163,24 @@ MLPToolbox::CNeuralNetwork::CNeuralNetwork(){ void MLPToolbox::CNeuralNetwork::defineInputLayer(unsigned long n_neurons){ - //cout << "Creating an input layer with " << n_neurons << " neurons. "<< endl; inputLayer = new CLayer(n_neurons); inputLayer->setInput(true); input_norm.resize(n_neurons); } void MLPToolbox::CNeuralNetwork::defineOutputLayer(unsigned long n_neurons){ - //cout << "Creating an output layer with " << n_neurons << " neurons. "<< endl; outputLayer = new CLayer(n_neurons); output_norm.resize(n_neurons); } void MLPToolbox::CNeuralNetwork::push_hidden_layer(unsigned long n_neurons){ CLayer *newLayer = new CLayer(n_neurons); - //cout << "Creating a hidden layer with " << n_neurons << " neurons. "<< endl; hiddenLayers.push_back(newLayer); n_hidden_layers ++; } void MLPToolbox::CNeuralNetwork::sizeWeights(){ - unsigned long i_layer{0}; - weights.resize(n_hidden_layers + 1); - weights.at(i_layer).resize(inputLayer->getNNeurons()); - CLayer * previouslayer = inputLayer; - - if(n_hidden_layers != 0){ - for(size_t i_hidden_layer=0; i_hidden_layer < n_hidden_layers; i_hidden_layer++){ - for(size_t i_neuron=0; i_neuron < previouslayer->getNNeurons(); i_neuron++){ - weights.at(i_layer).at(i_neuron).resize(hiddenLayers.at(i_hidden_layer)->getNNeurons()); - } - previouslayer = hiddenLayers.at(i_hidden_layer); - i_layer ++; - weights.at(i_layer).resize(previouslayer->getNNeurons()); - } - } - for(size_t i_neuron=0; i_neuron < previouslayer->getNNeurons(); i_neuron++){ - weights.at(i_layer).at(i_neuron).resize(outputLayer->getNNeurons()); - } - + total_layers.resize(n_hidden_layers + 2); total_layers.at(0) = inputLayer; for(size_t iLayer=0; iLayergetNNeurons() << " neurons, Activation Function: " << inputLayer->getActivationType() << endl; - for(size_t i=0; igetNNeurons(); i++){ - for(size_t j=0; jgetNNeurons(); j++){ - cout << weights_mat[0][i][j] << " "; - } - } - for(size_t i_layer=0; i_layer < hiddenLayers.size(); i_layer++){ - cout << "Hidden layer " << i_layer + 1 << ": " << hiddenLayers.at(i_layer)->getNNeurons() << " neurons, Activation Function: " << hiddenLayers.at(i_layer) ->getActivationType() << endl; - for(size_t i=0; igetNNeurons() <<" neurons, Activation Function: " << outputLayer->getActivationType() << endl; + /*! + TODO: + find way of displaying network architectures + */ } void MLPToolbox::CNeuralNetwork::setActivationFunction(unsigned long i_layer, string input) { if(input.compare("linear") == 0){ - //activation_functions[i_layer] = new Linear(); activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::LINEAR; return; } if(input.compare("relu") == 0){ - //activation_functions[i_layer] = new Relu(); activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::RELU; return; } if((input.compare("smooth_slope") == 0)){ - //activation_functions[i_layer] = new SmoothSlope(); activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::SMOOTH_SLOPE; return; } if((input.compare("elu") == 0)){ - //activation_functions[i_layer] = new SmoothSlope(); activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::ELU; return; } + if(input.compare("swish") == 0){ + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::SWISH; + return; + } + if(input.compare("sigmoid") == 0){ + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::SIGMOID; + return; + } + if(input.compare("tanh") == 0){ + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::TANH; + return; + } + if(input.compare("selu") == 0){ + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::SELU; + return; + } + if(input.compare("gelu") == 0){ + activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::GELU; + return; + } if(input.compare("none") == 0){ - //activation_functions[i_layer] = new None(); activation_function_types[i_layer] = ENUM_ACTIVATION_FUNCTION::NONE; return; } - //total_layers.at(i_layer)->setActivationFunction(input); + SU2_MPI::Error("Unknown activation function type: " + input, CURRENT_FUNCTION); return; } diff --git a/SU2_CFD/src/fluid/CPengRobinson.cpp b/SU2_CFD/src/fluid/CPengRobinson.cpp index 66abe62f4f4..962e8a60ea1 100644 --- a/SU2_CFD/src/fluid/CPengRobinson.cpp +++ b/SU2_CFD/src/fluid/CPengRobinson.cpp @@ -26,6 +26,7 @@ */ #include "../../include/fluid/CPengRobinson.hpp" +#include "../../../Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp" CPengRobinson::CPengRobinson(su2double gamma, su2double R, su2double Pstar, su2double Tstar, su2double w) : CIdealGas(gamma, R) { @@ -38,6 +39,56 @@ CPengRobinson::CPengRobinson(su2double gamma, su2double R, su2double Pstar, su2d k = 0.37464 + 1.54226 * w - 0.26992 * w * w; else k = 0.379642 + 1.48503 * w - 0.164423 * w * w + 0.016666 * w * w * w; + + vector call_input_variables; + vector call_output_variables; + vector call_inputs; + vector call_outputs; + call_input_variables.push_back("Progress_Variable"); + call_inputs.push_back(-5.74934292655689e-01); + call_input_variables.push_back("Enthalpy"); + call_inputs.push_back(+2.22692201641688e+03); + call_input_variables.push_back("Mixture_Fraction"); + call_inputs.push_back(0.0144045); + + call_output_variables.push_back("Temperature"); + call_outputs.push_back(&Temperature); + call_output_variables.push_back("Density"); + call_outputs.push_back(&Density); + + vector call_inputvars_lean; + call_inputvars_lean.push_back("Progress_Variable_lean"); + call_inputvars_lean.push_back("Enthalpy_lean"); + call_inputvars_lean.push_back("Mixture_Fraction_lean"); + + vector call_inputvars_rich; + call_inputvars_rich.push_back("Progress_Variable_rich"); + call_inputvars_rich.push_back("Enthalpy_rich"); + call_inputvars_rich.push_back("Mixture_Fraction_rich"); + + MLPToolbox::CLookUp_ANN * test_mlp = new MLPToolbox::CLookUp_ANN("MLP_collection.mlp"); + MLPToolbox::CIOMap * test_map = new MLPToolbox::CIOMap(test_mlp, call_input_variables, call_output_variables); + MLPToolbox::CIOMap * lean_map = new MLPToolbox::CIOMap(test_mlp, call_inputvars_lean, call_output_variables); + MLPToolbox::CIOMap * rich_map = new MLPToolbox::CIOMap(test_mlp, call_inputvars_rich, call_output_variables); + + + test_mlp->Predict_ANN(test_map, call_inputs, call_outputs); + cout << "in flame zone: " << Density << " " << Temperature << endl; + call_inputs[0] = -7.36; + call_inputs[1] = 26468.5; + call_inputs[2] = 1.0; + test_mlp->Predict_ANN(rich_map, call_inputs, call_outputs); + cout << "rich: " << Density << " " << Temperature << endl; + call_inputs[0] = -0.4753; + call_inputs[1] = 3144.6; + call_inputs[2] = 0.0; + test_mlp->Predict_ANN(lean_map, call_inputs, call_outputs); + cout << "lean: " << Density << " " << Temperature << endl; + + delete test_mlp; + delete test_map; + delete rich_map; + delete lean_map; } su2double CPengRobinson::alpha2(su2double T) const { From 04813b107392ff542fc4fb7577e30bd2a54bf7e5 Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Wed, 19 Oct 2022 14:43:54 +0200 Subject: [PATCH 036/598] Added a MLP fluid model template class --- Common/include/CConfig.hpp | 7 ++ Common/include/option_structure.hpp | 2 + Common/src/CConfig.cpp | 3 + .../multilayer_perceptron/CIOMap.cpp | 2 +- .../CReadNeuralNetwork.cpp | 3 +- .../{CMLPGas_Template.hpp => CMLPGas.hpp} | 13 +-- SU2_CFD/obj/Makefile.am | 2 +- .../{CMLPGas_Template.cpp => CMLPGas.cpp} | 95 ++++++++++++------- SU2_CFD/src/meson.build | 2 +- SU2_CFD/src/solvers/CEulerSolver.cpp | 12 +++ SU2_CFD/src/solvers/CIncEulerSolver.cpp | 13 +++ 11 files changed, 111 insertions(+), 43 deletions(-) rename SU2_CFD/include/fluid/{CMLPGas_Template.hpp => CMLPGas.hpp} (91%) rename SU2_CFD/src/fluid/{CMLPGas_Template.cpp => CMLPGas.cpp} (54%) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 9e47dc85e56..db4410287a8 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -223,6 +223,7 @@ class CConfig { string Inlet_Filename; /*!< \brief Filename specifying an inlet profile. */ su2double Inlet_Matching_Tol; /*!< \brief Tolerance used when matching a point to a point from the inlet file. */ string ActDisk_FileName; /*!< \brief Filename specifying an actuator disk. */ + string MLP_filename; /*!< \brief Filename specifying an MLP-driven fluid model. */ string *Marker_Euler, /*!< \brief Euler wall markers. */ *Marker_FarField, /*!< \brief Far field markers. */ @@ -4842,6 +4843,12 @@ class CConfig { */ string GetActDisk_FileName(void) const { return ActDisk_FileName; } + /*! + * \brief Get name of the input file for the fluid model multi-layer perceptron collection. + * \return Name of the input file for the specified MLP collection file. + */ + string GetMLP_FileName(void) const { return MLP_filename; } + /*! * \brief Get the tolerance used for matching two points on a specified inlet * \return Tolerance used for matching a point to a specified inlet diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index 0b97712612a..45d475fbbe4 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -569,6 +569,7 @@ enum ENUM_FLUIDMODEL { MUTATIONPP = 7, /*!< \brief Mutation++ gas model for nonequilibrium flow. */ SU2_NONEQ = 8, /*!< \brief User defined gas model for nonequilibrium flow. */ FLUID_MIXTURE = 9, /*!< \brief Species mixture model. */ + MLP_GAS = 10, /*!< \brief multi-layer perceptron driven fluid model. */ }; static const MapType FluidModel_Map = { MakePair("STANDARD_AIR", STANDARD_AIR) @@ -581,6 +582,7 @@ static const MapType FluidModel_Map = { MakePair("MUTATIONPP", MUTATIONPP) MakePair("SU2_NONEQ", SU2_NONEQ) MakePair("FLUID_MIXTURE", FLUID_MIXTURE) + MakePair("MLP_GAS", MLP_GAS) }; /*! diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index cc9ea692c76..e6375f1a78d 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -1482,6 +1482,9 @@ void CConfig::SetConfig_Options() { /*!\brief ACTDISK_FILENAME \n DESCRIPTION: Input file for a specified actuator disk (w/ extension) \n DEFAULT: actdiskinput.dat \ingroup Config*/ addStringOption("ACTDISK_FILENAME", ActDisk_FileName, string("actdiskinput.dat")); + /*!\brief MLP_FILENAME \n DESCRIPTION: Input file for a multi-layer perceptron input file for fluid model definition. w/ extension) \n DEFAULT: MLP_collection.mlp \ingroup Config*/ + addStringOption("MLP_FILENAME", MLP_filename, string("MLP_collection.mlp")); + /*!\brief INLET_TYPE \n DESCRIPTION: Inlet boundary type \n OPTIONS: see \link Inlet_Map \endlink \n DEFAULT: TOTAL_CONDITIONS \ingroup Config*/ addEnumOption("INLET_TYPE", Kind_Inlet, Inlet_Map, INLET_TYPE::TOTAL_CONDITIONS); /*!\brief INC_INLET_TYPE \n DESCRIPTION: List of inlet types for incompressible flows. List length must match number of inlet markers. Options: VELOCITY_INLET, PRESSURE_INLET, INPUT_FILE. \ingroup Config*/ diff --git a/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp b/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp index 789988af101..36d08a081db 100644 --- a/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CIOMap.cpp @@ -48,7 +48,7 @@ MLPToolbox::CIOMap::CIOMap(CLookUp_ANN*MLP_collection, vector &inputs, v MLP_collection->Check_Use_of_Outputs(outputs, this); // Check wether there are any duplicates in the MLP outputs - MLP_collection->Check_Duplicate_Outputs(outputs, this); + //MLP_collection->Check_Duplicate_Outputs(outputs, this); } } void MLPToolbox::CIOMap::PairVariableswithMLPs(CLookUp_ANN*MLP_collection, vector &inputs, vector &outputs){ diff --git a/Common/src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp b/Common/src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp index 8c34674e260..73e49fda1e1 100644 --- a/Common/src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp +++ b/Common/src/toolboxes/multilayer_perceptron/CReadNeuralNetwork.cpp @@ -30,7 +30,7 @@ using namespace std; MLPToolbox::CReadNeuralNetwork::CReadNeuralNetwork(string filename_in){ filename = filename_in; -}; +} void MLPToolbox::CReadNeuralNetwork::ReadMLPFile(){ ifstream file_stream; @@ -109,7 +109,6 @@ void MLPToolbox::CReadNeuralNetwork::ReadMLPFile(){ /* Read MLP input variable names */ if(line.compare("[input names]") == 0){ found_input_names = true; - unsigned short j{1}; getline(file_stream, line); while(line.compare("") != 0){ input_names.push_back(line); diff --git a/SU2_CFD/include/fluid/CMLPGas_Template.hpp b/SU2_CFD/include/fluid/CMLPGas.hpp similarity index 91% rename from SU2_CFD/include/fluid/CMLPGas_Template.hpp rename to SU2_CFD/include/fluid/CMLPGas.hpp index db3207c3313..0da131105b4 100644 --- a/SU2_CFD/include/fluid/CMLPGas_Template.hpp +++ b/SU2_CFD/include/fluid/CMLPGas.hpp @@ -1,5 +1,5 @@ /*! - * \file CMLPGas_Template.hpp + * \file CMLPGas.hpp * \brief Defines a template fluid model class using multilayer perceptrons * for theromodynamic state definition * \author E.Bunschoten @@ -31,17 +31,18 @@ #include "CFluidModel.hpp" #include "../../../Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp" /*! - * \class CMLPGas_Template + * \class CMLPGas * \brief Template class for fluid model definition using multi-layer perceptrons for * fluid dynamic state definition. * \author: E.Bunschoten. */ -class CMLPGas_Template : public CFluidModel { +class CMLPGas : public CFluidModel { protected: su2double Gamma{0.0}; /*!< \brief Ratio of Specific Heats. */ su2double Gamma_Minus_One{0.0}; /*!< \brief Ratio of Specific Heats Minus One. */ su2double Gas_Constant{0.0}; /*!< \brief Gas Constant. */ - bool ComputeEntropy{true}; /*!< \brief Whether or not to compute entropy. */ + + su2double R_u = 8.31451; string ann_input_filename; MLPToolbox::CLookUp_ANN * lookup_ann; @@ -69,9 +70,9 @@ class CMLPGas_Template : public CFluidModel { /*! * \brief Constructor of the class. */ - CMLPGas_Template(su2double gamma, su2double R, bool CompEntropy = true); + CMLPGas(const CConfig* config); - ~CMLPGas_Template(); + ~CMLPGas(); /*! * \brief Set the Dimensionless State using Density and Internal Energy * \param[in] rho - first thermodynamic variable. diff --git a/SU2_CFD/obj/Makefile.am b/SU2_CFD/obj/Makefile.am index 5ba91fd0d4e..361d69d5af9 100644 --- a/SU2_CFD/obj/Makefile.am +++ b/SU2_CFD/obj/Makefile.am @@ -57,7 +57,7 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/fluid/CNEMOGas.cpp \ ../src/fluid/CSU2TCLib.cpp \ ../src/fluid/CMutationTCLib.cpp \ - ../src/fluid/CMLPGas_Template.cpp \ + ../src/fluid/CMLPGas.cpp \ ../src/integration/CIntegration.cpp \ ../src/integration/CSingleGridIntegration.cpp \ ../src/integration/CMultiGridIntegration.cpp \ diff --git a/SU2_CFD/src/fluid/CMLPGas_Template.cpp b/SU2_CFD/src/fluid/CMLPGas.cpp similarity index 54% rename from SU2_CFD/src/fluid/CMLPGas_Template.cpp rename to SU2_CFD/src/fluid/CMLPGas.cpp index 44e00c5ec8d..219dc2351e3 100644 --- a/SU2_CFD/src/fluid/CMLPGas_Template.cpp +++ b/SU2_CFD/src/fluid/CMLPGas.cpp @@ -1,5 +1,5 @@ /*! - * \file CMLPGas_Template.cpp + * \file CMLPGas.cpp * \brief Source of the data-driven fluid model class using * multilayer perceptrons for data regression * \author E.Bunschoten @@ -26,35 +26,28 @@ * License along with SU2. If not, see . */ -#include "../../include/fluid/CMLPGas_Template.hpp" +#include "../../include/fluid/CMLPGas.hpp" -CMLPGas_Template::CMLPGas_Template(su2double gamma, su2double R, bool CompEntropy) : CFluidModel() { - Gamma = gamma; - Gamma_Minus_One = Gamma - 1.0; - Gas_Constant = R; - Cp = Gamma / Gamma_Minus_One * Gas_Constant; - Cv = Cp - R; - - ComputeEntropy = CompEntropy; +CMLPGas::CMLPGas(const CConfig* config) : CFluidModel() { /* Define a CLookUp_ANN object to allow for data regression */ - ann_input_filename = "MLP_collection.mlp"; + ann_input_filename = config->GetMLP_FileName(); lookup_ann = new MLPToolbox::CLookUp_ANN(ann_input_filename); /* Map MLP inputs to outputs for each look-up operation*/ MapInputs_to_Outputs(); } -CMLPGas_Template::~CMLPGas_Template(){ +CMLPGas::~CMLPGas(){ delete iomap_rhoe; delete iomap_PT; delete iomap_Prho; delete lookup_ann; } -void CMLPGas_Template::MapInputs_to_Outputs(){ +void CMLPGas::MapInputs_to_Outputs(){ - input_names_rhoe.push_back("rho"); - input_names_rhoe.push_back("e"); + input_names_rhoe.push_back("Density"); + input_names_rhoe.push_back("Energy"); output_names_rhoe.push_back("Temperature"); outputs_rhoe.push_back(&Temperature); @@ -75,41 +68,79 @@ void CMLPGas_Template::MapInputs_to_Outputs(){ iomap_rhoe = new MLPToolbox::CIOMap(lookup_ann, input_names_rhoe, output_names_rhoe); - input_names_PT.push_back("P"); - input_names_PT.push_back("T"); + input_names_PT.push_back("Pressure"); + input_names_PT.push_back("Temperature"); - output_names_PT.push_back("rho"); + output_names_PT.push_back("Density"); outputs_PT.push_back(&Density); - output_names_PT.push_back("e"); + output_names_PT.push_back("Energy"); outputs_PT.push_back(&StaticEnergy); iomap_PT = new MLPToolbox::CIOMap(lookup_ann, input_names_PT, output_names_PT); - input_names_Prho.push_back("P"); - input_names_Prho.push_back("rho"); + input_names_Prho.push_back("Pressure"); + input_names_Prho.push_back("Density"); - output_names_Prho.push_back("e"); + output_names_Prho.push_back("Energy"); outputs_Prho.push_back(&StaticEnergy); iomap_Prho = new MLPToolbox::CIOMap(lookup_ann, input_names_Prho, output_names_Prho); } -void CMLPGas_Template::SetTDState_rhoe(su2double rho, su2double e) { +void CMLPGas::SetTDState_rhoe(su2double rho, su2double e) { + Density = rho; + StaticEnergy = e; vector ann_inputs; ann_inputs.push_back(rho); ann_inputs.push_back(e); lookup_ann->Predict_ANN(iomap_rhoe, ann_inputs, outputs_rhoe); -} + Cp = (Pressure / (R_u * Density * Temperature)) * 1 / (dTde_rho); + Cv = (1/dTde_rho); + Gamma = Cp / Cv; + Gamma_Minus_One = Gamma - 1; + Gas_Constant = Cp * Gamma_Minus_One; -void CMLPGas_Template::SetTDState_PT(su2double P, su2double T) { - vector ann_inputs; - ann_inputs.push_back(P); - ann_inputs.push_back(T); - lookup_ann->Predict_ANN(iomap_PT, ann_inputs, outputs_PT); +} - SetTDState_rhoe(Density, StaticEnergy); +void CMLPGas::SetTDState_PT(su2double P, su2double T) { + // vector ann_inputs; + // ann_inputs.push_back(P); + // ann_inputs.push_back(T); + // lookup_ann->Predict_ANN(iomap_PT, ann_inputs, outputs_PT); + + su2double rho = 0.5*(6.9682399336300005e-01 + 2.4896548789900002e+00); + su2double e = 0.5*(3.2562734877400001e+05 +4.8566089128400001e+05); + rho = 1.0; + e = 3.2562734877400001e+05; + su2double delta_P, delta_T, delta_rho, delta_e, tolerance_P = 10, tolerance_T = 1.0; + su2double determinant, relaxation = 0.1; + unsigned long iter = 0, iter_max = 1000; + bool converged= false; + cout << "Target PT: " << P << " " << T << endl; + while(!converged && (iter < iter_max)){ + SetTDState_rhoe(rho, e); + delta_P = (P - Pressure); + delta_T = (T - Temperature); + cout << delta_P << " " << delta_T << endl; + if((abs(delta_P) ann_inputs; ann_inputs.push_back(P); ann_inputs.push_back(rho); @@ -117,7 +148,7 @@ void CMLPGas_Template::SetTDState_Prho(su2double P, su2double rho) { SetTDState_rhoe(rho, StaticEnergy); } -void CMLPGas_Template::SetEnergy_Prho(su2double P, su2double rho) { +void CMLPGas::SetEnergy_Prho(su2double P, su2double rho) { vector ann_inputs; ann_inputs.push_back(P); ann_inputs.push_back(rho); diff --git a/SU2_CFD/src/meson.build b/SU2_CFD/src/meson.build index 9d81ec13f71..e477f80b2b6 100644 --- a/SU2_CFD/src/meson.build +++ b/SU2_CFD/src/meson.build @@ -11,7 +11,7 @@ su2_cfd_src += files(['fluid/CFluidModel.cpp', 'fluid/CNEMOGas.cpp', 'fluid/CMutationTCLib.cpp', 'fluid/CSU2TCLib.cpp', - 'fluid/CMLPGas_Template.cpp']) + 'fluid/CMLPGas.cpp']) su2_cfd_src += files(['output/COutputFactory.cpp', 'output/CAdjElasticityOutput.cpp', diff --git a/SU2_CFD/src/solvers/CEulerSolver.cpp b/SU2_CFD/src/solvers/CEulerSolver.cpp index 43dcd3de27c..35338ebbfda 100644 --- a/SU2_CFD/src/solvers/CEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CEulerSolver.cpp @@ -32,6 +32,7 @@ #include "../../include/fluid/CIdealGas.hpp" #include "../../include/fluid/CVanDerWaalsGas.hpp" #include "../../include/fluid/CPengRobinson.hpp" +#include "../../include/fluid/CMLPGas.hpp" #include "../../include/numerics_simd/CNumericsSIMD.hpp" #include "../../include/limiters/CLimiterDetails.hpp" @@ -857,6 +858,12 @@ void CEulerSolver::SetNondimensionalization(CConfig *config, unsigned short iMes auxFluidModel = new CPengRobinson(Gamma, config->GetGas_Constant(), config->GetPressure_Critical(), config->GetTemperature_Critical(), config->GetAcentric_Factor()); break; + + case MLP_GAS: + + auxFluidModel = new CMLPGas(config); + + break; default: SU2_MPI::Error("Unknown fluid model.", CURRENT_FUNCTION); @@ -1070,6 +1077,11 @@ void CEulerSolver::SetNondimensionalization(CConfig *config, unsigned short iMes config->GetTemperature_Critical() / config->GetTemperature_Ref(), config->GetAcentric_Factor()); break; + + case MLP_GAS: + FluidModel[thread] = new CMLPGas(config); + + break; } GetFluidModel()->SetEnergy_Prho(Pressure_FreeStreamND, Density_FreeStreamND); diff --git a/SU2_CFD/src/solvers/CIncEulerSolver.cpp b/SU2_CFD/src/solvers/CIncEulerSolver.cpp index 371055f31bb..796144f085f 100644 --- a/SU2_CFD/src/solvers/CIncEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CIncEulerSolver.cpp @@ -30,6 +30,7 @@ #include "../../include/fluid/CConstantDensity.hpp" #include "../../include/fluid/CIncIdealGas.hpp" #include "../../include/fluid/CIncIdealGasPolynomial.hpp" +#include "../../include/fluid/CMLPGas.hpp" #include "../../include/variables/CIncNSVariable.hpp" #include "../../include/limiters/CLimiterDetails.hpp" #include "../../../Common/include/toolboxes/geometry_toolbox.hpp" @@ -330,6 +331,13 @@ void CIncEulerSolver::SetNondimensionalization(CConfig *config, unsigned short i config->SetPressure_Thermodynamic(Pressure_Thermodynamic); break; + case MLP_GAS: + auxFluidModel = new CMLPGas(config); + auxFluidModel->SetTDState_T(Temperature_FreeStream); + Pressure_Thermodynamic = auxFluidModel->GetPressure(); + config->SetPressure_Thermodynamic(Pressure_Thermodynamic); + break; + default: SU2_MPI::Error("Fluid model not implemented for incompressible solver.", CURRENT_FUNCTION); @@ -492,6 +500,11 @@ void CIncEulerSolver::SetNondimensionalization(CConfig *config, unsigned short i fluidModel->SetTDState_T(Temperature_FreeStreamND); break; + case MLP_GAS: + fluidModel = new CMLPGas(config); + fluidModel->SetTDState_T(Temperature_FreeStreamND); + break; + } if (viscous) { From 167e5d29bdaba5e0a60c9b656b265a2ca010957f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Bl=C3=BChdorn?= Date: Wed, 9 Nov 2022 17:01:40 +0100 Subject: [PATCH 037/598] CoDiPack update. --- externals/codi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/codi b/externals/codi index 96ac78ec5bc..82e80e953d3 160000 --- a/externals/codi +++ b/externals/codi @@ -1 +1 @@ -Subproject commit 96ac78ec5bcc5ac25b785e79b16ed76fca22d736 +Subproject commit 82e80e953d3aa1486d9879909308af51ed8159dc From 6a95f5a4e7967b0ef2518edaa75fcee6a4cd9384 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Bl=C3=BChdorn?= Date: Wed, 9 Nov 2022 17:03:14 +0100 Subject: [PATCH 038/598] OpDiLib update. --- externals/opdi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/externals/opdi b/externals/opdi index 1aabf5bd1ed..13350bc3b57 160000 --- a/externals/opdi +++ b/externals/opdi @@ -1 +1 @@ -Subproject commit 1aabf5bd1ed77611742eb655002f2ac7a3dddef9 +Subproject commit 13350bc3b57d27e1845af0e8998eafee22b29593 From c1940410d8a1c08aa40967cf9ffea0a32bde7229 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Bl=C3=BChdorn?= Date: Wed, 9 Nov 2022 17:06:03 +0100 Subject: [PATCH 039/598] Adapt AD names and syntax to CoDiPack 2. --- Common/include/basic_types/ad_structure.hpp | 91 ++++++++++--------- Common/include/code_config.hpp | 2 +- Common/include/linear_algebra/CSysSolve_b.hpp | 2 +- .../include/parallelization/mpi_structure.hpp | 4 +- .../include/parallelization/omp_structure.cpp | 2 - Common/src/basic_types/ad_structure.cpp | 2 +- Common/src/linear_algebra/CSysSolve.cpp | 16 ++-- Common/src/linear_algebra/CSysSolve_b.cpp | 2 +- SU2_CFD/src/SU2_CFD.cpp | 5 - .../src/drivers/CDiscAdjMultizoneDriver.cpp | 2 +- .../src/drivers/CDiscAdjSinglezoneDriver.cpp | 2 +- SU2_DOT/src/SU2_DOT.cpp | 10 -- 12 files changed, 63 insertions(+), 77 deletions(-) diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 27e7946a622..0dfcbddf380 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -290,13 +290,13 @@ namespace AD{ inline void EndNoSharedReading() {} #else - using CheckpointHandler = codi::DataStore; + using CheckpointHandler = codi::ExternalFunctionUserData; - using Tape = su2double::TapeType; + using Tape = su2double::Tape; using ExtFuncHelper = codi::ExternalFunctionHelper; - extern ExtFuncHelper* FuncHelper; + extern ExtFuncHelper FuncHelper; extern bool PreaccActive; #ifdef HAVE_OPDI @@ -306,11 +306,11 @@ namespace AD{ extern bool PreaccEnabled; #ifdef HAVE_OPDI - using CoDiTapePosition = su2double::TapeType::Position; + using CoDiTapePosition = Tape::Position; using OpDiState = void*; using TapePosition = std::pair; #else - using TapePosition = su2double::TapeType::Position; + using TapePosition = Tape::Position; #endif extern TapePosition StartPosition, EndPosition; @@ -324,45 +324,45 @@ namespace AD{ /*--- Reference to the tape. ---*/ - FORCEINLINE su2double::TapeType& getGlobalTape() {return su2double::getGlobalTape();} + FORCEINLINE Tape& getTape() {return su2double::getTape();} - FORCEINLINE void RegisterInput(su2double &data) {AD::getGlobalTape().registerInput(data);} + FORCEINLINE void RegisterInput(su2double &data) {AD::getTape().registerInput(data);} - FORCEINLINE void RegisterOutput(su2double& data) {AD::getGlobalTape().registerOutput(data);} + FORCEINLINE void RegisterOutput(su2double& data) {AD::getTape().registerOutput(data);} FORCEINLINE void ResetInput(su2double &data) {data = data.getValue();} - FORCEINLINE void StartRecording() {AD::getGlobalTape().setActive();} + FORCEINLINE void StartRecording() {AD::getTape().setActive();} - FORCEINLINE void StopRecording() {AD::getGlobalTape().setPassive();} + FORCEINLINE void StopRecording() {AD::getTape().setPassive();} - FORCEINLINE bool TapeActive() { return AD::getGlobalTape().isActive(); } + FORCEINLINE bool TapeActive() { return AD::getTape().isActive(); } - FORCEINLINE void PrintStatistics() {AD::getGlobalTape().printStatistics();} + FORCEINLINE void PrintStatistics() {AD::getTape().printStatistics();} - FORCEINLINE void ClearAdjoints() {AD::getGlobalTape().clearAdjoints(); } + FORCEINLINE void ClearAdjoints() {AD::getTape().clearAdjoints(); } FORCEINLINE void ComputeAdjoint() { #if defined(HAVE_OPDI) opdi::logic->prepareEvaluate(); #endif - AD::getGlobalTape().evaluate(); + AD::getTape().evaluate(); } FORCEINLINE void ComputeAdjoint(unsigned short enter, unsigned short leave) { #if defined(HAVE_OPDI) opdi::logic->recoverState(TapePositions[enter].second); opdi::logic->prepareEvaluate(); - AD::getGlobalTape().evaluate(TapePositions[enter].first, TapePositions[leave].first); + AD::getTape().evaluate(TapePositions[enter].first, TapePositions[leave].first); #else - AD::getGlobalTape().evaluate(TapePositions[enter], TapePositions[leave]); + AD::getTape().evaluate(TapePositions[enter], TapePositions[leave]); #endif } - FORCEINLINE void ComputeAdjointForward() {AD::getGlobalTape().evaluateForward();} + FORCEINLINE void ComputeAdjointForward() {AD::getTape().evaluateForward();} FORCEINLINE void Reset() { - AD::getGlobalTape().reset(); + AD::getTape().reset(); #if defined(HAVE_OPDI) opdi::logic->reset(); #endif @@ -377,15 +377,19 @@ namespace AD{ } FORCEINLINE void SetIndex(int &index, const su2double &data) { - index = data.getGradientData(); + index = data.getIdentifier(); } FORCEINLINE void SetDerivative(int index, const double val) { - AD::getGlobalTape().setGradient(index, val); + AD::getTape().setGradient(index, val); } FORCEINLINE double GetDerivative(int index) { - return AD::getGlobalTape().getGradient(index); + return AD::getTape().getGradient(index); + } + + FORCEINLINE bool IsIdentifierActive(su2double const& value) { + return getTape().isIdentifierActive(value.getIdentifier()); } /*--- Base case for parameter pack expansion. ---*/ @@ -394,7 +398,7 @@ namespace AD{ template::value> = 0> FORCEINLINE void SetPreaccIn(const T& data, Ts&&... moreData) { if (!PreaccActive) return; - if (data.isActive()) + if (IsIdentifierActive(data)) PreaccHelper.addInput(data); SetPreaccIn(moreData...); } @@ -408,7 +412,7 @@ namespace AD{ FORCEINLINE void SetPreaccIn(const T& data, const int size) { if (PreaccActive) { for (int i = 0; i < size; i++) { - if (data[i].isActive()) { + if (IsIdentifierActive(data[i])) { PreaccHelper.addInput(data[i]); } } @@ -420,7 +424,7 @@ namespace AD{ if (!PreaccActive) return; for (int i = 0; i < size_x; i++) { for (int j = 0; j < size_y; j++) { - if (data[i][j].isActive()) { + if (IsIdentifierActive(data[i][j])) { PreaccHelper.addInput(data[i][j]); } } @@ -428,7 +432,7 @@ namespace AD{ } FORCEINLINE void StartPreacc() { - if (AD::getGlobalTape().isActive() && PreaccEnabled) { + if (AD::getTape().isActive() && PreaccEnabled) { PreaccHelper.start(); PreaccActive = true; } @@ -440,7 +444,7 @@ namespace AD{ template::value> = 0> FORCEINLINE void SetPreaccOut(T& data, Ts&&... moreData) { if (!PreaccActive) return; - if (data.isActive()) + if (IsIdentifierActive(data)) PreaccHelper.addOutput(data); SetPreaccOut(moreData...); } @@ -449,7 +453,7 @@ namespace AD{ FORCEINLINE void SetPreaccOut(T&& data, const int size) { if (PreaccActive) { for (int i = 0; i < size; i++) { - if (data[i].isActive()) { + if (IsIdentifierActive(data[i])) { PreaccHelper.addOutput(data[i]); } } @@ -461,7 +465,7 @@ namespace AD{ if (!PreaccActive) return; for (int i = 0; i < size_x; i++) { for (int j = 0; j < size_y; j++) { - if (data[i][j].isActive()) { + if (IsIdentifierActive(data[i][j])) { PreaccHelper.addOutput(data[i][j]); } } @@ -470,9 +474,9 @@ namespace AD{ FORCEINLINE void Push_TapePosition() { #if defined(HAVE_OPDI) - TapePositions.push_back({AD::getGlobalTape().getPosition(), opdi::logic->exportState()}); + TapePositions.push_back({AD::getTape().getPosition(), opdi::logic->exportState()}); #else - TapePositions.push_back(AD::getGlobalTape().getPosition()); + TapePositions.push_back(AD::getTape().getPosition()); #endif } @@ -484,23 +488,22 @@ namespace AD{ } FORCEINLINE void StartExtFunc(bool storePrimalInput, bool storePrimalOutput){ - FuncHelper = new ExtFuncHelper(true); if (!storePrimalInput){ - FuncHelper->disableInputPrimalStore(); + FuncHelper.disableInputPrimalStore(); } if (!storePrimalOutput){ - FuncHelper->disableOutputPrimalStore(); + FuncHelper.disableOutputPrimalStore(); } } FORCEINLINE void SetExtFuncIn(const su2double &data) { - FuncHelper->addInput(data); + FuncHelper.addInput(data); } template FORCEINLINE void SetExtFuncIn(const T& data, const int size) { for (int i = 0; i < size; i++) { - FuncHelper->addInput(data[i]); + FuncHelper.addInput(data[i]); } } @@ -508,22 +511,22 @@ namespace AD{ FORCEINLINE void SetExtFuncIn(const T& data, const int size_x, const int size_y) { for (int i = 0; i < size_x; i++) { for (int j = 0; j < size_y; j++) { - FuncHelper->addInput(data[i][j]); + FuncHelper.addInput(data[i][j]); } } } FORCEINLINE void SetExtFuncOut(su2double& data) { - if (AD::getGlobalTape().isActive()) { - FuncHelper->addOutput(data); + if (AD::getTape().isActive()) { + FuncHelper.addOutput(data); } } template FORCEINLINE void SetExtFuncOut(T&& data, const int size) { for (int i = 0; i < size; i++) { - if (AD::getGlobalTape().isActive()) { - FuncHelper->addOutput(data[i]); + if (AD::getTape().isActive()) { + FuncHelper.addOutput(data[i]); } } } @@ -532,8 +535,8 @@ namespace AD{ FORCEINLINE void SetExtFuncOut(T&& data, const int size_x, const int size_y) { for (int i = 0; i < size_x; i++) { for (int j = 0; j < size_y; j++) { - if (AD::getGlobalTape().isActive()) { - FuncHelper->addOutput(data[i][j]); + if (AD::getTape().isActive()) { + FuncHelper.addOutput(data[i][j]); } } } @@ -544,10 +547,10 @@ namespace AD{ checkpoint->clear(); } - FORCEINLINE void EndExtFunc() { delete FuncHelper; } + FORCEINLINE void EndExtFunc() { } FORCEINLINE bool BeginPassive() { - if(AD::getGlobalTape().isActive()) { + if(AD::getTape().isActive()) { StopRecording(); return true; } diff --git a/Common/include/code_config.hpp b/Common/include/code_config.hpp index 7bb34cffbdb..4547054f800 100644 --- a/Common/include/code_config.hpp +++ b/Common/include/code_config.hpp @@ -87,7 +87,7 @@ FORCEINLINE Out su2staticcast_p(In ptr) { #if defined(CODI_REVERSE_TYPE) // reverse mode AD #include "codi.hpp" -#include "codi/tools/dataStore.hpp" +#include "codi/tools/data/externalFunctionUserData.hpp" #if defined(HAVE_OMP) using su2double = codi::RealReverseIndexParallel; diff --git a/Common/include/linear_algebra/CSysSolve_b.hpp b/Common/include/linear_algebra/CSysSolve_b.hpp index eae9de62ad4..006a5e09583 100644 --- a/Common/include/linear_algebra/CSysSolve_b.hpp +++ b/Common/include/linear_algebra/CSysSolve_b.hpp @@ -34,6 +34,6 @@ template struct CSysSolve_b { static void Solve_b(const su2double::Real* x, su2double::Real* x_b, size_t m, const su2double::Real* y, const su2double::Real* y_b, size_t n, - codi::DataStore* d); + codi::ExternalFunctionUserData* d); }; #endif diff --git a/Common/include/parallelization/mpi_structure.hpp b/Common/include/parallelization/mpi_structure.hpp index 06a65a6fef7..980572dc7eb 100644 --- a/Common/include/parallelization/mpi_structure.hpp +++ b/Common/include/parallelization/mpi_structure.hpp @@ -68,12 +68,12 @@ #include using namespace medi; -#include +#include class CMediMPIWrapper; typedef CMediMPIWrapper SU2_MPI; -typedef CoDiMpiTypes MediTypes; +typedef codi::CoDiMpiTypes MediTypes; typedef MediTypes::Tool MediTool; extern MediTypes* mediTypes; diff --git a/Common/include/parallelization/omp_structure.cpp b/Common/include/parallelization/omp_structure.cpp index 09a50c3ba72..ed690b78f6b 100644 --- a/Common/include/parallelization/omp_structure.cpp +++ b/Common/include/parallelization/omp_structure.cpp @@ -36,7 +36,6 @@ void omp_initialize() { #endif opdi::logic = new opdi::OmpLogic; opdi::logic->init(); - su2double::getGlobalTape().initialize(); opdi::tool = new CoDiOpDiTool; opdi::tool->init(); #endif @@ -45,7 +44,6 @@ void omp_initialize() { void omp_finalize() { #ifdef HAVE_OPDI opdi::tool->finalize(); - su2double::getGlobalTape().finalize(); opdi::logic->finalize(); opdi::backend->finalize(); delete opdi::tool; diff --git a/Common/src/basic_types/ad_structure.cpp b/Common/src/basic_types/ad_structure.cpp index d67bd486a8b..77b09675efd 100644 --- a/Common/src/basic_types/ad_structure.cpp +++ b/Common/src/basic_types/ad_structure.cpp @@ -46,7 +46,7 @@ namespace AD { SU2_OMP(threadprivate(PreaccHelper)) #endif - ExtFuncHelper* FuncHelper; + ExtFuncHelper FuncHelper; #endif } diff --git a/Common/src/linear_algebra/CSysSolve.cpp b/Common/src/linear_algebra/CSysSolve.cpp index 54406fdfc8c..3d7659d4441 100644 --- a/Common/src/linear_algebra/CSysSolve.cpp +++ b/Common/src/linear_algebra/CSysSolve.cpp @@ -864,7 +864,7 @@ unsigned long CSysSolve::Solve(CSysMatrix & Jacobian, co if (config->GetDiscrete_Adjoint()) { #ifdef CODI_REVERSE_TYPE - TapeActive = AD::getGlobalTape().isActive(); + TapeActive = AD::TapeActive(); BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS { AD::StartExtFunc(false, false); @@ -971,16 +971,16 @@ unsigned long CSysSolve::Solve(CSysMatrix & Jacobian, co BEGIN_SU2_OMP_SAFE_GLOBAL_ACCESS { AD::SetExtFuncOut(&LinSysSol[0], LinSysSol.GetLocSize()); - AD::FuncHelper->addUserData(&LinSysRes); - AD::FuncHelper->addUserData(&LinSysSol); - AD::FuncHelper->addUserData(&Jacobian); - AD::FuncHelper->addUserData(geometry); - AD::FuncHelper->addUserData(config); - AD::FuncHelper->addUserData(this); + AD::FuncHelper.addUserData(&LinSysRes); + AD::FuncHelper.addUserData(&LinSysSol); + AD::FuncHelper.addUserData(&Jacobian); + AD::FuncHelper.addUserData(geometry); + AD::FuncHelper.addUserData(config); + AD::FuncHelper.addUserData(this); } END_SU2_OMP_SAFE_GLOBAL_ACCESS - AD::FuncHelper->addToTape(CSysSolve_b::Solve_b); + AD::FuncHelper.addToTape(CSysSolve_b::Solve_b); SU2_OMP_SAFE_GLOBAL_ACCESS(AD::EndExtFunc();) #endif diff --git a/Common/src/linear_algebra/CSysSolve_b.cpp b/Common/src/linear_algebra/CSysSolve_b.cpp index c381eb26d39..3db62e67fa2 100644 --- a/Common/src/linear_algebra/CSysSolve_b.cpp +++ b/Common/src/linear_algebra/CSysSolve_b.cpp @@ -34,7 +34,7 @@ template void CSysSolve_b::Solve_b(const su2double::Real* x, su2double::Real* x_b, size_t m, const su2double::Real* y, const su2double::Real* y_b, size_t n, - codi::DataStore* d) { + codi::ExternalFunctionUserData* d) { CSysVector* LinSysRes_b = nullptr; d->getDataByIndex(LinSysRes_b, 0); diff --git a/SU2_CFD/src/SU2_CFD.cpp b/SU2_CFD/src/SU2_CFD.cpp index d5197f8c4dc..f342a4157e7 100644 --- a/SU2_CFD/src/SU2_CFD.cpp +++ b/SU2_CFD/src/SU2_CFD.cpp @@ -164,11 +164,6 @@ int main(int argc, char *argv[]) { libxsmm_finalize(); #endif - /*--- Finalize AD, if necessary. ---*/ -#ifdef HAVE_OPDI - AD::getGlobalTape().finalize(); -#endif - /*--- Finalize MPI parallelization. ---*/ SU2_MPI::Finalize(); diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 960a2a8ef4a..34312717cc4 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -673,7 +673,7 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t if (rank == MASTER_NODE) AD::PrintStatistics(); #ifdef CODI_REVERSE_TYPE if (size > SINGLE_NODE) { - su2double myMem = AD::getGlobalTape().getTapeValues().getUsedMemorySize(), totMem = 0.0; + su2double myMem = AD::getTape().getTapeValues().getUsedMemorySize(), totMem = 0.0; SU2_MPI::Allreduce(&myMem, &totMem, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); if (rank == MASTER_NODE) { cout << "MPI\n"; diff --git a/SU2_CFD/src/drivers/CDiscAdjSinglezoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjSinglezoneDriver.cpp index 2d943c5351e..c866133edaa 100644 --- a/SU2_CFD/src/drivers/CDiscAdjSinglezoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjSinglezoneDriver.cpp @@ -304,7 +304,7 @@ void CDiscAdjSinglezoneDriver::SetRecording(RECORDING kind_recording){ if (rank == MASTER_NODE) AD::PrintStatistics(); #ifdef CODI_REVERSE_TYPE if (size > SINGLE_NODE) { - su2double myMem = AD::getGlobalTape().getTapeValues().getUsedMemorySize(), totMem = 0.0; + su2double myMem = AD::getTape().getTapeValues().getUsedMemorySize(), totMem = 0.0; SU2_MPI::Allreduce(&myMem, &totMem, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); if (rank == MASTER_NODE) { cout << "MPI\n"; diff --git a/SU2_DOT/src/SU2_DOT.cpp b/SU2_DOT/src/SU2_DOT.cpp index e15bd2af8ee..05dea2fa5ee 100644 --- a/SU2_DOT/src/SU2_DOT.cpp +++ b/SU2_DOT/src/SU2_DOT.cpp @@ -53,11 +53,6 @@ int main(int argc, char *argv[]) { const int rank = SU2_MPI::GetRank(); const int size = SU2_MPI::GetSize(); - /*--- AD initialization ---*/ -#ifdef HAVE_OPDI - AD::getGlobalTape().initialize(); -#endif - /*--- Pointer to different structures that will be used throughout the entire code ---*/ CConfig **config_container = nullptr; @@ -425,11 +420,6 @@ int main(int argc, char *argv[]) { if (rank == MASTER_NODE) cout << "\n------------------------- Exit Success (SU2_DOT) ------------------------\n" << endl; - /*--- Finalize AD, if necessary. ---*/ -#ifdef HAVE_OPDI - AD::getGlobalTape().finalize(); -#endif - /*--- Finalize MPI parallelization. ---*/ SU2_MPI::Finalize(); From e8a3a93e987c38e54e98b86c9f35d4830d3c90c9 Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Mon, 21 Nov 2022 11:34:58 +0100 Subject: [PATCH 040/598] Bug fix --- SU2_CFD/src/fluid/CPengRobinson.cpp | 50 ----------------------------- 1 file changed, 50 deletions(-) diff --git a/SU2_CFD/src/fluid/CPengRobinson.cpp b/SU2_CFD/src/fluid/CPengRobinson.cpp index 962e8a60ea1..2b5b09d611d 100644 --- a/SU2_CFD/src/fluid/CPengRobinson.cpp +++ b/SU2_CFD/src/fluid/CPengRobinson.cpp @@ -39,56 +39,6 @@ CPengRobinson::CPengRobinson(su2double gamma, su2double R, su2double Pstar, su2d k = 0.37464 + 1.54226 * w - 0.26992 * w * w; else k = 0.379642 + 1.48503 * w - 0.164423 * w * w + 0.016666 * w * w * w; - - vector call_input_variables; - vector call_output_variables; - vector call_inputs; - vector call_outputs; - call_input_variables.push_back("Progress_Variable"); - call_inputs.push_back(-5.74934292655689e-01); - call_input_variables.push_back("Enthalpy"); - call_inputs.push_back(+2.22692201641688e+03); - call_input_variables.push_back("Mixture_Fraction"); - call_inputs.push_back(0.0144045); - - call_output_variables.push_back("Temperature"); - call_outputs.push_back(&Temperature); - call_output_variables.push_back("Density"); - call_outputs.push_back(&Density); - - vector call_inputvars_lean; - call_inputvars_lean.push_back("Progress_Variable_lean"); - call_inputvars_lean.push_back("Enthalpy_lean"); - call_inputvars_lean.push_back("Mixture_Fraction_lean"); - - vector call_inputvars_rich; - call_inputvars_rich.push_back("Progress_Variable_rich"); - call_inputvars_rich.push_back("Enthalpy_rich"); - call_inputvars_rich.push_back("Mixture_Fraction_rich"); - - MLPToolbox::CLookUp_ANN * test_mlp = new MLPToolbox::CLookUp_ANN("MLP_collection.mlp"); - MLPToolbox::CIOMap * test_map = new MLPToolbox::CIOMap(test_mlp, call_input_variables, call_output_variables); - MLPToolbox::CIOMap * lean_map = new MLPToolbox::CIOMap(test_mlp, call_inputvars_lean, call_output_variables); - MLPToolbox::CIOMap * rich_map = new MLPToolbox::CIOMap(test_mlp, call_inputvars_rich, call_output_variables); - - - test_mlp->Predict_ANN(test_map, call_inputs, call_outputs); - cout << "in flame zone: " << Density << " " << Temperature << endl; - call_inputs[0] = -7.36; - call_inputs[1] = 26468.5; - call_inputs[2] = 1.0; - test_mlp->Predict_ANN(rich_map, call_inputs, call_outputs); - cout << "rich: " << Density << " " << Temperature << endl; - call_inputs[0] = -0.4753; - call_inputs[1] = 3144.6; - call_inputs[2] = 0.0; - test_mlp->Predict_ANN(lean_map, call_inputs, call_outputs); - cout << "lean: " << Density << " " << Temperature << endl; - - delete test_mlp; - delete test_map; - delete rich_map; - delete lean_map; } su2double CPengRobinson::alpha2(su2double T) const { From 0a565343307aa6a5a7f012f2779cf5c02ad4e8b7 Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Mon, 21 Nov 2022 16:57:25 +0100 Subject: [PATCH 041/598] Allowed for LUT alongside MLP evaluation in datadriven fluid model --- .../multilayer_perceptron/CNeuralNetwork.hpp | 3 + SU2_CFD/include/fluid/CDataDrivenFluid.hpp | 75 +++++-- SU2_CFD/src/fluid/CDataDrivenFluid.cpp | 211 ++++++++++++++++-- 3 files changed, 246 insertions(+), 43 deletions(-) diff --git a/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp index a7d1cfba5e4..b58528069d8 100644 --- a/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp @@ -83,6 +83,9 @@ class CNeuralNetwork delete total_layers.at(i); } delete [] ANN_outputs; + delete [] inputLayer; + delete [] outputLayer; + delete [] activation_function_types; }; void defineInputLayer(unsigned long n_neurons); void defineOutputLayer(unsigned long n_neurons); diff --git a/SU2_CFD/include/fluid/CDataDrivenFluid.hpp b/SU2_CFD/include/fluid/CDataDrivenFluid.hpp index 2866bcbebf8..79e423d6215 100644 --- a/SU2_CFD/include/fluid/CDataDrivenFluid.hpp +++ b/SU2_CFD/include/fluid/CDataDrivenFluid.hpp @@ -30,6 +30,8 @@ #include "CFluidModel.hpp" #include "../../../Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp" +#include "../../../Common/include/containers/CLookUpTable.hpp" + /*! * \class CDataDrivenFluid * \brief Template class for fluid model definition using multi-layer perceptrons for @@ -39,26 +41,35 @@ class CDataDrivenFluid : public CFluidModel { protected: - unsigned short Kind_DataDriven_Method = ENUM_DATADRIVEN_METHOD::LUT; - size_t idx_rho, - idx_e; + unsigned short Kind_DataDriven_Method = ENUM_DATADRIVEN_METHOD::LUT; // Interpolation method for data set evaluation - su2double Newton_Relaxation, - rho_start, - e_start; + size_t idx_rho, // Interpolator index for density input + idx_e; // Interpolator index for energy input - string input_filename; + su2double Newton_Relaxation, // Relaxation factor for Newton solvers. + rho_start, // Initial value for the density in Newton solver processes. + e_start; // Initial value for the energy in Newton solver processes. - vector input_names_rhoe, - output_names_rhoe; + string input_filename; // Data-driven method input file name. + + su2double dsde_rho, dsdrho_e, d2sde2, d2sdedrho, d2sdrho2; + + su2double Gamma{0.0}; /*!< \brief Ratio of Specific Heats. */ + su2double Gamma_Minus_One{0.0}; /*!< \brief Ratio of Specific Heats Minus One. */ + su2double Gas_Constant{0.0}; /*!< \brief Gas Constant. */ + + vector input_names_rhoe, // Data-driven method input variable names of the independent variables (density, energy). + output_names_rhoe; // Output variable names listed in the data-driven method input file name. - vector outputs_rhoe; + vector outputs_rhoe; // Pointers to output variables. - MLPToolbox::CLookUp_ANN * lookup_mlp; - MLPToolbox::CIOMap * iomap_rhoe; - vector MLP_inputs; + /*--- Class variables for the multi-layer perceptron method ---*/ + MLPToolbox::CLookUp_ANN * lookup_mlp; // multi-layer perceptron collection. + MLPToolbox::CIOMap * iomap_rhoe; // input-output map. + vector MLP_inputs; // inputs for the multi-layer perceptron look-up operation. - + /*--- Class variables for the look-up table method ---*/ + CLookUpTable *lookup_table; void MapInputs_to_Outputs(); @@ -71,29 +82,49 @@ class CDataDrivenFluid : public CFluidModel { ~CDataDrivenFluid(); /*! * \brief Set the Dimensionless State using Density and Internal Energy - * \param[in] rho - first thermodynamic variable. - * \param[in] e - second thermodynamic variable. + * \param[in] rho - first thermodynamic variable (density). + * \param[in] e - second thermodynamic variable (static energy). */ void SetTDState_rhoe(su2double rho, su2double e) override; /*! * \brief Set the Dimensionless State using Pressure and Temperature - * \param[in] P - first thermodynamic variable. - * \param[in] T - second thermodynamic variable. + * \param[in] P - first thermodynamic variable (pressure). + * \param[in] T - second thermodynamic variable (temperature). */ void SetTDState_PT(su2double P, su2double T) override; /*! * \brief Set the Dimensionless State using Pressure and Density - * \param[in] P - first thermodynamic variable. - * \param[in] rho - second thermodynamic variable. + * \param[in] P - first thermodynamic variable (pressure). + * \param[in] rho - second thermodynamic variable (density). */ void SetTDState_Prho(su2double P, su2double rho) override; /*! * \brief Set the Dimensionless Internal Energy using Pressure and Density - * \param[in] P - first thermodynamic variable. - * \param[in] rho - second thermodynamic variable. + * \param[in] P - first thermodynamic variable (pressure). + * \param[in] rho - second thermodynamic variable (density). */ void SetEnergy_Prho(su2double P, su2double rho) override; + + /*! + * \brief Set the Dimensionless Internal Energy using Pressure and Density + * \param[in] rho - second thermodynamic variable (density). + */ + void SetTDState_rhoT(su2double rho, su2double T) override; + + /*! + * \brief Set the Dimensionless State using Enthalpy and Entropy + * \param[in] h - first thermodynamic variable (h). + * \param[in] s - second thermodynamic variable (s). + */ + void SetTDState_hs(su2double h, su2double s) override; + + /*! + * \brief Set the Dimensionless State using Pressure and Entropy + * \param[in] P - first thermodynamic variable (P). + * \param[in] s - second thermodynamic variable (s). + */ + void SetTDState_Ps(su2double P, su2double s) override; }; diff --git a/SU2_CFD/src/fluid/CDataDrivenFluid.cpp b/SU2_CFD/src/fluid/CDataDrivenFluid.cpp index 4f4b7e95790..7dafd4bf5e6 100644 --- a/SU2_CFD/src/fluid/CDataDrivenFluid.cpp +++ b/SU2_CFD/src/fluid/CDataDrivenFluid.cpp @@ -44,6 +44,9 @@ CDataDrivenFluid::CDataDrivenFluid(const CConfig* config) : CFluidModel() { case ENUM_DATADRIVEN_METHOD::MLP: lookup_mlp = new MLPToolbox::CLookUp_ANN(input_filename); break; + case ENUM_DATADRIVEN_METHOD::LUT: + lookup_table = new CLookUpTable(input_filename, "Density", "Energy"); + break; default: break; } @@ -66,7 +69,9 @@ CDataDrivenFluid::~CDataDrivenFluid(){ delete iomap_rhoe; delete lookup_mlp; break; - + case ENUM_DATADRIVEN_METHOD::LUT: + delete lookup_table; + break; default: break; } @@ -80,23 +85,19 @@ void CDataDrivenFluid::MapInputs_to_Outputs(){ input_names_rhoe.push_back("Energy"); idx_e = 1; - /*--- Required outputs for the interpolation method are primary and secondary thermodynamic variables. ---*/ - output_names_rhoe.push_back("Temperature"); - outputs_rhoe.push_back(&Temperature); - output_names_rhoe.push_back("Pressure"); - outputs_rhoe.push_back(&Pressure); - output_names_rhoe.push_back("SoundSpeed2"); - outputs_rhoe.push_back(&SoundSpeed2); - output_names_rhoe.push_back("dPdrho_e"); - outputs_rhoe.push_back(&dPdrho_e); - output_names_rhoe.push_back("dPde_rho"); - outputs_rhoe.push_back(&dPde_rho); - output_names_rhoe.push_back("dTdrho_e"); - outputs_rhoe.push_back(&dTdrho_e); - output_names_rhoe.push_back("dTde_rho"); - outputs_rhoe.push_back(&dTde_rho); - output_names_rhoe.push_back("Entropy"); + /*--- Required outputs for the interpolation method are entropy and its partial derivatives with respect to energy and density ---*/ + output_names_rhoe.push_back("s"); outputs_rhoe.push_back(&Entropy); + output_names_rhoe.push_back("dsde_rho"); + outputs_rhoe.push_back(&dsde_rho); + output_names_rhoe.push_back("dsdrho_e"); + outputs_rhoe.push_back(&dsdrho_e); + output_names_rhoe.push_back("d2sde2"); + outputs_rhoe.push_back(&d2sde2); + output_names_rhoe.push_back("d2sdedrho"); + outputs_rhoe.push_back(&d2sdedrho); + output_names_rhoe.push_back("d2sdrho2"); + outputs_rhoe.push_back(&d2sdrho2); /*--- Further preprocessing of input and output variables ---*/ switch (Kind_DataDriven_Method) @@ -125,15 +126,37 @@ void CDataDrivenFluid::SetTDState_rhoe(su2double rho, su2double e) { /* --- Evaluate MLP --- */ lookup_mlp->Predict_ANN(iomap_rhoe, MLP_inputs, outputs_rhoe); break; - + case ENUM_DATADRIVEN_METHOD::LUT: + lookup_table->LookUp_ProgEnth(output_names_rhoe, outputs_rhoe, rho, e, "Density", "Energy"); default: break; } + su2double blue_term = (dsdrho_e * (2 - rho * pow(dsde_rho, -1) * d2sdedrho) + rho * d2sdrho2); + su2double green_term = (- pow(dsde_rho, -1) * d2sde2 * dsdrho_e + d2sdedrho); + + SoundSpeed2 = - rho * pow(dsde_rho, -1) * (blue_term - rho * green_term * (dsdrho_e / dsde_rho)); + + Temperature = 1.0 / dsde_rho; + Pressure = -pow(rho, 2) * Temperature * dsdrho_e; + Density = rho; + StaticEnergy = e; + + dTde_rho = -pow(dsde_rho, -2)*d2sde2; + dTdrho_e = 0.0; + + dPde_rho = -pow(rho, 2) * dTde_rho * dsdrho_e; + dPdrho_e = -2*rho*Temperature*dsdrho_e - pow(rho, 2)*Temperature*d2sdrho2; + + Cp = (1 / dTde_rho) * ( 1 + (1 / Density)*dPde_rho) + (1/Density)*(1/dTdrho_e)*(dPdrho_e - Pressure / Density); + Cv = 1 / dTde_rho; + Gamma = Cp / Cv; + Gamma_Minus_One = Gamma - 1; + Gas_Constant = Cp - Cv; + } void CDataDrivenFluid::SetTDState_PT(su2double P, su2double T) { - /*--- Newton solver for */ /*--- Setting initial values for density and energy ---*/ su2double rho = rho_start, @@ -152,6 +175,7 @@ void CDataDrivenFluid::SetTDState_PT(su2double P, su2double T) { delta_e, // Energy step size determinant; // Jacobian determinant + /*--- Initiating Newton solver ---*/ while(!converged && (Iter < iter_max)){ /*--- Determine thermodynamic state based on current density and energy*/ @@ -220,8 +244,8 @@ void CDataDrivenFluid::SetEnergy_Prho(su2double P, su2double rho) { /*--- Compute step size for energy ---*/ delta_e = delta_P / dPde_rho; - /*--- Update density and energy values ---*/ - e -= Newton_Relaxation * delta_e; + /*--- energy value ---*/ + e += Newton_Relaxation * delta_e; } Iter ++; } @@ -229,3 +253,148 @@ void CDataDrivenFluid::SetEnergy_Prho(su2double P, su2double rho) { /*--- Setting static energy as the converged value ---*/ StaticEnergy = e; } + +void CDataDrivenFluid::SetTDState_rhoT(su2double rho, su2double T) { + + /*--- Setting initial values for density and energy ---*/ + su2double e = e_start; + + su2double tolerance_T = 1; // Tolerance for temperature solution + + bool converged = false; // Convergence flag + unsigned long iter_max = 1000, // Maximum number of iterations + Iter = 0; + + su2double delta_T, // Temperature residual + delta_e; // Energy increment + + /*--- Initiating Newton solver ---*/ + while(!converged && (Iter < iter_max)){ + + /*--- Determine thermodynamic state based on current density and energy*/ + SetTDState_rhoe(rho ,e); + + /*--- Determine temperature residual ---*/ + delta_T = Temperature - T; + + /*--- Continue iterative process if residuals are outside tolerances ---*/ + if((abs(delta_T) < tolerance_T)){ + converged = true; + }else{ + + + delta_e = delta_T / dTde_rho; + + /*--- Update energy value ---*/ + e += Newton_Relaxation * delta_e; + } + Iter ++; + } + + /*--- Calculate thermodynamic state based on converged values for density and energy ---*/ + SetTDState_rhoe(rho, e); +} + +void CDataDrivenFluid::SetTDState_hs(su2double h, su2double s) { + + /*--- Setting initial values for density and energy ---*/ + su2double rho = rho_start, + e = e_start; + + su2double tolerance_h = 10, // Tolerance for enthalpy solution + tolerance_s = 1; // Tolerance for entropy solution + + bool converged = false; // Convergence flag + unsigned long iter_max = 1000, // Maximum number of iterations + Iter = 0; + + su2double delta_h, // Enthalpy + delta_s, // Entropy residual + delta_rho, // Density step size + delta_e, // Energy step size + determinant; // Jacobian determinant + + /*--- Initiating Newton solver ---*/ + while(!converged && (Iter < iter_max)){ + + /*--- Determine thermodynamic state based on current density and energy*/ + SetTDState_rhoe(rho ,e); + + su2double Enthalpy = e + Pressure / rho; + /*--- Determine pressure and temperature residuals ---*/ + delta_h = Enthalpy - h; + delta_s = Entropy - s; + + /*--- Continue iterative process if residuals are outside tolerances ---*/ + if((abs(delta_h) < tolerance_h) && (abs(delta_s) < tolerance_s)){ + converged = true; + }else{ + + su2double dh_de = 1 + dPde_rho / rho; + su2double dh_drho = -Pressure*pow(rho, -2) + dPdrho_e / rho; + + determinant = dh_drho * dsde_rho - dh_de * dsdrho_e; + delta_rho = (dsde_rho * delta_h - dh_de * delta_s) / determinant; + delta_e = (-dsdrho_e * delta_h + dh_drho * delta_s) / determinant; + + /*--- Update density and energy values ---*/ + rho -= Newton_Relaxation * delta_rho; + e -= Newton_Relaxation * delta_e; + } + Iter ++; + } + + /*--- Calculate thermodynamic state based on converged values for density and energy ---*/ + SetTDState_rhoe(rho, e); +} + +void CDataDrivenFluid::SetTDState_Ps(su2double P, su2double s) { + + /*--- Setting initial values for density and energy ---*/ + su2double rho = rho_start, + e = e_start; + + su2double tolerance_P = 10, // Tolerance for pressure solution + tolerance_s = 1; // Tolerance for entropy solution + + bool converged = false; // Convergence flag + unsigned long iter_max = 1000, // Maximum number of iterations + Iter = 0; + + su2double delta_P, // Enthalpy + delta_s, // Entropy residual + delta_rho, // Density step size + delta_e, // Energy step size + determinant; // Jacobian determinant + + /*--- Initiating Newton solver ---*/ + while(!converged && (Iter < iter_max)){ + + /*--- Determine thermodynamic state based on current density and energy*/ + SetTDState_rhoe(rho ,e); + + /*--- Determine pressure and temperature residuals ---*/ + delta_P = Pressure - P; + delta_s = Entropy - s; + + /*--- Continue iterative process if residuals are outside tolerances ---*/ + if((abs(delta_P) < tolerance_P) && (abs(delta_s) < tolerance_s)){ + converged = true; + }else{ + + /*--- Compute step size for density and energy ---*/ + determinant = dPdrho_e * dsde_rho - dPde_rho * dsdrho_e; + + delta_rho = (dsde_rho * delta_P - dPde_rho * delta_s) / determinant; + delta_e = (-dsdrho_e * delta_P + dPdrho_e * delta_s) / determinant; + + /*--- Update density and energy values ---*/ + rho -= Newton_Relaxation * delta_rho; + e -= Newton_Relaxation * delta_e; + } + Iter ++; + } + + /*--- Calculate thermodynamic state based on converged values for density and energy ---*/ + SetTDState_rhoe(rho, e); +} \ No newline at end of file From 8ce5a260cec8fefcbd240081d2153de5ec8e321c Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Mon, 21 Nov 2022 17:15:11 +0100 Subject: [PATCH 042/598] Replaced progress variable and enthalpy variables in the CLookUpTable class with x and y --- Common/include/containers/CLookUpTable.hpp | 102 +++++++------- Common/src/containers/CLookUpTable.cpp | 154 ++++++++++----------- 2 files changed, 128 insertions(+), 128 deletions(-) diff --git a/Common/include/containers/CLookUpTable.hpp b/Common/include/containers/CLookUpTable.hpp index ecb59c97aa1..1d93cdea516 100644 --- a/Common/include/containers/CLookUpTable.hpp +++ b/Common/include/containers/CLookUpTable.hpp @@ -53,10 +53,10 @@ class CLookUpTable { unsigned long n_hull_points; /*! - * \brief the lower and upper limits of the enthalpy and progress variable. + * \brief the lower and upper limits of the y and x. */ - su2double limits_table_enth[2]; - su2double limits_table_prog[2]; + su2double limits_table_y[2]; + su2double limits_table_x[2]; /*! \brief Holds the variable names stored in the table file. * Order is in sync with data @@ -80,12 +80,12 @@ class CLookUpTable { */ std::vector hull; - CTrapezoidalMap trap_map_prog_enth; + CTrapezoidalMap trap_map_x_y; /*! \brief * vector of all the weight factors for the interpolation. */ - std::vector interp_mat_inv_prog_enth; + std::vector interp_mat_inv_x_y; /*! \brief * returns the index to the variable in the lookup table. @@ -112,12 +112,12 @@ class CLookUpTable { /*! * \brief find the table limits, i.e. the minimum and maximum values of the 2 independent. - * controlling variables (progress variable and enthalpy). We put the values in the variables. - * limits_table_prog[2] and limit_table_enth[2]. - * \param[in] name_prog - the string name for the first controlling variable. - * \param[in] name_enth - the string name of the second controlling variable. + * controlling variables (x and y). We put the values in the variables. + * limits_table_x[2] and limit_table_y[2]. + * \param[in] name_x - the string name for the first controlling variable. + * \param[in] name_y - the string name of the second controlling variable. */ - void FindTableLimits(const std::string& name_prog, const std::string& name_enth); + void FindTableLimits(const std::string& name_x, const std::string& name_y); /*! * \brief construct a list of all the edges and a list of the pair of elements left and right of the edge. @@ -132,15 +132,15 @@ class CLookUpTable { /*! * \brief compute vector of all (inverse) interpolation coefficients "interp_mat_inv_prog_enth" of all triangles. - * \param[in] name_prog - the string name of the first controlling variable (progress variable). - * \param[in] name_enth - the string name of the second controlling variable (enthalpy). + * \param[in] name_prog - the string name of the first controlling variable (x). + * \param[in] name_enth - the string name of the second controlling variable (y). */ - void ComputeInterpCoeffs(const std::string& name_prog, const std::string& name_enth); + void ComputeInterpCoeffs(const std::string& name_x, const std::string& name_y); /*! * \brief compute the inverse matrix for interpolation. - * \param[in] vec_x - pointer to first coordinate (progress variable). - * \param[in] vec_y - pointer to second coordinate (enthalpy). + * \param[in] vec_x - pointer to first coordinate (x). + * \param[in] vec_y - pointer to second coordinate (y). * \param[in] point_ids - single triangle data. * \param[out] interp_mat_inv - inverse matrix for interpolation. */ @@ -149,8 +149,8 @@ class CLookUpTable { /*! * \brief compute the interpolation coefficients for the triangular interpolation. - * \param[in] val_x - value of first coordinate (progress variable). - * \param[in] val_y - value of second coordinate (enthalpy). + * \param[in] val_x - value of first coordinate (x). + * \param[in] val_y - value of second coordinate (y). * \param[in] interp_mat_inv - inverse matrix for interpolation. * \param[out] interp_coeffs - interpolation coefficients. */ @@ -168,14 +168,14 @@ class CLookUpTable { std::array& val_interp_coeffs); /*! - * \brief find the point on the hull (boundary of the table) that is closest to the point P(val_prog,val_enth). + * \brief find the point on the hull (boundary of the table) that is closest to the point P(val_x,val_y). * \param[in] val_x - first coordinate of point P(val_x,val_y) to check. * \param[in] val_y - second coordinate of point P(val_x,val_y) to check. * \param[in] name_prog - string name of the first controlling variable. * \param[in] name_enth - string name of the second controlling variable. * \returns point id of the nearest neighbor on the hull. */ - unsigned long FindNearestNeighborOnHull(su2double val_prog, su2double val_enth, const std::string& name_prog, const std::string& name_enth); + unsigned long FindNearestNeighborOnHull(su2double val_x, su2double val_y, const std::string& name_x, const std::string& name_y); /*! * \brief determine if a point P(val_x,val_y) is inside the triangle val_id_triangle. @@ -186,8 +186,8 @@ class CLookUpTable { * \param[in] name_enth - string name of the second controlling variable. * \returns true if the point is in the triangle, false if it is outside. */ - bool IsInTriangle(su2double val_x, su2double val_y, unsigned long val_id_triangle, const std::string& name_prog, - const std::string& name_enth); + bool IsInTriangle(su2double val_x, su2double val_y, unsigned long val_id_triangle, const std::string& name_x, + const std::string& name_y); /*! * \brief compute the area of a triangle given the 3 points of the triangle. @@ -204,7 +204,7 @@ class CLookUpTable { } public: - CLookUpTable(const std::string& file_name_lut, const std::string& name_prog, const std::string& name_enth); + CLookUpTable(const std::string& file_name_lut, const std::string& name_x, const std::string& name_y); /*! @@ -214,59 +214,59 @@ class CLookUpTable { /*! * \brief lookup 1 value of the single variable "val_name_var" using controlling variable values(val_prog,val_enth) - * whose controlling variable names are "name_prog" and "name_enth". + * whose controlling variable names are "name_x" and "name_y". * \param[in] val_name_var - string name of the variable to look up. * \param[out] val_var - the stored value of the variable to look up. - * \param[in] val_prog - value of controlling variable 1 (progress variable). - * \param[in] val_enth - value of controlling variable 2 (enthalpy). - * \param[in] name_prog - string name of controlling variable 1 (progress variable). - * \param[in] name_enth - string name of controlling variable 2 (enthalpy). + * \param[in] val_x - value of controlling variable 1 (x). + * \param[in] val_y - value of controlling variable 2 (y). + * \param[in] name_x - string name of controlling variable 1 (x). + * \param[in] name_y - string name of controlling variable 2 (y). * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ - unsigned long LookUp_ProgEnth(const std::string& val_name_var, su2double* val_var, su2double val_prog, su2double val_enth, - const std::string& name_prog, const std::string& name_enth); + unsigned long LookUp_XY(const std::string& val_name_var, su2double* val_var, su2double val_x, su2double val_y, + const std::string& name_x, const std::string& name_y); /*! - * \brief lookup 1 value for each of the variables in "val_name_var" using controlling variable values(val_prog,val_enth) - * whose controlling variable names are "name_prog" and "name_enth". + * \brief lookup 1 value for each of the variables in "val_name_var" using controlling variable values(val_x,val_y) + * whose controlling variable names are "name_x" and "name_y". * \param[in] val_names_var - vector of string names of the variables to look up. * \param[out] val_vars - pointer to the vector of stored values of the variables to look up. - * \param[in] val_prog - value of controlling variable 1 (progress variable). - * \param[in] val_enth - value of controlling variable 2 (enthalpy). - * \param[in] name_prog - string name of controlling variable 1 (progress variable). - * \param[in] name_enth - string name of controlling variable 2 (enthalpy). + * \param[in] val_x - value of controlling variable 1 (x). + * \param[in] val_y - value of controlling variable 2 (y). + * \param[in] name_x - string name of controlling variable 1 (x). + * \param[in] name_y - string name of controlling variable 2 (y). * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ - unsigned long LookUp_ProgEnth(const std::vector& val_names_var, std::vector& val_vars, su2double val_prog, - su2double val_enth, const std::string& name_prog, const std::string& name_enth); + unsigned long LookUp_XY(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, + su2double val_y, const std::string& name_x, const std::string& name_y); /*! - * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_prog,val_enth) - * whose controlling variable names are "name_prog" and "name_enth". + * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_x,val_y) + * whose controlling variable names are "name_x" and "name_y". * \param[in] val_name_var - string name of the variable to look up. * \param[out] val_var - the stored value of the variable to look up. - * \param[in] val_prog - value of controlling variable 1 (progress variable). - * \param[in] val_enth - value of controlling variable 2 (enthalpy). - * \param[in] name_prog - string name of controlling variable 1 (progress variable). - * \param[in] name_enth - string name of controlling variable 2 (enthalpy). + * \param[in] val_x - value of controlling variable 1 (x). + * \param[in] val_y - value of controlling variable 2 (y). + * \param[in] name_x - string name of controlling variable 1 (x). + * \param[in] name_y - string name of controlling variable 2 (y). * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ - unsigned long LookUp_ProgEnth(const std::vector& val_names_var, std::vector& val_vars, su2double val_prog, - su2double val_enth, const std::string& name_prog, const std::string& name_enth); + unsigned long LookUp_XY(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, + su2double val_y, const std::string& name_x, const std::string& name_y); /*! - * \brief determine the minimum and maximum value of the enthalpy (controlling variable 2). + * \brief determine the minimum and maximum value of the y (controlling variable 2). * \returns pair of minimum and maximum value of controlling variable 2. */ - inline std::pair GetTableLimitsEnth() const { - return std::make_pair(limits_table_enth[0], limits_table_enth[1]); + inline std::pair GetTableLimitsY() const { + return std::make_pair(limits_table_y[0], limits_table_y[1]); } /*! - * \brief determine the minimum and maximum value of the progress variable (controlling variable 1). + * \brief determine the minimum and maximum value of the x (controlling variable 1). * \returns pair of minimum and maximum value of controlling variable 1. */ - inline std::pair GetTableLimitsProg() const { - return std::make_pair(limits_table_prog[0], limits_table_prog[1]); + inline std::pair GetTableLimitsX() const { + return std::make_pair(limits_table_x[0], limits_table_x[1]); } }; diff --git a/Common/src/containers/CLookUpTable.cpp b/Common/src/containers/CLookUpTable.cpp index a0e84c2926e..2f450268d9a 100644 --- a/Common/src/containers/CLookUpTable.cpp +++ b/Common/src/containers/CLookUpTable.cpp @@ -31,14 +31,14 @@ using namespace std; -CLookUpTable::CLookUpTable(const string& var_file_name_lut, const string& name_prog, const string& name_enth) { +CLookUpTable::CLookUpTable(const string& var_file_name_lut, const string& name_x, const string& name_y) { file_name_lut = var_file_name_lut; rank = SU2_MPI::GetRank(); LoadTableRaw(var_file_name_lut); - FindTableLimits(name_prog, name_enth); + FindTableLimits(name_x, name_y); if (rank == MASTER_NODE) cout << "Detecting all unique edges and setting edge to triangle connectivity " @@ -53,11 +53,11 @@ CLookUpTable::CLookUpTable(const string& var_file_name_lut, const string& name_p PrintTableInfo(); if (rank == MASTER_NODE) - cout << "Building a trapezoidal map for the (progress variable, enthalpy) " + cout << "Building a trapezoidal map for the (x, y) " "space ..." << endl; - trap_map_prog_enth = CTrapezoidalMap(GetDataP(name_prog), GetDataP(name_enth), table_data.cols(), edges, edge_to_triangle); + trap_map_x_y = CTrapezoidalMap(GetDataP(name_x), GetDataP(name_y), table_data.cols(), edges, edge_to_triangle); if (rank == MASTER_NODE) cout << " done." << endl; @@ -66,7 +66,7 @@ CLookUpTable::CLookUpTable(const string& var_file_name_lut, const string& name_p cout << "Precomputing interpolation coefficients..." << endl; - ComputeInterpCoeffs(name_prog, name_enth); + ComputeInterpCoeffs(name_x, name_y); if (rank == MASTER_NODE) cout << "LUT fluid model ready for use" << endl; @@ -95,15 +95,15 @@ void CLookUpTable::LoadTableRaw(const string& var_file_name_lut) { cout << " done." << endl; } -void CLookUpTable::FindTableLimits(const string& name_prog, const string& name_enth) { - int ixEnth = GetIndexOfVar(name_enth); - int ixProg = GetIndexOfVar(name_prog); +void CLookUpTable::FindTableLimits(const string& name_x, const string& name_y) { + int ixy = GetIndexOfVar(name_y); + int ixx = GetIndexOfVar(name_x); - /* we find the lowest and highest value of enthalpy and progress variable in the table */ - limits_table_enth[0] = *min_element(&table_data[ixEnth][0], &table_data[ixEnth][0]+table_data.cols()); - limits_table_enth[1] = *max_element(&table_data[ixEnth][0], &table_data[ixEnth][0]+table_data.cols()); - limits_table_prog[0] = *min_element(&table_data[ixProg][0], &table_data[ixProg][0]+table_data.cols()); - limits_table_prog[1] = *max_element(&table_data[ixProg][0], &table_data[ixProg][0]+table_data.cols()); + /* we find the lowest and highest value of y and x in the table */ + limits_table_y[0] = *min_element(&table_data[ixy][0], &table_data[ixy][0]+table_data.cols()); + limits_table_y[1] = *max_element(&table_data[ixy][0], &table_data[ixy][0]+table_data.cols()); + limits_table_x[0] = *min_element(&table_data[ixx][0], &table_data[ixx][0]+table_data.cols()); + limits_table_x[1] = *max_element(&table_data[ixx][0], &table_data[ixx][0]+table_data.cols()); } @@ -122,10 +122,10 @@ void CLookUpTable::PrintTableInfo() { cout << "| Number of triangles:" << setw(44) << right << n_triangles << " |" << endl; cout << "| Number of edges:" << setw(48) << right << edges.size() << " |" << endl; cout << "+------------------------------------------------------------------+" << endl; - cout << "| Minimum enthalpy:" << setw(47) << right << limits_table_enth[0] << " |" << endl; - cout << "| Maximum enthalpy:" << setw(47) << right << limits_table_enth[1] << " |" << endl; - cout << "| Minimum progress variable:" << setw(38) << right << limits_table_prog[0] << " |" << endl; - cout << "| Maximum progress variable:" << setw(38) << right << limits_table_prog[1] << " |" << endl; + cout << "| Minimum y:" << setw(47) << right << limits_table_y[0] << " |" << endl; + cout << "| Maximum y:" << setw(47) << right << limits_table_y[1] << " |" << endl; + cout << "| Minimum x:" << setw(38) << right << limits_table_x[0] << " |" << endl; + cout << "| Maximum x:" << setw(38) << right << limits_table_x[1] << " |" << endl; cout << "+------------------------------------------------------------------+" << endl; cout << "| Variable names: |" << endl; cout << "| |" << endl; @@ -243,13 +243,13 @@ void CLookUpTable::IdentifyUniqueEdges() { } } -void CLookUpTable::ComputeInterpCoeffs(const string& name_prog, const string& name_enth) { - /* build KD tree for enthalpy, progress variable space */ +void CLookUpTable::ComputeInterpCoeffs(const string& name_x, const string& name_y) { + /* build KD tree for y, x space */ std::array next_triangle; - const su2double* prog = GetDataP(name_prog); - const su2double* enth = GetDataP(name_enth); + const su2double* x = GetDataP(name_x); + const su2double* y = GetDataP(name_y); /* calculate weights for each triangle (basically a distance function) and * build inverse interpolation matrices */ @@ -259,9 +259,9 @@ void CLookUpTable::ComputeInterpCoeffs(const string& name_prog, const string& na next_triangle[p] = triangles[i_triangle][p]; } - su2activematrix prog_interp_mat_inv(3, 3); - GetInterpMatInv(prog, enth, next_triangle, prog_interp_mat_inv); - interp_mat_inv_prog_enth.push_back(prog_interp_mat_inv); + su2activematrix x_interp_mat_inv(3, 3); + GetInterpMatInv(x, y, next_triangle, x_interp_mat_inv); + interp_mat_inv_x_y.push_back(x_interp_mat_inv); } } @@ -291,8 +291,8 @@ void CLookUpTable::GetInterpMatInv(const su2double* vec_x, const su2double* vec_ } -unsigned long CLookUpTable::LookUp_ProgEnth(const string& val_name_var, su2double *val_var, su2double val_prog, - su2double val_enth, const string& name_prog, const string& name_enth) { +unsigned long CLookUpTable::LookUp_XY(const string& val_name_var, su2double *val_var, su2double val_x, + su2double val_y, const string& name_x, const string& name_y) { unsigned long exit_code = 0; if (val_name_var.compare("NULL") == 0) { @@ -301,17 +301,17 @@ unsigned long CLookUpTable::LookUp_ProgEnth(const string& val_name_var, su2doubl return exit_code; } - /* check if progress variable and enthalpy value is in table range */ - if ((val_prog >= limits_table_prog[0] && val_prog <= limits_table_prog[1]) && - (val_enth >= limits_table_enth[0] && val_enth <= limits_table_enth[1])){ + /* check if x and y value is in table range */ + if ((val_x >= limits_table_x[0] && val_x <= limits_table_x[1]) && + (val_y >= limits_table_y[0] && val_y <= limits_table_y[1])){ - /* find the triangle that holds the (prog, enth) point */ - unsigned long id_triangle = trap_map_prog_enth.GetTriangle(val_prog, val_enth); + /* find the triangle that holds the (x, y) point */ + unsigned long id_triangle = trap_map_x_y.GetTriangle(val_x, val_y); - if (IsInTriangle(val_prog, val_enth, id_triangle, name_prog, name_enth)) { + if (IsInTriangle(val_x, val_y, id_triangle, name_x, name_y)) { /* get interpolation coefficients for point on triangle */ std::array interp_coeffs{0}; - GetInterpCoeffs(val_prog, val_enth, interp_mat_inv_prog_enth[id_triangle], interp_coeffs); + GetInterpCoeffs(val_x, val_y, interp_mat_inv_x_y[id_triangle], interp_coeffs); /* first, copy the single triangle from the large triangle list*/ std::array triangle{0}; @@ -322,67 +322,67 @@ unsigned long CLookUpTable::LookUp_ProgEnth(const string& val_name_var, su2doubl exit_code = 0; } else { /* in bounding box but outside of table */ - unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_prog, val_enth, name_prog, name_enth); + unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y); *val_var = GetDataP(val_name_var)[nearest_neighbor]; exit_code = 1; } } else { /* lookup is outside of table bounding box */ - unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_prog, val_enth, name_prog, name_enth); + unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y); *val_var = GetDataP(val_name_var)[nearest_neighbor]; exit_code = 1; } return exit_code; } -unsigned long CLookUpTable::LookUp_ProgEnth(const vector& val_names_var, vector& val_vars, - su2double val_prog, su2double val_enth, const string& name_prog, - const string& name_enth) { +unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vector& val_vars, + su2double val_x, su2double val_y, const string& name_x, + const string& name_y) { vector look_up_data; for (long unsigned int i_var = 0; i_var < val_vars.size(); ++i_var) { look_up_data.push_back(&val_vars[i_var]); } - unsigned long exit_code = LookUp_ProgEnth(val_names_var, look_up_data, val_prog, val_enth, name_prog, name_enth); + unsigned long exit_code = LookUp_XY(val_names_var, look_up_data, val_x, val_y, name_x, name_y); return exit_code; } -unsigned long CLookUpTable::LookUp_ProgEnth(const vector& val_names_var, vector& val_vars, - su2double val_prog, su2double val_enth, const string& name_prog, - const string& name_enth) { +unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vector& val_vars, + su2double val_x, su2double val_y, const string& name_x, + const string& name_y) { unsigned long exit_code = 0; unsigned long nearest_neighbor = 0; unsigned long id_triangle; std::array interp_coeffs{0}; std::array triangle{0}; - /* check if progress variable value is in progress variable table range - * and if enthalpy is in enthalpy table range */ - if (val_prog >= limits_table_prog[0] && val_prog <= limits_table_prog[1] && val_enth >= limits_table_enth[0] && - val_enth <= limits_table_enth[1]) { - /* if so, try to find the triangle that holds the (prog, enth) point */ - id_triangle = trap_map_prog_enth.GetTriangle(val_prog, val_enth); + /* check if x value is in x table range + * and if y is in y table range */ + if (val_x >= limits_table_x[0] && val_x <= limits_table_x[1] && val_y >= limits_table_y[0] && + val_y <= limits_table_y[1]) { + /* if so, try to find the triangle that holds the (x, y) point */ + id_triangle = trap_map_x_y.GetTriangle(val_x, val_y); /* check if point is inside a triangle (if table domain is non-rectangular, * the previous range check might be true but the point could still be outside of the domain) */ - if (IsInTriangle(val_prog, val_enth, id_triangle, name_prog, name_enth)) { + if (IsInTriangle(val_x, val_y, id_triangle, name_x, name_y)) { /* if so, get interpolation coefficients for point in the triangle */ - GetInterpCoeffs(val_prog, val_enth, interp_mat_inv_prog_enth[id_triangle], interp_coeffs); + GetInterpCoeffs(val_x, val_y, interp_mat_inv_x_y[id_triangle], interp_coeffs); /* exit_code 0 means point was in triangle */ exit_code = 0; } else { /* if point is not inside a triangle (outside table domain) search nearest neighbor */ - nearest_neighbor = FindNearestNeighborOnHull(val_prog, val_enth, name_prog, name_enth); + nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y); exit_code = 1; } } else { /* if point is outside of table ranges, find nearest neighbor */ - nearest_neighbor = FindNearestNeighborOnHull(val_prog, val_enth, name_prog, name_enth); + nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y); exit_code = 1; } @@ -433,27 +433,27 @@ su2double CLookUpTable::Interpolate(const su2double* val_samples, std::array Date: Mon, 21 Nov 2022 19:28:45 +0100 Subject: [PATCH 043/598] Added third dimension to CLookUpTable class, changed method names in CLookupTable_tests --- Common/include/containers/CFileReaderLUT.hpp | 29 +- Common/include/containers/CLookUpTable.hpp | 132 +++++--- Common/src/containers/CFileReaderLUT.cpp | 120 +++++-- Common/src/containers/CLookUpTable.cpp | 313 ++++++++++++------ .../Common/containers/CLookupTable_tests.cpp | 10 +- 5 files changed, 403 insertions(+), 201 deletions(-) diff --git a/Common/include/containers/CFileReaderLUT.hpp b/Common/include/containers/CFileReaderLUT.hpp index a000b2ddc60..37b6f7a4aaa 100644 --- a/Common/include/containers/CFileReaderLUT.hpp +++ b/Common/include/containers/CFileReaderLUT.hpp @@ -42,11 +42,13 @@ class CFileReaderLUT { protected: int rank; + unsigned short table_dim = 2; std::string version_lut; std::string version_reader; - unsigned long n_points; - unsigned long n_triangles; - unsigned long n_hull_points; + unsigned long n_levels = 1; + unsigned long *n_points; + unsigned long *n_triangles; + unsigned long *n_hull_points; unsigned long n_variables; /*! \brief Holds the variable names stored in the table file. @@ -57,11 +59,11 @@ class CFileReaderLUT { /*! \brief Holds all data stored in the table. * First index addresses the variable while second index addresses the point. */ - su2activematrix table_data; + su2activematrix *table_data; - su2matrix triangles; + su2matrix *triangles; - std::vector hull; + std::vector *hull; /*! \brief Searches for the position of flag in file_stream and * sets the stream position of file_stream to that position. @@ -82,18 +84,21 @@ class CFileReaderLUT { inline const std::string& GetVersionLUT() const { return version_lut; } inline const std::string& GetVersionReader() const { return version_reader; } - inline unsigned long GetNPoints() const { return n_points; } - inline unsigned long GetNTriangles() const { return n_triangles; } - inline unsigned long GetNHullPoints() const { return n_hull_points; } + inline unsigned long GetNPoints(std::size_t i_level=0) const { return n_points[i_level]; } + inline unsigned long GetNTriangles(std::size_t i_level=0) const { return n_triangles[i_level]; } + inline unsigned long GetNHullPoints(std::size_t i_level=0) const { return n_hull_points[i_level]; } inline unsigned long GetNVariables() const { return n_variables; } + inline unsigned long GetNLevels() const { return n_levels; } inline const std::vector& GetNamesVar() const { return names_var; } - inline const su2activematrix& GetTableData() const { return table_data; } + inline const su2activematrix& GetTableData(std::size_t i_level=0) const { return table_data[i_level]; } - inline const su2matrix& GetTriangles() const { return triangles; }; + inline const su2matrix& GetTriangles(std::size_t i_level=0) const { return triangles[i_level]; } - inline const std::vector& GetHull() const { return hull; }; + inline const std::vector& GetHull(std::size_t i_level=0) const { return hull[i_level]; } + + inline const unsigned short GetTableDim() const { return table_dim; } void ReadRawLUT(const std::string& file_name); }; diff --git a/Common/include/containers/CLookUpTable.hpp b/Common/include/containers/CLookUpTable.hpp index 1d93cdea516..3dcfceb0d51 100644 --- a/Common/include/containers/CLookUpTable.hpp +++ b/Common/include/containers/CLookUpTable.hpp @@ -1,7 +1,7 @@ /*! * \file CLookupTable.hpp * \brief tabulation of fluid properties - * \author D. Mayer, T. Economon + * \author D. Mayer, T. Economon, E.C.Bunschoten * \version 7.4.0 "Blackbird" * * SU2 Project Website: https://su2code.github.io @@ -47,16 +47,19 @@ class CLookUpTable { std::string file_name_lut; std::string version_lut; std::string version_reader; - unsigned long n_points; - unsigned long n_triangles; + unsigned long *n_points; + unsigned long *n_triangles; unsigned long n_variables; - unsigned long n_hull_points; + unsigned long *n_hull_points; + unsigned long n_table_levels = 1; + su2double *z_values_levels; /*! - * \brief the lower and upper limits of the y and x. + * \brief the lower and upper limits of the z, y and x variable. */ - su2double limits_table_y[2]; - su2double limits_table_x[2]; + std::pair limits_table_z; + std::pair *limits_table_y; + std::pair *limits_table_x; /*! \brief Holds the variable names stored in the table file. * Order is in sync with data @@ -67,25 +70,25 @@ class CLookUpTable { * Holds all data stored in the table. First index addresses the variable * while second index addresses the point. */ - su2activematrix table_data; + su2activematrix *table_data; - su2matrix triangles; + su2matrix *triangles; /* we do not know this size in advance until we go through the entire lookup table */ - std::vector > edges; - std::vector > edge_to_triangle; + std::vector > *edges; + std::vector > *edge_to_triangle; /*! \brief * The hull contains the boundary of the lookup table. */ - std::vector hull; + std::vector *hull; - CTrapezoidalMap trap_map_x_y; + CTrapezoidalMap *trap_map_x_y; /*! \brief * vector of all the weight factors for the interpolation. */ - std::vector interp_mat_inv_x_y; + std::vector *interp_mat_inv_x_y; /*! \brief * returns the index to the variable in the lookup table. @@ -106,13 +109,13 @@ class CLookUpTable { * \brief Get the pointer to the column data of the table (density, temperature, source terms, ...). * \returns pointer to the column data. */ - inline const su2double* GetDataP(const std::string& name_var) const { - return table_data[GetIndexOfVar(name_var)]; + inline const su2double* GetDataP(const std::string& name_var, unsigned long i_level=0) const { + return table_data[i_level][GetIndexOfVar(name_var)]; } /*! * \brief find the table limits, i.e. the minimum and maximum values of the 2 independent. - * controlling variables (x and y). We put the values in the variables. + * controlling variables. We put the values in the variables. * limits_table_x[2] and limit_table_y[2]. * \param[in] name_x - the string name for the first controlling variable. * \param[in] name_y - the string name of the second controlling variable. @@ -131,16 +134,16 @@ class CLookUpTable { void LoadTableRaw(const std::string& file_name_lut); /*! - * \brief compute vector of all (inverse) interpolation coefficients "interp_mat_inv_prog_enth" of all triangles. - * \param[in] name_prog - the string name of the first controlling variable (x). - * \param[in] name_enth - the string name of the second controlling variable (y). + * \brief compute vector of all (inverse) interpolation coefficients "interp_mat_inv_x_y" of all triangles. + * \param[in] name_x - the string name of the first controlling variable. + * \param[in] name_y - the string name of the second controlling variable. */ void ComputeInterpCoeffs(const std::string& name_x, const std::string& name_y); /*! * \brief compute the inverse matrix for interpolation. - * \param[in] vec_x - pointer to first coordinate (x). - * \param[in] vec_y - pointer to second coordinate (y). + * \param[in] vec_x - pointer to first coordinate (progress variable). + * \param[in] vec_y - pointer to second coordinate (enthalpy). * \param[in] point_ids - single triangle data. * \param[out] interp_mat_inv - inverse matrix for interpolation. */ @@ -149,8 +152,8 @@ class CLookUpTable { /*! * \brief compute the interpolation coefficients for the triangular interpolation. - * \param[in] val_x - value of first coordinate (x). - * \param[in] val_y - value of second coordinate (y). + * \param[in] val_x - value of first coordinate (progress variable). + * \param[in] val_y - value of second coordinate (enthalpy). * \param[in] interp_mat_inv - inverse matrix for interpolation. * \param[out] interp_coeffs - interpolation coefficients. */ @@ -167,27 +170,29 @@ class CLookUpTable { su2double Interpolate(const su2double* val_samples, std::array& val_triangle, std::array& val_interp_coeffs); + void Linear_Interpolation(su2double val_z, std::pair &inclusion_levels, std::vector&lower_values,std::vector&upper_values, std::vector&var_vals); + /*! * \brief find the point on the hull (boundary of the table) that is closest to the point P(val_x,val_y). * \param[in] val_x - first coordinate of point P(val_x,val_y) to check. * \param[in] val_y - second coordinate of point P(val_x,val_y) to check. - * \param[in] name_prog - string name of the first controlling variable. - * \param[in] name_enth - string name of the second controlling variable. + * \param[in] name_x - string name of the first controlling variable. + * \param[in] name_y - string name of the second controlling variable. * \returns point id of the nearest neighbor on the hull. */ - unsigned long FindNearestNeighborOnHull(su2double val_x, su2double val_y, const std::string& name_x, const std::string& name_y); + unsigned long FindNearestNeighborOnHull(su2double val_x, su2double val_y, const std::string& name_x, const std::string& name_y, unsigned long i_level=0); /*! * \brief determine if a point P(val_x,val_y) is inside the triangle val_id_triangle. * \param[in] val_x - first coordinate of point P(val_x,val_y) to check. * \param[in] val_y - second coordinate of point P(val_x,val_y) to check. * \param[in] val_id_triangle - ID of the triangle to check. - * \param[in] name_prog - string name of the first controlling variable. - * \param[in] name_enth - string name of the second controlling variable. + * \param[in] name_x - string name of the first controlling variable. + * \param[in] name_y - string name of the second controlling variable. * \returns true if the point is in the triangle, false if it is outside. */ bool IsInTriangle(su2double val_x, su2double val_y, unsigned long val_id_triangle, const std::string& name_x, - const std::string& name_y); + const std::string& name_y, unsigned long i_level=0); /*! * \brief compute the area of a triangle given the 3 points of the triangle. @@ -205,7 +210,7 @@ class CLookUpTable { public: CLookUpTable(const std::string& file_name_lut, const std::string& name_x, const std::string& name_y); - + ~CLookUpTable(); /*! * \brief print information to screen. @@ -213,60 +218,79 @@ class CLookUpTable { void PrintTableInfo(); /*! - * \brief lookup 1 value of the single variable "val_name_var" using controlling variable values(val_prog,val_enth) - * whose controlling variable names are "name_x" and "name_y". + * \brief lookup 1 value of the single variable "val_name_var" using controlling variable values(val_x,val_y) + * whose controlling variable names are "name_prog" and "name_enth". * \param[in] val_name_var - string name of the variable to look up. * \param[out] val_var - the stored value of the variable to look up. - * \param[in] val_x - value of controlling variable 1 (x). - * \param[in] val_y - value of controlling variable 2 (y). - * \param[in] name_x - string name of controlling variable 1 (x). - * \param[in] name_y - string name of controlling variable 2 (y). + * \param[in] val_x - value of controlling variable 1. + * \param[in] val_y - value of controlling variable 2. + * \param[in] name_x - string name of controlling variable 1. + * \param[in] name_y - string name of controlling variable 2. * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ unsigned long LookUp_XY(const std::string& val_name_var, su2double* val_var, su2double val_x, su2double val_y, - const std::string& name_x, const std::string& name_y); + const std::string& name_x, const std::string& name_y, unsigned long i_level=0); /*! * \brief lookup 1 value for each of the variables in "val_name_var" using controlling variable values(val_x,val_y) * whose controlling variable names are "name_x" and "name_y". * \param[in] val_names_var - vector of string names of the variables to look up. * \param[out] val_vars - pointer to the vector of stored values of the variables to look up. - * \param[in] val_x - value of controlling variable 1 (x). - * \param[in] val_y - value of controlling variable 2 (y). - * \param[in] name_x - string name of controlling variable 1 (x). - * \param[in] name_y - string name of controlling variable 2 (y). + * \param[in] val_x - value of controlling variable 1. + * \param[in] val_y - value of controlling variable 2. + * \param[in] name_x - string name of controlling variable 1. + * \param[in] name_y - string name of controlling variable 2. * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ unsigned long LookUp_XY(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, - su2double val_y, const std::string& name_x, const std::string& name_y); + su2double val_y, const std::string& name_x, const std::string& name_y, unsigned long i_level=0); /*! * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_x,val_y) * whose controlling variable names are "name_x" and "name_y". * \param[in] val_name_var - string name of the variable to look up. * \param[out] val_var - the stored value of the variable to look up. - * \param[in] val_x - value of controlling variable 1 (x). - * \param[in] val_y - value of controlling variable 2 (y). - * \param[in] name_x - string name of controlling variable 1 (x). - * \param[in] name_y - string name of controlling variable 2 (y). + * \param[in] val_x - value of controlling variable 1. + * \param[in] val_y - value of controlling variable 2. + * \param[in] name_x - string name of controlling variable 1. + * \param[in] name_y - string name of controlling variable 2. * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ unsigned long LookUp_XY(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, - su2double val_y, const std::string& name_x, const std::string& name_y); + su2double val_y, const std::string& name_x, const std::string& name_y, unsigned long i_level=0); + + /*! + * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_x,val_y,val_z) + * whose controlling variable names are "name_x" and "name_y". + * \param[in] val_name_var - string name of the variable to look up. + * \param[out] val_var - the stored value of the variable to look up. + * \param[in] val_x - value of controlling variable 1. + * \param[in] val_y - value of controlling variable 2. + * \param[in] name_x - string name of controlling variable 1. + * \param[in] name_y - string name of controlling variable 2. + * \param[in] val_z - value of controlling variable 3. + * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. + */ + unsigned long LookUp_XYZ(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, + su2double val_y, const std::string& name_x, const std::string& name_y, su2double val_z=0); + + std::pair FindInclusionLevels(su2double val_z, bool *within_limits); /*! - * \brief determine the minimum and maximum value of the y (controlling variable 2). + * \brief determine the minimum and maximum value of the second controlling variable. * \returns pair of minimum and maximum value of controlling variable 2. */ - inline std::pair GetTableLimitsY() const { - return std::make_pair(limits_table_y[0], limits_table_y[1]); + inline std::pair GetTableLimitsY(unsigned long i_level = 0) const { + return limits_table_y[i_level]; } /*! - * \brief determine the minimum and maximum value of the x (controlling variable 1). + * \brief determine the minimum and maximum value of the first controlling variable. * \returns pair of minimum and maximum value of controlling variable 1. */ - inline std::pair GetTableLimitsX() const { - return std::make_pair(limits_table_x[0], limits_table_x[1]); + inline std::pair GetTableLimitsX(unsigned long i_level = 0) const { + return limits_table_x[i_level]; } + + }; diff --git a/Common/src/containers/CFileReaderLUT.cpp b/Common/src/containers/CFileReaderLUT.cpp index 081293eded1..4e9e6b013d2 100644 --- a/Common/src/containers/CFileReaderLUT.cpp +++ b/Common/src/containers/CFileReaderLUT.cpp @@ -59,31 +59,64 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { /*--- Read header ---*/ SkipToFlag(file_stream, line, "
"); - + table_dim = 2; + bool found_level_count = false; while (GetNextNonEmptyLine(file_stream, line) && !eoHeader) { /*--- number of points in LUT ---*/ if (line.compare("[Version]") == 0) { GetNextNonEmptyLine(file_stream, line); version_lut = line; + + if(version_lut.compare("1.0.0") == 0){ + table_dim = 2; + n_levels = 1; + found_level_count = true; + } + if(version_lut.compare("1.1.0") == 0){ + table_dim = 3; + } + } + + if (line.compare("[Number of table levels]") == 0) + { + found_level_count = true; + GetNextNonEmptyLine(file_stream, line); + n_levels = stoul(line); + + n_points = new unsigned long[n_levels]; + n_triangles = new unsigned long[n_levels]; + n_hull_points = new unsigned long[n_levels]; } /*--- number of points in LUT ---*/ if (line.compare("[Number of points]") == 0) { - GetNextNonEmptyLine(file_stream, line); - n_points = stoi(line); + if(!found_level_count) + SU2_MPI::Error("Number of points provided before specifying level count.", CURRENT_FUNCTION); + for(unsigned long i_level=0; i_level"); - + unsigned long i_level = 0; + bool eoLevel = false; unsigned long pointCounter = 0; + unsigned long levelCounter = 0; while (GetNextNonEmptyLine(file_stream, line) && !eoData) { /*--- check if end of data is reached ---*/ if (line.compare("") == 0) eoData = true; if (!eoData) { - /*--- one line contains values for one point for all variables ---*/ - istringstream streamDataLine(line); - - /*--- add next line to table array ---*/ - for (unsigned long iVar = 0; iVar < n_variables; iVar++) { - streamDataLine >> word; - passivedouble tmp = stod(word); - table_data[iVar][pointCounter] = (su2double)tmp; + if(line.compare("") == 0){ + eoLevel = false; + pointCounter = 0; + GetNextNonEmptyLine(file_stream, line); + } + if(line.compare("") == 0){ + eoLevel = true; + if (n_points[levelCounter] != pointCounter - 1) + SU2_MPI::Error( + "Number of read points on level " + std::to_string(levelCounter) + " does not match number of points " + "specified in lookup table library header.", + CURRENT_FUNCTION); + levelCounter++; + } + if(!eoLevel || (table_dim == 2)){ + /*--- one line contains values for one point for all variables ---*/ + istringstream streamDataLine(line); + + /*--- add next line to table array ---*/ + for (unsigned long iVar = 0; iVar < n_variables; iVar++) { + streamDataLine >> word; + passivedouble tmp = stod(word); + table_data[levelCounter][iVar][pointCounter] = (su2double)tmp; + } + pointCounter++; } } - pointCounter++; } - if (n_points != pointCounter - 1) - SU2_MPI::Error( - "Number of read points does not match number of points " - "specified in lookup table library header.", - CURRENT_FUNCTION); + /*--- read connectivity ---*/ if (rank == MASTER_NODE) cout << "loading connectivity block" << endl; SkipToFlag(file_stream, line, ""); - + i_level = 0; unsigned long triCounter = 0; while (GetNextNonEmptyLine(file_stream, line) && !eoConnectivity) { if (!line.empty() && (line[line.length()-1] == '\n' || line[line.length()-1] == '\r' )) { @@ -193,13 +249,13 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { streamTriLine >> word; /*--- lookup table index starts with 1, convert to c++ indexing starting with 0: ---*/ - triangles[triCounter][iPoint] = stol(word) - 1; + triangles[i_level][triCounter][iPoint] = stol(word) - 1; } } triCounter++; } - if (n_triangles != triCounter - 1) + if (n_triangles[i_level] != triCounter - 1) SU2_MPI::Error( "Number of read triangles does not match number of points " "specified in lookup table library header.", @@ -209,7 +265,7 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { if (rank == MASTER_NODE) cout << "loading hull block" << endl; SkipToFlag(file_stream, line, ""); - + i_level = 0; unsigned long hullCounter = 0; while (GetNextNonEmptyLine(file_stream, line) && !eoHull) { if (!line.empty() && (line[line.length()-1] == '\n' || line[line.length()-1] == '\r' )) { @@ -225,12 +281,12 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { streamHullLine >> word; /*--- Lookup table indices start with 1, convert to c++ indexing starting with 0: ---*/ - hull[hullCounter] = stol(word) - 1; + hull[i_level][hullCounter] = stol(word) - 1; } hullCounter++; } - if (n_hull_points != hullCounter - 1) + if (n_hull_points[i_level] != hullCounter - 1) SU2_MPI::Error( "Number of read hull points does not match number of points " "specified in lookup table library header.", diff --git a/Common/src/containers/CLookUpTable.cpp b/Common/src/containers/CLookUpTable.cpp index 2f450268d9a..a64ebcfa7ab 100644 --- a/Common/src/containers/CLookUpTable.cpp +++ b/Common/src/containers/CLookUpTable.cpp @@ -1,7 +1,7 @@ /*! * \file CLookupTable.cpp * \brief tabulation of fluid properties - * \author D. Mayer, T. Economon + * \author D. Mayer, T. Economon, E.C.Bunschoten * \version 7.4.0 "Blackbird" * * SU2 Project Website: https://su2code.github.io @@ -53,11 +53,12 @@ CLookUpTable::CLookUpTable(const string& var_file_name_lut, const string& name_x PrintTableInfo(); if (rank == MASTER_NODE) - cout << "Building a trapezoidal map for the (x, y) " + cout << "Building a trapezoidal map for the (" + name_x + ", " + name_y + ") " "space ..." << endl; - - trap_map_x_y = CTrapezoidalMap(GetDataP(name_x), GetDataP(name_y), table_data.cols(), edges, edge_to_triangle); + trap_map_x_y = new CTrapezoidalMap[n_table_levels]; + for(auto i_level = 0ul; i_level[n_table_levels]; + triangles = new su2matrix[n_table_levels]; + interp_mat_inv_x_y = new std::vector[n_table_levels]; + edges = new std::vector >[n_table_levels]; + edge_to_triangle = new std::vector >[n_table_levels]; + + for(unsigned long i_level=0; i_level[n_table_levels]; + limits_table_y = new pair[n_table_levels]; /* we find the lowest and highest value of y and x in the table */ - limits_table_y[0] = *min_element(&table_data[ixy][0], &table_data[ixy][0]+table_data.cols()); - limits_table_y[1] = *max_element(&table_data[ixy][0], &table_data[ixy][0]+table_data.cols()); - limits_table_x[0] = *min_element(&table_data[ixx][0], &table_data[ixx][0]+table_data.cols()); - limits_table_x[1] = *max_element(&table_data[ixx][0], &table_data[ixx][0]+table_data.cols()); - + for(auto i_level=0u; i_level > neighborElemsOfPoint; - neighborElemsOfPoint.resize(n_points); - for (unsigned long iElem = 0; iElem < n_triangles; iElem++) { + neighborElemsOfPoint.resize(n_points[i_level]); + for (unsigned long iElem = 0; iElem < n_triangles[i_level]; iElem++) { /* loop over 3 points per triangle */ for (unsigned long iPoint = 0; iPoint < N_POINTS_TRIANGLE; iPoint++) { /* get the global ID of the current point */ - const unsigned long GlobalIndex = triangles[iElem][iPoint]; + const unsigned long GlobalIndex = triangles[i_level][iElem][iPoint]; /* add the current element ID to the neighbor list for this point */ neighborElemsOfPoint[GlobalIndex].push_back(iElem); @@ -160,7 +205,7 @@ void CLookUpTable::IdentifyUniqueEdges() { /* remove duplicates from the neighboring element lists*/ vector::iterator vecIt; - for (unsigned long iPoint = 0; iPoint < n_points; iPoint++) { + for (unsigned long iPoint = 0; iPoint < n_points[i_level]; iPoint++) { /* sort neighboring elements for each point */ sort(neighborElemsOfPoint[iPoint].begin(), neighborElemsOfPoint[iPoint].end()); @@ -174,13 +219,13 @@ void CLookUpTable::IdentifyUniqueEdges() { /* loop through all neighboring elements of each point and store the point IDs that are neighboring points */ vector > neighborPointsOfPoint; - neighborPointsOfPoint.resize(n_points); - for (unsigned long iPoint = 0; iPoint < n_points; iPoint++) { + neighborPointsOfPoint.resize(n_points[i_level]); + for (unsigned long iPoint = 0; iPoint < n_points[i_level]; iPoint++) { for (unsigned long iElem = 0; iElem < neighborElemsOfPoint[iPoint].size(); iElem++) { /* loop over element points */ for (unsigned long jPoint = 0; jPoint < N_POINTS_TRIANGLE; jPoint++) { /* get the global ID of the current point */ - const unsigned long GlobalIndex = triangles[neighborElemsOfPoint[iPoint][iElem]][jPoint]; + const unsigned long GlobalIndex = triangles[i_level][neighborElemsOfPoint[iPoint][iElem]][jPoint]; /* add the current element ID to the neighbor list for this point */ if (GlobalIndex != iPoint) neighborPointsOfPoint[iPoint].push_back(GlobalIndex); @@ -189,7 +234,7 @@ void CLookUpTable::IdentifyUniqueEdges() { } /* remove duplicates from the neighboring points lists */ - for (unsigned long iPoint = 0; iPoint < n_points; iPoint++) { + for (unsigned long iPoint = 0; iPoint < n_points[i_level]; iPoint++) { /* sort neighboring points for each point */ sort(neighborPointsOfPoint[iPoint].begin(), neighborPointsOfPoint[iPoint].end()); @@ -205,7 +250,7 @@ void CLookUpTable::IdentifyUniqueEdges() { that the smaller global index is in the first position and the larger is in the second to make for a unique set, so there's no need to remove duplicates. */ - for (unsigned long iPoint = 0; iPoint < n_points; iPoint++) { + for (unsigned long iPoint = 0; iPoint < n_points[i_level]; iPoint++) { for (unsigned long jPoint = 0; jPoint < neighborPointsOfPoint[iPoint].size(); jPoint++) { /* Store the neighbor index more clearly. */ const unsigned long GlobalIndex = neighborPointsOfPoint[iPoint][jPoint]; @@ -215,53 +260,57 @@ void CLookUpTable::IdentifyUniqueEdges() { vector edge(2); edge[0] = iPoint; edge[1] = GlobalIndex; - edges.push_back(edge); + edges[i_level].push_back(edge); } } } + /* Loop over our edges data structure. For the first point in each pair, loop through the neighboring elements and store the two elements that contain the second point in the edge ('left' and 'right' of the edge). */ - edge_to_triangle.resize(edges.size()); - for (unsigned long iEdge = 0; iEdge < edges.size(); iEdge++) { + edge_to_triangle[i_level].resize(edges[i_level].size()); + for (unsigned long iEdge = 0; iEdge < edges[i_level].size(); iEdge++) { /* Store the two points of the edge more clearly. */ - const unsigned long iPoint = edges[iEdge][0]; - const unsigned long jPoint = edges[iEdge][1]; + const unsigned long iPoint = edges[i_level][iEdge][0]; + const unsigned long jPoint = edges[i_level][iEdge][1]; /* Loop over all neighboring elements to iPoint. */ for (unsigned long iElem = 0; iElem < neighborElemsOfPoint[iPoint].size(); iElem++) { /* loop over 3 points per triangle */ for (unsigned long kPoint = 0; kPoint < N_POINTS_TRIANGLE; kPoint++) { /* Get the global ID of the current point. */ - const unsigned long GlobalIndex = triangles[neighborElemsOfPoint[iPoint][iElem]][kPoint]; + const unsigned long GlobalIndex = triangles[i_level][neighborElemsOfPoint[iPoint][iElem]][kPoint]; /* Add the current element ID to the neighbor list for this point. */ - if (GlobalIndex == jPoint) edge_to_triangle[iEdge].push_back(neighborElemsOfPoint[iPoint][iElem]); + if (GlobalIndex == jPoint) edge_to_triangle[i_level][iEdge].push_back(neighborElemsOfPoint[iPoint][iElem]); } } } + } } void CLookUpTable::ComputeInterpCoeffs(const string& name_x, const string& name_y) { - /* build KD tree for y, x space */ + for(auto i_level=0ul; i_level next_triangle; + std::array next_triangle; - const su2double* x = GetDataP(name_x); - const su2double* y = GetDataP(name_y); + const su2double* val_x = GetDataP(name_x, i_level); + const su2double* val_y = GetDataP(name_y, i_level); - /* calculate weights for each triangle (basically a distance function) and - * build inverse interpolation matrices */ - for (unsigned long i_triangle = 0; i_triangle < n_triangles; i_triangle++) { + /* calculate weights for each triangle (basically a distance function) and + * build inverse interpolation matrices */ + for (unsigned long i_triangle = 0; i_triangle < n_triangles[i_level]; i_triangle++) { - for (int p = 0; p < 3; p++) { - next_triangle[p] = triangles[i_triangle][p]; - } + for (int p = 0; p < 3; p++) { + next_triangle[p] = triangles[i_level][i_triangle][p]; + } - su2activematrix x_interp_mat_inv(3, 3); - GetInterpMatInv(x, y, next_triangle, x_interp_mat_inv); - interp_mat_inv_x_y.push_back(x_interp_mat_inv); + su2activematrix x_interp_mat_inv(3, 3); + GetInterpMatInv(val_x, val_y, next_triangle, x_interp_mat_inv); + interp_mat_inv_x_y[i_level].push_back(x_interp_mat_inv); + } } } @@ -291,8 +340,76 @@ void CLookUpTable::GetInterpMatInv(const su2double* vec_x, const su2double* vec_ } +std::pair CLookUpTable::FindInclusionLevels(su2double val_z, bool*within_table_limits) +{ + std::pair inclusion_levels; + if(val_z >= limits_table_z.second){ + *within_table_limits = false; + inclusion_levels = std::make_pair(n_table_levels-1, n_table_levels-1); + }else if(val_z <= limits_table_z.first){ + *within_table_limits = false; + inclusion_levels = std::make_pair(0, 0); + }else{ + for(auto i_level = 0ul; i_level < n_table_levels-1; i_level++){ + if((val_z >= z_values_levels[i_level]) && (val_z < z_values_levels[i_level+1])){ + *within_table_limits = true; + inclusion_levels = std::make_pair(i_level, i_level+1); + } + } + } + return inclusion_levels; +} + +unsigned long CLookUpTable::LookUp_XYZ(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, + su2double val_y, const std::string& name_x, const std::string& name_y, su2double val_z) +{ + bool within_z_limits, exit_code; + unsigned long lower_level, upper_level; + std::pair inclusion_levels; + if(val_z == 0){ + inclusion_levels = std::make_pair(0, 0); + within_z_limits = false; + }else{ + inclusion_levels = FindInclusionLevels(val_z, &within_z_limits); + } + + if(within_z_limits){ + lower_level = inclusion_levels.first; + upper_level = inclusion_levels.second; + std::vector val_vars_lower, val_vars_upper; + val_vars_lower.resize(val_vars.size()); + val_vars_upper.resize(val_vars.size()); + unsigned long exit_code_lower = LookUp_XY(val_names_var, val_vars_lower, val_x, val_y, name_x, name_y, lower_level); + unsigned long exit_code_upper = LookUp_XY(val_names_var, val_vars_upper, val_x, val_y, name_x, name_y, upper_level); + + Linear_Interpolation(val_z, inclusion_levels, val_vars_lower, val_vars_upper, val_vars); + + return max(exit_code_lower, exit_code_upper); + }else{ + lower_level = inclusion_levels.first; + exit_code = LookUp_XY(val_names_var, val_vars, val_x, val_y, name_x, name_y, lower_level); + if( val_z == 0 ){ + return exit_code; + }else{ + return 1; + } + } +} + +void CLookUpTable::Linear_Interpolation(su2double val_z, std::pair &inclusion_levels, std::vector&lower_values,std::vector&upper_values, std::vector&var_vals) +{ + su2double val_z_lower = z_values_levels[inclusion_levels.first]; + su2double val_z_upper = z_values_levels[inclusion_levels.second]; + su2double factor_upper = (val_z - val_z_lower) / (val_z_upper - val_z_lower); + su2double factor_lower = (val_z_upper - val_z) / (val_z_upper - val_z_lower); + + for(unsigned short iVar=0; iVar= limits_table_x[0] && val_x <= limits_table_x[1]) && - (val_y >= limits_table_y[0] && val_y <= limits_table_y[1])){ + if ((val_x >= limits_table_x[i_level].first && val_x <= limits_table_x[i_level].second) && + (val_y >= limits_table_y[i_level].first && val_y <= limits_table_y[i_level].second)){ /* find the triangle that holds the (x, y) point */ - unsigned long id_triangle = trap_map_x_y.GetTriangle(val_x, val_y); + unsigned long id_triangle = trap_map_x_y[i_level].GetTriangle(val_x, val_y); - if (IsInTriangle(val_x, val_y, id_triangle, name_x, name_y)) { + if (IsInTriangle(val_x, val_y, id_triangle, name_x, name_y, i_level)) { /* get interpolation coefficients for point on triangle */ std::array interp_coeffs{0}; - GetInterpCoeffs(val_x, val_y, interp_mat_inv_x_y[id_triangle], interp_coeffs); + GetInterpCoeffs(val_x, val_y, interp_mat_inv_x_y[i_level][id_triangle], interp_coeffs); /* first, copy the single triangle from the large triangle list*/ std::array triangle{0}; for (int p = 0; p < 3; p++) - triangle[p] = triangles[id_triangle][p]; + triangle[p] = triangles[i_level][id_triangle][p]; *val_var = Interpolate(GetDataP(val_name_var), triangle, interp_coeffs); exit_code = 0; } else { /* in bounding box but outside of table */ - unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y); - *val_var = GetDataP(val_name_var)[nearest_neighbor]; + unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y, i_level); + *val_var = GetDataP(val_name_var, i_level)[nearest_neighbor]; exit_code = 1; } } else { /* lookup is outside of table bounding box */ - unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y); - *val_var = GetDataP(val_name_var)[nearest_neighbor]; + unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y, i_level); + *val_var = GetDataP(val_name_var, i_level)[nearest_neighbor]; exit_code = 1; } return exit_code; @@ -337,52 +454,52 @@ unsigned long CLookUpTable::LookUp_XY(const string& val_name_var, su2double *val unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vector& val_vars, su2double val_x, su2double val_y, const string& name_x, - const string& name_y) { + const string& name_y, unsigned long i_level) { vector look_up_data; for (long unsigned int i_var = 0; i_var < val_vars.size(); ++i_var) { look_up_data.push_back(&val_vars[i_var]); } - unsigned long exit_code = LookUp_XY(val_names_var, look_up_data, val_x, val_y, name_x, name_y); + unsigned long exit_code = LookUp_XY(val_names_var, look_up_data, val_x, val_y, name_x, name_y, i_level); return exit_code; } unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vector& val_vars, su2double val_x, su2double val_y, const string& name_x, - const string& name_y) { + const string& name_y, unsigned long i_level) { unsigned long exit_code = 0; unsigned long nearest_neighbor = 0; unsigned long id_triangle; std::array interp_coeffs{0}; std::array triangle{0}; - /* check if x value is in x table range - * and if y is in y table range */ - if (val_x >= limits_table_x[0] && val_x <= limits_table_x[1] && val_y >= limits_table_y[0] && - val_y <= limits_table_y[1]) { - /* if so, try to find the triangle that holds the (x, y) point */ - id_triangle = trap_map_x_y.GetTriangle(val_x, val_y); + /* check if x value is in table x-dimension range + * and if y is in table y-dimension table range */ + if ((val_x >= limits_table_x[i_level].first && val_x <= limits_table_x[i_level].second) && + (val_y >= limits_table_y[i_level].first && val_y <= limits_table_y[i_level].second)){ + /* if so, try to find the triangle that holds the (prog, enth) point */ + id_triangle = trap_map_x_y[i_level].GetTriangle(val_x, val_y); /* check if point is inside a triangle (if table domain is non-rectangular, * the previous range check might be true but the point could still be outside of the domain) */ - if (IsInTriangle(val_x, val_y, id_triangle, name_x, name_y)) { + if (IsInTriangle(val_x, val_y, id_triangle, name_x, name_y, i_level)) { /* if so, get interpolation coefficients for point in the triangle */ - GetInterpCoeffs(val_x, val_y, interp_mat_inv_x_y[id_triangle], interp_coeffs); + GetInterpCoeffs(val_x, val_y, interp_mat_inv_x_y[i_level][id_triangle], interp_coeffs); /* exit_code 0 means point was in triangle */ exit_code = 0; } else { /* if point is not inside a triangle (outside table domain) search nearest neighbor */ - nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y); + nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y, i_level); exit_code = 1; } } else { /* if point is outside of table ranges, find nearest neighbor */ - nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y); + nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y, i_level); exit_code = 1; } @@ -395,11 +512,11 @@ unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vecto /* first, copy the single triangle from the large triangle list*/ for (int p = 0; p < 3; p++) - triangle[p] = triangles[id_triangle][p]; + triangle[p] = triangles[i_level][id_triangle][p]; *val_vars[i_var] = Interpolate(GetDataP(val_names_var[i_var]), triangle, interp_coeffs); } else - *val_vars[i_var] = GetDataP(val_names_var[i_var])[nearest_neighbor]; + *val_vars[i_var] = GetDataP(val_names_var[i_var], i_level)[nearest_neighbor]; } } return exit_code; @@ -434,45 +551,45 @@ su2double CLookUpTable::Interpolate(const su2double* val_samples, std::array Date: Tue, 22 Nov 2022 14:30:22 +0100 Subject: [PATCH 044/598] Improved Newton solver behavior in data driven fluid model --- .../multilayer_perceptron/CLayer.hpp | 3 -- .../multilayer_perceptron/CNeuralNetwork.hpp | 3 -- SU2_CFD/include/fluid/CDataDrivenFluid.hpp | 12 ++++++++ SU2_CFD/include/fluid/CFluidModel.hpp | 12 ++++++++ SU2_CFD/src/fluid/CCoolProp.cpp | 28 +++++++++++++++++++ SU2_CFD/src/fluid/CDataDrivenFluid.cpp | 12 ++++---- SU2_CFD/src/solvers/CEulerSolver.cpp | 5 +++- 7 files changed, 62 insertions(+), 13 deletions(-) diff --git a/Common/include/toolboxes/multilayer_perceptron/CLayer.hpp b/Common/include/toolboxes/multilayer_perceptron/CLayer.hpp index c72709fe52e..92566312809 100644 --- a/Common/include/toolboxes/multilayer_perceptron/CLayer.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CLayer.hpp @@ -126,9 +126,6 @@ class CLayer */ string getActivationType(){return activation_type;} - ~CLayer(){ - delete [] neurons; - }; }; } diff --git a/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp index b58528069d8..54eb19f3238 100644 --- a/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp @@ -83,8 +83,6 @@ class CNeuralNetwork delete total_layers.at(i); } delete [] ANN_outputs; - delete [] inputLayer; - delete [] outputLayer; delete [] activation_function_types; }; void defineInputLayer(unsigned long n_neurons); @@ -101,7 +99,6 @@ class CNeuralNetwork unsigned long getNNeurons(unsigned long iLayer){; return total_layers.at(iLayer)->getNNeurons();} - //unsigned long getNNeurons(unsigned long iLayer, unsigned long iNeuron){return weights.at(iLayer).at(iNeuron).size();} void predict(std::vector &inputs); diff --git a/SU2_CFD/include/fluid/CDataDrivenFluid.hpp b/SU2_CFD/include/fluid/CDataDrivenFluid.hpp index 79e423d6215..deb893edd6b 100644 --- a/SU2_CFD/include/fluid/CDataDrivenFluid.hpp +++ b/SU2_CFD/include/fluid/CDataDrivenFluid.hpp @@ -127,4 +127,16 @@ class CDataDrivenFluid : public CFluidModel { * \param[in] s - second thermodynamic variable (s). */ void SetTDState_Ps(su2double P, su2double s) override; + + /*! + * \brief Set the initial guess for the density in Newton solvers + * \param[in] rho - Initial value for density. + */ + void SetDensity(su2double rho) override {rho_start = rho;} + + /*! + * \brief Set the initial guess for the static energy in Newton solvers + * \param[in] e - Initial value for static energy. + */ + void SetEnergy(su2double e) override {e_start = e;} }; diff --git a/SU2_CFD/include/fluid/CFluidModel.hpp b/SU2_CFD/include/fluid/CFluidModel.hpp index b57badc99c9..4a1bc47e403 100644 --- a/SU2_CFD/include/fluid/CFluidModel.hpp +++ b/SU2_CFD/include/fluid/CFluidModel.hpp @@ -325,4 +325,16 @@ class CFluidModel { * \brief Set fluid eddy viscosity provided by a turbulence model needed for computing effective thermal conductivity. */ void SetEddyViscosity(su2double val_Mu_Turb) { Mu_Turb = val_Mu_Turb; } + + /*! + * \brief Set the initial guess for the density in Newton solvers + * \param[in] rho - Initial value for density. + */ + virtual void SetDensity(su2double rho) {} + + /*! + * \brief Set the initial guess for the static energy in Newton solvers + * \param[in] e - Initial value for static energy. + */ + virtual void SetEnergy(su2double e) {} }; diff --git a/SU2_CFD/src/fluid/CCoolProp.cpp b/SU2_CFD/src/fluid/CCoolProp.cpp index 61dfb5840cb..9121c8164ed 100644 --- a/SU2_CFD/src/fluid/CCoolProp.cpp +++ b/SU2_CFD/src/fluid/CCoolProp.cpp @@ -37,6 +37,34 @@ CCoolProp::CCoolProp(string fluidname) : CFluidModel() { Pressure_Critical = fluid_entity->p_critical(); Temperature_Critical = fluid_entity->T_critical(); acentric_factor = fluid_entity->acentric_factor(); + + su2double p = 5e4; + su2double T = 250; + su2double p_max = 2e6; + su2double T_max = 600; + su2double delta_p = (p_max - p)/500; + su2double delta_T = (T_max - T)/500; + cout << "rho, e, s, dsde_rho, dsdrho_e, d2sde2, d2sdedrho, d2sdrho2, pressure, temperature, soundspeed2" << endl; + for(unsigned long i=0;i<500;i++){ + p = 5e4; + for(unsigned long j=0; j<500;j++){ + fluid_entity->update(CoolProp::PT_INPUTS, p, T); + cout << fluid_entity->rhomass() << ", " + << fluid_entity->umass() << ", " + << fluid_entity->smass() << ", " + << fluid_entity->first_partial_deriv(CoolProp::iSmass, CoolProp::iUmass, CoolProp::iDmass) << ", " + << fluid_entity->first_partial_deriv(CoolProp::iSmass, CoolProp::iDmass, CoolProp::iUmass) << ", " + << fluid_entity->second_partial_deriv(CoolProp::iSmass, CoolProp::iUmass, CoolProp::iDmass, CoolProp::iUmass, CoolProp::iDmass) << ", " + << fluid_entity->second_partial_deriv(CoolProp::iSmass, CoolProp::iUmass, CoolProp::iDmass, CoolProp::iDmass, CoolProp::iUmass) << ", " + << fluid_entity->second_partial_deriv(CoolProp::iSmass, CoolProp::iDmass, CoolProp::iUmass, CoolProp::iDmass, CoolProp::iUmass) << ", " + << p << ", " + << T << ", " + << pow(fluid_entity->speed_sound(), 2) << endl; + p += delta_p; + } + T += delta_T; + + } } CCoolProp::~CCoolProp() {} diff --git a/SU2_CFD/src/fluid/CDataDrivenFluid.cpp b/SU2_CFD/src/fluid/CDataDrivenFluid.cpp index 7dafd4bf5e6..b95f7c81986 100644 --- a/SU2_CFD/src/fluid/CDataDrivenFluid.cpp +++ b/SU2_CFD/src/fluid/CDataDrivenFluid.cpp @@ -60,6 +60,7 @@ CDataDrivenFluid::CDataDrivenFluid(const CConfig* config) : CFluidModel() { /*--- Set initial values for density and energy based on config options ---*/ rho_start = config->GetDensity_Init_DataDriven(); e_start = config->GetEnergy_Init_DataDriven(); + } CDataDrivenFluid::~CDataDrivenFluid(){ @@ -148,7 +149,7 @@ void CDataDrivenFluid::SetTDState_rhoe(su2double rho, su2double e) { dPde_rho = -pow(rho, 2) * dTde_rho * dsdrho_e; dPdrho_e = -2*rho*Temperature*dsdrho_e - pow(rho, 2)*Temperature*d2sdrho2; - Cp = (1 / dTde_rho) * ( 1 + (1 / Density)*dPde_rho) + (1/Density)*(1/dTdrho_e)*(dPdrho_e - Pressure / Density); + Cp = (1 / dTde_rho) * ( 1 + (1 / Density)*dPde_rho); Cv = 1 / dTde_rho; Gamma = Cp / Cv; Gamma_Minus_One = Gamma - 1; @@ -174,7 +175,6 @@ void CDataDrivenFluid::SetTDState_PT(su2double P, su2double T) { delta_rho, // Density step size delta_e, // Energy step size determinant; // Jacobian determinant - /*--- Initiating Newton solver ---*/ while(!converged && (Iter < iter_max)){ @@ -184,7 +184,6 @@ void CDataDrivenFluid::SetTDState_PT(su2double P, su2double T) { /*--- Determine pressure and temperature residuals ---*/ delta_P = Pressure - P; delta_T = Temperature - T; - /*--- Continue iterative process if residuals are outside tolerances ---*/ if((abs(delta_P) < tolerance_P) && (abs(delta_T) < tolerance_T)){ converged = true; @@ -199,6 +198,7 @@ void CDataDrivenFluid::SetTDState_PT(su2double P, su2double T) { /*--- Update density and energy values ---*/ rho -= Newton_Relaxation * delta_rho; e -= Newton_Relaxation * delta_e; + } Iter ++; } @@ -210,6 +210,7 @@ void CDataDrivenFluid::SetTDState_PT(su2double P, su2double T) { void CDataDrivenFluid::SetTDState_Prho(su2double P, su2double rho) { /*--- Computing static energy according to pressure and density ---*/ SetEnergy_Prho(P, rho); + /*--- Calculate thermodynamic state based on converged value for energy ---*/ SetTDState_rhoe(rho, StaticEnergy); @@ -245,7 +246,7 @@ void CDataDrivenFluid::SetEnergy_Prho(su2double P, su2double rho) { delta_e = delta_P / dPde_rho; /*--- energy value ---*/ - e += Newton_Relaxation * delta_e; + e -= Newton_Relaxation * delta_e; } Iter ++; } @@ -286,7 +287,7 @@ void CDataDrivenFluid::SetTDState_rhoT(su2double rho, su2double T) { delta_e = delta_T / dTde_rho; /*--- Update energy value ---*/ - e += Newton_Relaxation * delta_e; + e -= Newton_Relaxation * delta_e; } Iter ++; } @@ -343,7 +344,6 @@ void CDataDrivenFluid::SetTDState_hs(su2double h, su2double s) { } Iter ++; } - /*--- Calculate thermodynamic state based on converged values for density and energy ---*/ SetTDState_rhoe(rho, e); } diff --git a/SU2_CFD/src/solvers/CEulerSolver.cpp b/SU2_CFD/src/solvers/CEulerSolver.cpp index d2f07539d29..1850649063e 100644 --- a/SU2_CFD/src/solvers/CEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CEulerSolver.cpp @@ -4658,11 +4658,14 @@ void CEulerSolver::BC_Riemann(CGeometry *geometry, CSolver **solver_container, P_Total /= config->GetPressure_Ref(); T_Total /= config->GetTemperature_Ref(); + /*--- Set initial values for density and energy for Newton solvers in fluid model ---*/ + GetFluidModel()->SetDensity(Density_i); + GetFluidModel()->SetEnergy(StaticEnergy_i); + /* --- Computes the total state --- */ GetFluidModel()->SetTDState_PT(P_Total, T_Total); Enthalpy_e = GetFluidModel()->GetStaticEnergy()+ GetFluidModel()->GetPressure()/GetFluidModel()->GetDensity(); Entropy_e = GetFluidModel()->GetEntropy(); - /* --- Compute the boundary state u_e --- */ Velocity2_e = Velocity2_i; if (nDim == 2){ From 32366c44e07f11e3628581a6fe7ca45ef93b4136 Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Tue, 22 Nov 2022 16:34:29 +0100 Subject: [PATCH 045/598] Removed controlling variable names from inputs to lookup operations, as they're redundant. Added a 3D table unit test case --- Common/include/containers/CFileReaderLUT.hpp | 5 +- Common/include/containers/CLookUpTable.hpp | 59 ++++---- Common/src/containers/CFileReaderLUT.cpp | 115 +++++++++++---- Common/src/containers/CLookUpTable.cpp | 112 ++++++++++----- .../Common/containers/CLookupTable_tests.cpp | 56 +++++++- .../Common/containers/lookuptable_3D.drg | 135 ++++++++++++++++++ 6 files changed, 383 insertions(+), 99 deletions(-) create mode 100644 UnitTests/Common/containers/lookuptable_3D.drg diff --git a/Common/include/containers/CFileReaderLUT.hpp b/Common/include/containers/CFileReaderLUT.hpp index 37b6f7a4aaa..fbd31bc84fb 100644 --- a/Common/include/containers/CFileReaderLUT.hpp +++ b/Common/include/containers/CFileReaderLUT.hpp @@ -50,6 +50,7 @@ class CFileReaderLUT { unsigned long *n_triangles; unsigned long *n_hull_points; unsigned long n_variables; + su2double *table_levels = nullptr; /*! \brief Holds the variable names stored in the table file. * Order is in sync with tableFlamelet. @@ -81,7 +82,7 @@ class CFileReaderLUT { public: CFileReaderLUT(){}; - + ~CFileReaderLUT(); inline const std::string& GetVersionLUT() const { return version_lut; } inline const std::string& GetVersionReader() const { return version_reader; } inline unsigned long GetNPoints(std::size_t i_level=0) const { return n_points[i_level]; } @@ -98,6 +99,8 @@ class CFileReaderLUT { inline const std::vector& GetHull(std::size_t i_level=0) const { return hull[i_level]; } + inline const su2double GetTableLevel(std::size_t i_level) const { return table_levels[i_level]; } + inline const unsigned short GetTableDim() const { return table_dim; } void ReadRawLUT(const std::string& file_name); diff --git a/Common/include/containers/CLookUpTable.hpp b/Common/include/containers/CLookUpTable.hpp index 3dcfceb0d51..b92f0903aef 100644 --- a/Common/include/containers/CLookUpTable.hpp +++ b/Common/include/containers/CLookUpTable.hpp @@ -47,6 +47,9 @@ class CLookUpTable { std::string file_name_lut; std::string version_lut; std::string version_reader; + std::string name_CV1, // Name of controlling variable 1 + name_CV2; // Name of xontrolling variable 2 + unsigned long *n_points; unsigned long *n_triangles; unsigned long n_variables; @@ -135,10 +138,8 @@ class CLookUpTable { /*! * \brief compute vector of all (inverse) interpolation coefficients "interp_mat_inv_x_y" of all triangles. - * \param[in] name_x - the string name of the first controlling variable. - * \param[in] name_y - the string name of the second controlling variable. */ - void ComputeInterpCoeffs(const std::string& name_x, const std::string& name_y); + void ComputeInterpCoeffs(); /*! * \brief compute the inverse matrix for interpolation. @@ -170,29 +171,27 @@ class CLookUpTable { su2double Interpolate(const su2double* val_samples, std::array& val_triangle, std::array& val_interp_coeffs); + void Linear_Interpolation(su2double val_z, std::pair &inclusion_levels, su2double&lower_value,su2double&upper_value, su2double*&var_vals); + + void Linear_Interpolation(su2double val_z, std::pair &inclusion_levels, std::vector&lower_values,std::vector&upper_values, std::vector&var_vals); /*! * \brief find the point on the hull (boundary of the table) that is closest to the point P(val_x,val_y). * \param[in] val_x - first coordinate of point P(val_x,val_y) to check. * \param[in] val_y - second coordinate of point P(val_x,val_y) to check. - * \param[in] name_x - string name of the first controlling variable. - * \param[in] name_y - string name of the second controlling variable. * \returns point id of the nearest neighbor on the hull. */ - unsigned long FindNearestNeighborOnHull(su2double val_x, su2double val_y, const std::string& name_x, const std::string& name_y, unsigned long i_level=0); + unsigned long FindNearestNeighborOnHull(su2double val_x, su2double val_y, unsigned long i_level=0); /*! * \brief determine if a point P(val_x,val_y) is inside the triangle val_id_triangle. * \param[in] val_x - first coordinate of point P(val_x,val_y) to check. * \param[in] val_y - second coordinate of point P(val_x,val_y) to check. * \param[in] val_id_triangle - ID of the triangle to check. - * \param[in] name_x - string name of the first controlling variable. - * \param[in] name_y - string name of the second controlling variable. * \returns true if the point is in the triangle, false if it is outside. */ - bool IsInTriangle(su2double val_x, su2double val_y, unsigned long val_id_triangle, const std::string& name_x, - const std::string& name_y, unsigned long i_level=0); + bool IsInTriangle(su2double val_x, su2double val_y, unsigned long val_id_triangle, unsigned long i_level=0); /*! * \brief compute the area of a triangle given the 3 points of the triangle. @@ -218,61 +217,59 @@ class CLookUpTable { void PrintTableInfo(); /*! - * \brief lookup 1 value of the single variable "val_name_var" using controlling variable values(val_x,val_y) - * whose controlling variable names are "name_prog" and "name_enth". + * \brief lookup 1 value of the single variable "val_name_var" using controlling variable values(val_x,val_y). * \param[in] val_name_var - string name of the variable to look up. * \param[out] val_var - the stored value of the variable to look up. * \param[in] val_x - value of controlling variable 1. * \param[in] val_y - value of controlling variable 2. - * \param[in] name_x - string name of controlling variable 1. - * \param[in] name_y - string name of controlling variable 2. * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ - unsigned long LookUp_XY(const std::string& val_name_var, su2double* val_var, su2double val_x, su2double val_y, - const std::string& name_x, const std::string& name_y, unsigned long i_level=0); + unsigned long LookUp_XY(const std::string& val_name_var, su2double* val_var, su2double val_x, su2double val_y, unsigned long i_level=0); /*! - * \brief lookup 1 value for each of the variables in "val_name_var" using controlling variable values(val_x,val_y) - * whose controlling variable names are "name_x" and "name_y". + * \brief lookup 1 value for each of the variables in "val_name_var" using controlling variable values(val_x,val_y). * \param[in] val_names_var - vector of string names of the variables to look up. * \param[out] val_vars - pointer to the vector of stored values of the variables to look up. * \param[in] val_x - value of controlling variable 1. * \param[in] val_y - value of controlling variable 2. - * \param[in] name_x - string name of controlling variable 1. - * \param[in] name_y - string name of controlling variable 2. * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ unsigned long LookUp_XY(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, - su2double val_y, const std::string& name_x, const std::string& name_y, unsigned long i_level=0); + su2double val_y, unsigned long i_level=0); /*! - * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_x,val_y) - * whose controlling variable names are "name_x" and "name_y". + * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_x,val_y). * \param[in] val_name_var - string name of the variable to look up. * \param[out] val_var - the stored value of the variable to look up. * \param[in] val_x - value of controlling variable 1. * \param[in] val_y - value of controlling variable 2. - * \param[in] name_x - string name of controlling variable 1. - * \param[in] name_y - string name of controlling variable 2. * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ unsigned long LookUp_XY(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, - su2double val_y, const std::string& name_x, const std::string& name_y, unsigned long i_level=0); + su2double val_y, unsigned long i_level=0); + + /*! + * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_x,val_y,val_z). + * \param[in] val_name_var - string name of the variable to look up. + * \param[out] val_var - the stored value of the variable to look up. + * \param[in] val_x - value of controlling variable 1. + * \param[in] val_y - value of controlling variable 2. + * \param[in] val_z - value of controlling variable 3. + * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. + */ + unsigned long LookUp_XYZ(const std::string& val_name_var, su2double* val_var, su2double val_x, su2double val_y, su2double val_z); /*! - * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_x,val_y,val_z) - * whose controlling variable names are "name_x" and "name_y". + * \brief lookup the value of the variable "val_name_var" using controlling variable values(val_x,val_y,val_z). * \param[in] val_name_var - string name of the variable to look up. * \param[out] val_var - the stored value of the variable to look up. * \param[in] val_x - value of controlling variable 1. * \param[in] val_y - value of controlling variable 2. - * \param[in] name_x - string name of controlling variable 1. - * \param[in] name_y - string name of controlling variable 2. * \param[in] val_z - value of controlling variable 3. * \returns 1 if the lookup and subsequent interpolation was a success, 0 if not. */ unsigned long LookUp_XYZ(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, - su2double val_y, const std::string& name_x, const std::string& name_y, su2double val_z=0); + su2double val_y, su2double val_z=0); std::pair FindInclusionLevels(su2double val_z, bool *within_limits); diff --git a/Common/src/containers/CFileReaderLUT.cpp b/Common/src/containers/CFileReaderLUT.cpp index 4e9e6b013d2..d18ab05f7f8 100644 --- a/Common/src/containers/CFileReaderLUT.cpp +++ b/Common/src/containers/CFileReaderLUT.cpp @@ -63,18 +63,22 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { bool found_level_count = false; while (GetNextNonEmptyLine(file_stream, line) && !eoHeader) { - /*--- number of points in LUT ---*/ + /*--- check version_lut ---*/ if (line.compare("[Version]") == 0) { GetNextNonEmptyLine(file_stream, line); version_lut = line; - if(version_lut.compare("1.0.0") == 0){ + if(version_lut.compare("1.0.1") == 0){ table_dim = 2; n_levels = 1; found_level_count = true; - } - if(version_lut.compare("1.1.0") == 0){ + n_points = new unsigned long[n_levels]; + n_triangles = new unsigned long[n_levels]; + n_hull_points = new unsigned long[n_levels]; + }else if(version_lut.compare("1.1.0") == 0){ table_dim = 3; + }else{ + SU2_MPI::Error("Version conflict between LUT reader and LUT library file.", CURRENT_FUNCTION); } } @@ -87,13 +91,14 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { n_points = new unsigned long[n_levels]; n_triangles = new unsigned long[n_levels]; n_hull_points = new unsigned long[n_levels]; + table_levels = new su2double[n_levels]; } /*--- number of points in LUT ---*/ if (line.compare("[Number of points]") == 0) { if(!found_level_count) SU2_MPI::Error("Number of points provided before specifying level count.", CURRENT_FUNCTION); - for(unsigned long i_level=0; i_level") == 0) eoHeader = true; } - - /*--- check version_lut ---*/ - if (version_lut.compare(version_reader) != 0) - SU2_MPI::Error("Version conflict between LUT reader and LUT library file.", CURRENT_FUNCTION); + /*--- check header quantities ---*/ for(unsigned long i_level=0; i_level < n_levels; i_level++){ @@ -186,7 +194,7 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { SkipToFlag(file_stream, line, ""); unsigned long i_level = 0; - bool eoLevel = false; + bool eoLevel = true; unsigned long pointCounter = 0; unsigned long levelCounter = 0; while (GetNextNonEmptyLine(file_stream, line) && !eoData) { @@ -202,7 +210,7 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { } if(line.compare("") == 0){ eoLevel = true; - if (n_points[levelCounter] != pointCounter - 1) + if (n_points[levelCounter] != pointCounter) SU2_MPI::Error( "Number of read points on level " + std::to_string(levelCounter) + " does not match number of points " "specified in lookup table library header.", @@ -232,6 +240,8 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { SkipToFlag(file_stream, line, ""); i_level = 0; unsigned long triCounter = 0; + eoLevel = true; + levelCounter = 0; while (GetNextNonEmptyLine(file_stream, line) && !eoConnectivity) { if (!line.empty() && (line[line.length()-1] == '\n' || line[line.length()-1] == '\r' )) { line.erase(line.length()-1); @@ -240,22 +250,39 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { if (line.compare("") == 0) eoConnectivity = true; if (!eoConnectivity) { - /*--- one line contains values for one triangle (3 points) ---*/ - istringstream streamTriLine(line); + if(line.compare("") == 0){ + eoLevel = false; + triCounter = 0; + GetNextNonEmptyLine(file_stream, line); + } + if(line.compare("") == 0){ + eoLevel = true; + if (n_triangles[levelCounter] != triCounter) + SU2_MPI::Error( + "Number of read points on level " + std::to_string(levelCounter) + " does not match number of points " + "specified in lookup table library header.", + CURRENT_FUNCTION); + levelCounter++; + } + if(!eoLevel || (table_dim == 2)){ + /*--- one line contains values for one triangle (3 points) ---*/ + istringstream streamTriLine(line); - /*--- add next line to triangles ---*/ - for (int iPoint = 0; iPoint < 3; iPoint++) { + /*--- add next line to triangles ---*/ + for (int iPoint = 0; iPoint < 3; iPoint++) { - streamTriLine >> word; + streamTriLine >> word; - /*--- lookup table index starts with 1, convert to c++ indexing starting with 0: ---*/ - triangles[i_level][triCounter][iPoint] = stol(word) - 1; + /*--- lookup table index starts with 1, convert to c++ indexing starting with 0: ---*/ + triangles[levelCounter][triCounter][iPoint] = stol(word) - 1; + } + triCounter++; } } - triCounter++; + } - if (n_triangles[i_level] != triCounter - 1) + if (n_triangles[0] != triCounter) SU2_MPI::Error( "Number of read triangles does not match number of points " "specified in lookup table library header.", @@ -267,6 +294,8 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { SkipToFlag(file_stream, line, ""); i_level = 0; unsigned long hullCounter = 0; + eoLevel = true; + levelCounter = 0; while (GetNextNonEmptyLine(file_stream, line) && !eoHull) { if (!line.empty() && (line[line.length()-1] == '\n' || line[line.length()-1] == '\r' )) { line.erase(line.length()-1); @@ -275,18 +304,34 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { if (line.compare("") == 0) eoHull = true; if (!eoHull) { - /*--- one line contains one point ID for one point on the hull ---*/ - istringstream streamHullLine(line); + if(line.compare("") == 0){ + eoLevel = false; + hullCounter = 0; + GetNextNonEmptyLine(file_stream, line); + } + if(line.compare("") == 0){ + eoLevel = true; + if (n_hull_points[levelCounter] != hullCounter) + SU2_MPI::Error( + "Number of read points on level " + std::to_string(levelCounter) + " does not match number of points " + "specified in lookup table library header.", + CURRENT_FUNCTION); + levelCounter++; + } + if(!eoLevel || (table_dim == 2)){ + /*--- one line contains one point ID for one point on the hull ---*/ + istringstream streamHullLine(line); - streamHullLine >> word; + streamHullLine >> word; - /*--- Lookup table indices start with 1, convert to c++ indexing starting with 0: ---*/ - hull[i_level][hullCounter] = stol(word) - 1; - } - hullCounter++; + /*--- Lookup table indices start with 1, convert to c++ indexing starting with 0: ---*/ + hull[levelCounter][hullCounter] = stol(word) - 1; + hullCounter++; + } + } } - if (n_hull_points[i_level] != hullCounter - 1) + if (n_hull_points[0] != hullCounter) SU2_MPI::Error( "Number of read hull points does not match number of points " "specified in lookup table library header.", @@ -296,6 +341,16 @@ void CFileReaderLUT::ReadRawLUT(const string& file_name) { } +CFileReaderLUT::~CFileReaderLUT(){ + delete [] n_triangles; + delete [] n_hull_points; + delete [] n_points; + delete [] table_data; + delete [] hull; + delete [] triangles; + if(table_levels != nullptr) delete [] table_levels; +} + void CFileReaderLUT::SkipToFlag(ifstream& file_stream, const string& current_line, const string& flag) const { string next_line = ""; diff --git a/Common/src/containers/CLookUpTable.cpp b/Common/src/containers/CLookUpTable.cpp index a64ebcfa7ab..f3e455a1418 100644 --- a/Common/src/containers/CLookUpTable.cpp +++ b/Common/src/containers/CLookUpTable.cpp @@ -36,6 +36,9 @@ CLookUpTable::CLookUpTable(const string& var_file_name_lut, const string& name_x rank = SU2_MPI::GetRank(); + name_CV1 = name_x; + name_CV2 = name_y; + LoadTableRaw(var_file_name_lut); FindTableLimits(name_x, name_y); @@ -67,7 +70,7 @@ CLookUpTable::CLookUpTable(const string& var_file_name_lut, const string& name_x cout << "Precomputing interpolation coefficients..." << endl; - ComputeInterpCoeffs(name_x, name_y); + ComputeInterpCoeffs(); if (rank == MASTER_NODE) cout << "LUT fluid model ready for use" << endl; @@ -123,8 +126,9 @@ void CLookUpTable::LoadTableRaw(const string& var_file_name_lut) { if(table_dim == 3){ z_values_levels = new su2double[n_table_levels]; - //TODO: fill in z-values from table reader. - //TODO: get minimum and maximum z-values from table reader. + for(unsigned long i_level=0; i_level next_triangle; - const su2double* val_x = GetDataP(name_x, i_level); - const su2double* val_y = GetDataP(name_y, i_level); + const su2double* val_x = GetDataP(name_CV1, i_level); + const su2double* val_y = GetDataP(name_CV2, i_level); /* calculate weights for each triangle (basically a distance function) and * build inverse interpolation matrices */ @@ -360,8 +364,41 @@ std::pair CLookUpTable::FindInclusionLevels(su2dou return inclusion_levels; } +unsigned long CLookUpTable::LookUp_XYZ(const std::string& val_name_var, su2double* val_var, su2double val_x, + su2double val_y, su2double val_z) +{ + bool within_z_limits, exit_code; + unsigned long lower_level, upper_level; + std::pair inclusion_levels; + if(val_z == 0){ + inclusion_levels = std::make_pair(0, 0); + within_z_limits = false; + }else{ + inclusion_levels = FindInclusionLevels(val_z, &within_z_limits); + } + + if(within_z_limits){ + lower_level = inclusion_levels.first; + upper_level = inclusion_levels.second; + su2double val_var_lower, val_var_upper; + unsigned long exit_code_lower = LookUp_XY(val_name_var, &val_var_lower, val_x, val_y, lower_level); + unsigned long exit_code_upper = LookUp_XY(val_name_var, &val_var_upper, val_x, val_y, upper_level); + + Linear_Interpolation(val_z, inclusion_levels, val_var_lower, val_var_upper, val_var); + + return max(exit_code_lower, exit_code_upper); + }else{ + lower_level = inclusion_levels.first; + exit_code = LookUp_XY(val_name_var, val_var, val_x, val_y, lower_level); + if( val_z == 0 ){ + return exit_code; + }else{ + return 1; + } + } +} unsigned long CLookUpTable::LookUp_XYZ(const std::vector& val_names_var, std::vector& val_vars, su2double val_x, - su2double val_y, const std::string& name_x, const std::string& name_y, su2double val_z) + su2double val_y, su2double val_z) { bool within_z_limits, exit_code; unsigned long lower_level, upper_level; @@ -379,15 +416,15 @@ unsigned long CLookUpTable::LookUp_XYZ(const std::vector& val_names std::vector val_vars_lower, val_vars_upper; val_vars_lower.resize(val_vars.size()); val_vars_upper.resize(val_vars.size()); - unsigned long exit_code_lower = LookUp_XY(val_names_var, val_vars_lower, val_x, val_y, name_x, name_y, lower_level); - unsigned long exit_code_upper = LookUp_XY(val_names_var, val_vars_upper, val_x, val_y, name_x, name_y, upper_level); + unsigned long exit_code_lower = LookUp_XY(val_names_var, val_vars_lower, val_x, val_y, lower_level); + unsigned long exit_code_upper = LookUp_XY(val_names_var, val_vars_upper, val_x, val_y, upper_level); Linear_Interpolation(val_z, inclusion_levels, val_vars_lower, val_vars_upper, val_vars); return max(exit_code_lower, exit_code_upper); }else{ lower_level = inclusion_levels.first; - exit_code = LookUp_XY(val_names_var, val_vars, val_x, val_y, name_x, name_y, lower_level); + exit_code = LookUp_XY(val_names_var, val_vars, val_x, val_y, lower_level); if( val_z == 0 ){ return exit_code; }else{ @@ -396,6 +433,17 @@ unsigned long CLookUpTable::LookUp_XYZ(const std::vector& val_names } } +void CLookUpTable::Linear_Interpolation(su2double val_z, std::pair &inclusion_levels, su2double&lower_value,su2double&upper_value, su2double*&var_val) +{ + su2double val_z_lower = z_values_levels[inclusion_levels.first]; + su2double val_z_upper = z_values_levels[inclusion_levels.second]; + su2double factor_upper = (val_z - val_z_lower) / (val_z_upper - val_z_lower); + su2double factor_lower = (val_z_upper - val_z) / (val_z_upper - val_z_lower); + + *var_val = lower_value * factor_lower + upper_value * factor_upper; + +} + void CLookUpTable::Linear_Interpolation(su2double val_z, std::pair &inclusion_levels, std::vector&lower_values,std::vector&upper_values, std::vector&var_vals) { su2double val_z_lower = z_values_levels[inclusion_levels.first]; @@ -409,7 +457,7 @@ void CLookUpTable::Linear_Interpolation(su2double val_z, std::pair interp_coeffs{0}; GetInterpCoeffs(val_x, val_y, interp_mat_inv_x_y[i_level][id_triangle], interp_coeffs); @@ -439,13 +487,13 @@ unsigned long CLookUpTable::LookUp_XY(const string& val_name_var, su2double *val exit_code = 0; } else { /* in bounding box but outside of table */ - unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y, i_level); + unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, i_level); *val_var = GetDataP(val_name_var, i_level)[nearest_neighbor]; exit_code = 1; } } else { /* lookup is outside of table bounding box */ - unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y, i_level); + unsigned long nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, i_level); *val_var = GetDataP(val_name_var, i_level)[nearest_neighbor]; exit_code = 1; } @@ -453,22 +501,20 @@ unsigned long CLookUpTable::LookUp_XY(const string& val_name_var, su2double *val } unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vector& val_vars, - su2double val_x, su2double val_y, const string& name_x, - const string& name_y, unsigned long i_level) { + su2double val_x, su2double val_y, unsigned long i_level) { vector look_up_data; for (long unsigned int i_var = 0; i_var < val_vars.size(); ++i_var) { look_up_data.push_back(&val_vars[i_var]); } - unsigned long exit_code = LookUp_XY(val_names_var, look_up_data, val_x, val_y, name_x, name_y, i_level); + unsigned long exit_code = LookUp_XY(val_names_var, look_up_data, val_x, val_y, i_level); return exit_code; } unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vector& val_vars, - su2double val_x, su2double val_y, const string& name_x, - const string& name_y, unsigned long i_level) { + su2double val_x, su2double val_y, unsigned long i_level) { unsigned long exit_code = 0; unsigned long nearest_neighbor = 0; unsigned long id_triangle; @@ -484,7 +530,7 @@ unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vecto /* check if point is inside a triangle (if table domain is non-rectangular, * the previous range check might be true but the point could still be outside of the domain) */ - if (IsInTriangle(val_x, val_y, id_triangle, name_x, name_y, i_level)) { + if (IsInTriangle(val_x, val_y, id_triangle, i_level)) { /* if so, get interpolation coefficients for point in the triangle */ GetInterpCoeffs(val_x, val_y, interp_mat_inv_x_y[i_level][id_triangle], interp_coeffs); @@ -493,13 +539,13 @@ unsigned long CLookUpTable::LookUp_XY(const vector& val_names_var, vecto } else { /* if point is not inside a triangle (outside table domain) search nearest neighbor */ - nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y, i_level); + nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, i_level); exit_code = 1; } } else { /* if point is outside of table ranges, find nearest neighbor */ - nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, name_x, name_y, i_level); + nearest_neighbor = FindNearestNeighborOnHull(val_x, val_y, i_level); exit_code = 1; } @@ -550,16 +596,15 @@ su2double CLookUpTable::Interpolate(const su2double* val_samples, std::array +[Version] +1.1.0 + +[Number of table levels] +2 + +[Number of points] +12 +12 + +[Number of triangles] +14 +14 + +[Number of hull points] +8 +8 + +[Progress variable definition] +prog var = 1*Y-CH4 + +[Progress variable range] +0.0 | 1.0 +0.0 | 1.0 + +[Enthalpy range] +-1.0 | 1.0 +-1.0 | 1.0 + +[Table levels] +0.0 +1.0 + +[Number of variables] +4 + +[Variable names] +1:ProgressVariable +2:EnthalpyTot +3:Density +4:Viscosity + +
+ + + +0.0 -1.0 1.0 1.0e-5 +0.3 -1.0 1.0 1.2e-5 +0.6 -1.0 1.0 1.4e-5 +1.0 -1.0 1.0 1.6e-5 +0.5 0.25 1.05 2.0e-5 +0.75 0.25 1.05 3.0e-5 +0.3 0.5 1.1 3.0e-5 +0.6 0.5 1.1 4.0e-5 +1.0 0.5 1.1 5.0e-5 +0.0 1.0 1.2 6.0e-5 +0.3 1.0 1.2 7.0e-5 +1.0 1.0 1.2 8.0e-5 + + +0.0 -1.0 1.0 1.0e-5 +0.3 -1.0 1.0 1.2e-5 +0.6 -1.0 1.0 1.4e-5 +1.0 -1.0 1.0 1.6e-5 +0.5 0.25 1.05 2.0e-5 +0.75 0.25 1.05 3.0e-5 +0.3 0.5 1.1 3.0e-5 +0.6 0.5 1.1 4.0e-5 +1.0 0.5 1.1 5.0e-5 +0.0 1.0 1.2 6.0e-5 +0.3 1.0 1.2 7.0e-5 +1.0 1.0 1.2 8.0e-5 + + + + + +1 2 7 +1 7 11 +1 11 10 +2 5 7 +2 3 5 +3 8 5 +5 8 7 +7 8 11 +3 6 8 +3 4 6 +4 9 6 +6 9 8 +8 9 12 +8 12 11 + + +1 2 7 +1 7 11 +1 11 10 +2 5 7 +2 3 5 +3 8 5 +5 8 7 +7 8 11 +3 6 8 +3 4 6 +4 9 6 +6 9 8 +8 9 12 +8 12 11 + + + + + +1 +2 +3 +4 +9 +12 +11 +10 + + +1 +2 +3 +4 +9 +12 +11 +10 + + From 68d02ae7036ef8fa5d93cfb6a6bc47aa9a280d4d Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Wed, 23 Nov 2022 12:17:38 +0100 Subject: [PATCH 046/598] Added unit test for multi-layer perceptron --- .../CLookUp_ANN_tests.cpp | 35 ++++++++++++++ .../multilayer_perceptron/mlp_collection.mlp | 5 ++ .../multilayer_perceptron/simple_mlp.mlp | 47 +++++++++++++++++++ 3 files changed, 87 insertions(+) create mode 100644 UnitTests/Common/toolboxes/multilayer_perceptron/CLookUp_ANN_tests.cpp create mode 100644 UnitTests/Common/toolboxes/multilayer_perceptron/mlp_collection.mlp create mode 100644 UnitTests/Common/toolboxes/multilayer_perceptron/simple_mlp.mlp diff --git a/UnitTests/Common/toolboxes/multilayer_perceptron/CLookUp_ANN_tests.cpp b/UnitTests/Common/toolboxes/multilayer_perceptron/CLookUp_ANN_tests.cpp new file mode 100644 index 00000000000..13e3709f3f8 --- /dev/null +++ b/UnitTests/Common/toolboxes/multilayer_perceptron/CLookUp_ANN_tests.cpp @@ -0,0 +1,35 @@ +/*! + * \file CLookUp_ANN_tests.cpp + * \brief Unit tests for NdFlattener template classes. + * \author M. Aehle + * \version 7.4.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2022, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "catch.hpp" +#include "../../../../Common/include/toolboxes/multilayer_perceptron/CLookUp_ANN.hpp" +#include "../../../../Common/include/toolboxes/multilayer_perceptron/CIOMap.hpp" + +TEST_CASE("LookUp ANN test", "[LookUpANN]"){ + CLookUp_ANN ANN("mlp_collection.mlp"); + +} diff --git a/UnitTests/Common/toolboxes/multilayer_perceptron/mlp_collection.mlp b/UnitTests/Common/toolboxes/multilayer_perceptron/mlp_collection.mlp new file mode 100644 index 00000000000..620e796825e --- /dev/null +++ b/UnitTests/Common/toolboxes/multilayer_perceptron/mlp_collection.mlp @@ -0,0 +1,5 @@ +[number of MLP files] +1 + +[MLP file names] +simple_mlp.mlp diff --git a/UnitTests/Common/toolboxes/multilayer_perceptron/simple_mlp.mlp b/UnitTests/Common/toolboxes/multilayer_perceptron/simple_mlp.mlp new file mode 100644 index 00000000000..01fb20bd102 --- /dev/null +++ b/UnitTests/Common/toolboxes/multilayer_perceptron/simple_mlp.mlp @@ -0,0 +1,47 @@ +
+ +[number of layers] +3 + +[neurons per layer] +2 +4 +1 + +[activation function] +linear +elu +linear + +[input names] +x +y + +[input normalization] ++0.0000000000000000e+00 +2.0000000000000000e+00 +-1.0000000000000000e+00 +0.0000000000000000e+00 + +[output names] +z + +[output normalization] +-1.0000000000000000e+00 +9.9998769302960888e-01 + +
+ +[weights per layer] + +-4.1729342937469482e-01 -2.2465672492980957e+00 +1.1258139610290527e+00 -7.0158332586288452e-01 ++1.1477893590927124e+00 +2.5089375674724579e-02 +2.6767715811729431e-01 +1.0031684637069702e+00 + + ++2.5062826275825500e-01 +-6.2471812963485718e-01 +-2.0578651130199432e-01 ++2.6085931062698364e-01 + + +[biases per layer] ++0.0000000000000000e+00 +0.0000000000000000e+00 +0.0000000000000000e+00 ++7.5714819133281708e-02 +7.7316933870315552e-01 -4.4279521703720093e-01 +4.1041103005409241e-01 ++2.8878501057624817e-01 From 1a40d51afd58dd01d28189e06c9337010d850af9 Mon Sep 17 00:00:00 2001 From: EvertBunschoten Date: Wed, 23 Nov 2022 15:39:36 +0100 Subject: [PATCH 047/598] Added MLP test case configuration file and unit test --- .../multilayer_perceptron/CNeuralNetwork.hpp | 184 +++++++++++++++--- .../CReadNeuralNetwork.hpp | 10 +- SU2_CFD/src/fluid/CCoolProp.cpp | 28 --- SU2_CFD/src/fluid/CDataDrivenFluid.cpp | 5 +- TestCases/nicf/coolprop/coolprop_nozzle.cfg | 2 +- .../nicf/datadriven/datadriven_nozzle.cfg | 128 ++++++++++++ .../CLookUp_ANN_tests.cpp | 36 +++- .../multilayer_perceptron/mlp_collection.mlp | 2 +- UnitTests/meson.build | 1 + 9 files changed, 330 insertions(+), 66 deletions(-) create mode 100644 TestCases/nicf/datadriven/datadriven_nozzle.cfg diff --git a/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp index 54eb19f3238..c5aa90c30fc 100644 --- a/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp +++ b/Common/include/toolboxes/multilayer_perceptron/CNeuralNetwork.hpp @@ -41,27 +41,28 @@ namespace MLPToolbox{ class CNeuralNetwork { private: - std::vector input_names, - output_names; + std::vector input_names, // MLP input variable names. + output_names; // MLP output variable names. - unsigned long n_hidden_layers; + unsigned long n_hidden_layers; // Number of hidden layers (layers between input and output layer). - CLayer *inputLayer, - *outputLayer; + CLayer *inputLayer, // Pointer to network input layer. + *outputLayer; // Pointer to network output layer. - std::vector hiddenLayers, - total_layers; + std::vector hiddenLayers, // Hidden layer collection. + total_layers; // Hidden layers plus in/output layers - //std::vector>> weights; - std::vector weights_mat; - std::vector> values; + std::vector weights_mat; // Weights of synapses connecting layers - std::vector> input_norm, - output_norm; - std::vector last_inputs; + std::vector> input_norm, // Normalization factors for network inputs + output_norm; // Normalization factors for network outputs - su2double* ANN_outputs; + std::vector last_inputs; // Inputs from previous lookup operation. Evaluation of the network + // is skipped if current inputs are the same as the last inputs. + su2double* ANN_outputs; // Pointer to network outputs + + /*--- Activation function types that are currently supported ---*/ enum ENUM_ACTIVATION_FUNCTION { NONE=0, LINEAR=1, @@ -79,46 +80,169 @@ class CNeuralNetwork public: CNeuralNetwork(); ~CNeuralNetwork(){ - for(std::size_t i=0; i