diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 87291feba80e..646d07376817 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -71,7 +71,6 @@ class CConfig { unsigned short Kind_PerformanceAverageProcess; /*!< \brief Kind of mixing process.*/ unsigned short Kind_MixingPlaneInterface; /*!< \brief Kind of mixing process.*/ unsigned short Kind_SpanWise; /*!< \brief Kind of span-wise section computation.*/ - unsigned short *Kind_TurboMachinery; /*!< \brief Kind of turbomachynery architecture.*/ unsigned short iZone, nZone; /*!< \brief Number of zones in the mesh. */ unsigned short nZoneSpecified; /*!< \brief Number of zones that are specified in config file. */ su2double Highlite_Area; /*!< \brief Highlite area. */ @@ -427,6 +426,9 @@ class CConfig { CFLFineGrid, /*!< \brief CFL of the finest grid. */ Max_DeltaTime, /*!< \brief Max delta time. */ Unst_CFL; /*!< \brief Unsteady CFL number. */ + + TURBO_PERF_KIND *Kind_TurboPerf; /*!< \brief Kind of turbomachynery architecture.*/ + TURBOMACHINERY_TYPE *Kind_TurboMachinery; bool ReorientElements; /*!< \brief Flag for enabling element reorientation. */ bool AddIndNeighbor; /*!< \brief Include indirect neighbor in the agglomeration process. */ @@ -4825,7 +4827,7 @@ class CConfig { * \brief Get the kind of turbomachinery architecture. * \return Kind of turbomachinery architecture. */ - unsigned short GetKind_TurboMachinery(unsigned short val_iZone) const { return Kind_TurboMachinery[val_iZone]; } + TURBOMACHINERY_TYPE GetKind_TurboMachinery(unsigned short val_iZone) const { return Kind_TurboMachinery[val_iZone]; } /*! * \brief Get the kind of turbomachinery architecture. @@ -4962,10 +4964,10 @@ class CConfig { string GetMarker_TurboPerf_BoundOut(unsigned short index) const { return Marker_TurboBoundOut[index];} /*! - * \brief get marker kind for Turbomachinery performance calculation. + * \brief get marker kind for Turbomachinery performance calculation kind. * \return kind index. */ - unsigned short GetKind_TurboPerf(unsigned short index); + TURBO_PERF_KIND GetKind_TurboPerf(unsigned short val_iZone) const { return Kind_TurboPerf[val_iZone]; }; /*! * \brief get outlet bounds name for Turbomachinery performance calculation. diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index f5d6a61a972e..5233f8d87fc4 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -1227,8 +1227,10 @@ enum RIEMANN_TYPE { TOTAL_CONDITIONS_PT_1D = 11, STATIC_PRESSURE_1D = 12, MIXING_IN_1D = 13, - MIXING_OUT_1D =14 + MIXING_OUT_1D = 14, + MASS_FLOW_OUTLET = 15 /*!< \brief User prescribes the mass flow rate at the outlet boundary */ }; + static const MapType Riemann_Map = { MakePair("TOTAL_CONDITIONS_PT", TOTAL_CONDITIONS_PT) MakePair("DENSITY_VELOCITY", DENSITY_VELOCITY) @@ -1244,6 +1246,7 @@ static const MapType Riemann_Map = { MakePair("RADIAL_EQUILIBRIUM", RADIAL_EQUILIBRIUM) MakePair("TOTAL_CONDITIONS_PT_1D", TOTAL_CONDITIONS_PT_1D) MakePair("STATIC_PRESSURE_1D", STATIC_PRESSURE_1D) + MakePair("MASS_FLOW_OUTLET", MASS_FLOW_OUTLET) }; static const MapType Giles_Map = { @@ -1261,6 +1264,7 @@ static const MapType Giles_Map = { MakePair("RADIAL_EQUILIBRIUM", RADIAL_EQUILIBRIUM) MakePair("TOTAL_CONDITIONS_PT_1D", TOTAL_CONDITIONS_PT_1D) MakePair("STATIC_PRESSURE_1D", STATIC_PRESSURE_1D) + MakePair("MASS_FLOW_OUTLET", MASS_FLOW_OUTLET) }; /*! @@ -1308,19 +1312,33 @@ static const MapType SpanWise_Map = { /*! * \brief Types of mixing process for averaging quantities at the boundaries. */ -enum TURBOMACHINERY_TYPE { - AXIAL = 1, /*!< \brief axial turbomachinery. */ - CENTRIFUGAL = 2, /*!< \brief centrifugal turbomachinery. */ - CENTRIPETAL = 3, /*!< \brief centripetal turbomachinery. */ - CENTRIPETAL_AXIAL = 4, /*!< \brief mixed flow turbine. */ - AXIAL_CENTRIFUGAL = 5 /*!< \brief mixed flow turbine. */ +enum class TURBOMACHINERY_TYPE { + AXIAL, /*!< \brief axial turbomachinery. */ + CENTRIFUGAL, /*!< \brief centrifugal turbomachinery. */ + CENTRIPETAL, /*!< \brief centripetal turbomachinery. */ + CENTRIPETAL_AXIAL, /*!< \brief mixed flow turbine. */ + AXIAL_CENTRIFUGAL, /*!< \brief mixed flow turbine. */ }; static const MapType TurboMachinery_Map = { - MakePair("AXIAL", AXIAL) - MakePair("CENTRIFUGAL", CENTRIFUGAL) - MakePair("CENTRIPETAL", CENTRIPETAL) - MakePair("CENTRIPETAL_AXIAL", CENTRIPETAL_AXIAL) - MakePair("AXIAL_CENTRIFUGAL", AXIAL_CENTRIFUGAL) + MakePair("AXIAL", TURBOMACHINERY_TYPE::AXIAL) + MakePair("CENTRIFUGAL", TURBOMACHINERY_TYPE::CENTRIFUGAL) + MakePair("CENTRIPETAL", TURBOMACHINERY_TYPE::CENTRIPETAL) + MakePair("CENTRIPETAL_AXIAL", TURBOMACHINERY_TYPE::CENTRIPETAL_AXIAL) + MakePair("AXIAL_CENTRIFUGAL", TURBOMACHINERY_TYPE::AXIAL_CENTRIFUGAL) +}; + +/*! + * \brief Types of Turbomachinery performance Type. + */ +enum class TURBO_PERF_KIND{ + TURBINE, /*!< \brief Turbine Performance. */ + COMPRESSOR, /*!< \brief Compressor Performance. */ + PROPELLOR /*!< \brief Propellor Performance. */ +}; +static const MapType TurboPerfKind_Map = { + MakePair("TURBINE", TURBO_PERF_KIND::TURBINE) + MakePair("COMPRESSOR", TURBO_PERF_KIND::COMPRESSOR) + MakePair("PROPELLOR", TURBO_PERF_KIND::PROPELLOR) }; /*! diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 3eaed4c333f1..4294caf38051 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -1499,6 +1499,9 @@ void CConfig::SetConfig_Options() { /*!\brief TURBOMACHINERY_KIND \n DESCRIPTION: types of turbomachynery architecture. \n OPTIONS: see \link TurboMachinery_Map \endlink \n Default: AXIAL */ addEnumListOption("TURBOMACHINERY_KIND",nTurboMachineryKind, Kind_TurboMachinery, TurboMachinery_Map); + /*!\brief TURBOMACHINERY_KIND \n DESCRIPTION: types of turbomachynery Performance Calculations. + \n OPTIONS: see \link TurboPerfKind_Map \endlink \n Default: TURBINE */ + addEnumListOption("TURBO_PERF_KIND", nTurboMachineryKind, Kind_TurboPerf, TurboPerfKind_Map); /*!\brief MARKER_SHROUD \n DESCRIPTION: markers in which velocity is forced to 0.0 . * \n Format: (shroud1, shroud2, ...)*/ addStringListOption("MARKER_SHROUD", nMarker_Shroud, Marker_Shroud); diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 5bebaded5f09..e1b4f072d94c 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -5071,28 +5071,22 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, } else{ if(SpanWise_Kind == AUTOMATIC){ - /*--- loop to find inflow of outflow marker---*/ + /*--- loop to find inflow or outflow marker---*/ for (iMarker = 0; iMarker < nMarker; iMarker++){ for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){ - if (config->GetMarker_All_Turbomachinery(iMarker) != iMarkerTP) continue; - if (config->GetMarker_All_TurbomachineryFlag(iMarker) != marker_flag) continue; + if (config->GetMarker_All_TurbomachineryFlag(iMarker) != marker_flag) continue; + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); - /*--- loop to find the vertex that ar both of inflow or outflow marker and on the periodic - * in order to caount the number of Span ---*/ - for (jMarker = 0; jMarker < nMarker; jMarker++){ + /*--- loop to find the vertex that ar both of inflow or outflow marker and on the periodic + * in order to count the number of Span ---*/ + for (jMarker = 0; jMarker < nMarker; jMarker++){ if (config->GetMarker_All_KindBC(jMarker) != PERIODIC_BOUNDARY) continue; - - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (!nodes->GetDomain(iPoint)) continue; - PeriodicBoundary = config->GetMarker_All_PerBound(jMarker); jVertex = nodes->GetVertex(iPoint, jMarker); - - if ((jVertex != -1) && (PeriodicBoundary == (val_iZone + 1))){ - nSpan++; + if ((jVertex != -1) && (PeriodicBoundary == ((val_iZone) + 1)) && nodes->GetDomain(iPoint)) { + nSpan++; } } } @@ -5101,9 +5095,13 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, /*--- storing the local number of span---*/ nSpan_loc = nSpan; + + /*--- if parallel computing the global number of span---*/ +#ifdef HAVE_MPI + nSpan_max = nSpan; SU2_MPI::Allreduce(&nSpan_loc, &nSpan, 1, MPI_INT, MPI_SUM, SU2_MPI::GetComm()); SU2_MPI::Allreduce(&nSpan_loc, &nSpan_max, 1, MPI_INT, MPI_MAX, SU2_MPI::GetComm()); - +#endif /*--- initialize the vector that will contain the disordered values span-wise ---*/ nSpanWiseSections[marker_flag -1] = nSpan; valueSpan = new su2double[nSpan]; @@ -5118,33 +5116,27 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, for (iMarkerTP=1; iMarkerTP < config->GetnMarker_Turbomachinery()+1; iMarkerTP++){ if (config->GetMarker_All_Turbomachinery(iMarker) != iMarkerTP) continue; - if (config->GetMarker_All_TurbomachineryFlag(iMarker) != marker_flag) continue; - - for (jMarker = 0; jMarker < nMarker; jMarker++){ - if (config->GetMarker_All_KindBC(jMarker) != PERIODIC_BOUNDARY) continue; - - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (!nodes->GetDomain(iPoint)) continue; - - PeriodicBoundary = config->GetMarker_All_PerBound(jMarker); - jVertex = nodes->GetVertex(iPoint, jMarker); - - if ((jVertex != -1) && (PeriodicBoundary == (val_iZone + 1))){ + if (config->GetMarker_All_TurbomachineryFlag(iMarker) != marker_flag) continue; + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + for (jMarker = 0; jMarker < nMarker; jMarker++){ + if (config->GetMarker_All_KindBC(jMarker) != PERIODIC_BOUNDARY) continue; + PeriodicBoundary = config->GetMarker_All_PerBound(jMarker); + jVertex = nodes->GetVertex(iPoint, jMarker); + if ((jVertex != -1) && (PeriodicBoundary == (( val_iZone) + 1) && nodes->GetDomain(iPoint))){ coord = nodes->GetCoord(iPoint); radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]); switch (config->GetKind_TurboMachinery(val_iZone)){ - case CENTRIFUGAL: + case TURBOMACHINERY_TYPE::CENTRIFUGAL: valueSpan[nSpan_loc] = coord[2]; break; - case CENTRIPETAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL: valueSpan[nSpan_loc] = coord[2]; break; - case AXIAL: + case TURBOMACHINERY_TYPE::AXIAL: valueSpan[nSpan_loc] = radius; break; - case CENTRIPETAL_AXIAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL_AXIAL: if (marker_flag == OUTFLOW){ valueSpan[nSpan_loc] = radius; } @@ -5152,7 +5144,7 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, valueSpan[nSpan_loc] = coord[2]; } break; - case AXIAL_CENTRIFUGAL: + case TURBOMACHINERY_TYPE::AXIAL_CENTRIFUGAL: if (marker_flag == INFLOW){ valueSpan[nSpan_loc] = radius; } @@ -5214,33 +5206,25 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, if (config->GetMarker_All_Turbomachinery(iMarker) != iMarkerTP) continue; if (config->GetMarker_All_TurbomachineryFlag(iMarker) != marker_flag) continue; - - for (jMarker = 0; jMarker < nMarker; jMarker++){ - if (config->GetMarker_All_KindBC(jMarker) != PERIODIC_BOUNDARY) continue; - - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (!nodes->GetDomain(iPoint)) continue; - + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + for (jMarker = 0; jMarker < nMarker; jMarker++){ + if (config->GetMarker_All_KindBC(jMarker) != PERIODIC_BOUNDARY) continue; PeriodicBoundary = config->GetMarker_All_PerBound(jMarker); jVertex = nodes->GetVertex(iPoint, jMarker); - - if ((jVertex != -1) && (PeriodicBoundary == (val_iZone + 1))){ - + if ((jVertex != -1) && (PeriodicBoundary == ((val_iZone) + 1)) && nodes->GetDomain(iPoint)){ coord = nodes->GetCoord(iPoint); radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]); switch (config->GetKind_TurboMachinery(val_iZone)){ - case CENTRIFUGAL: - case CENTRIPETAL: + case TURBOMACHINERY_TYPE::CENTRIFUGAL: case TURBOMACHINERY_TYPE::CENTRIPETAL: if (coord[2] < min) min = coord[2]; if (coord[2] > max) max = coord[2]; break; - case AXIAL: + case TURBOMACHINERY_TYPE::AXIAL: if (radius < min) min = radius; if (radius > max) max = radius; break; - case CENTRIPETAL_AXIAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL_AXIAL: if (marker_flag == OUTFLOW){ if (radius < min) min = radius; if (radius > max) max = radius; @@ -5250,7 +5234,8 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, if (coord[2] > max) max = coord[2]; } break; - case AXIAL_CENTRIFUGAL: + + case TURBOMACHINERY_TYPE::AXIAL_CENTRIFUGAL: if (marker_flag == INFLOW){ if (radius < min) min = radius; if (radius > max) max = radius; @@ -5261,7 +5246,7 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, } break; } - } + } } } } @@ -5399,7 +5384,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone coord = nodes->GetCoord(iPoint); switch (config->GetKind_TurboMachinery(val_iZone)){ - case CENTRIFUGAL: case CENTRIPETAL: + case TURBOMACHINERY_TYPE::CENTRIFUGAL: case TURBOMACHINERY_TYPE::CENTRIPETAL: for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ if (dist > (abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]))){ dist= abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]); @@ -5407,7 +5392,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } } break; - case AXIAL: + case TURBOMACHINERY_TYPE::AXIAL: radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]); for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ if (dist > (abs(radius - SpanWiseValue[marker_flag-1][iSpan]))){ @@ -5416,7 +5401,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } } break; - case CENTRIPETAL_AXIAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL_AXIAL: if (marker_flag == OUTFLOW){ radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]); for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ @@ -5436,7 +5421,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } break; - case AXIAL_CENTRIFUGAL: + case TURBOMACHINERY_TYPE::AXIAL_CENTRIFUGAL: if (marker_flag == INFLOW){ radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]); for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ @@ -5500,7 +5485,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone coord = nodes->GetCoord(iPoint); switch (config->GetKind_TurboMachinery(val_iZone)){ - case CENTRIFUGAL: case CENTRIPETAL: + case TURBOMACHINERY_TYPE::CENTRIFUGAL: case TURBOMACHINERY_TYPE::CENTRIPETAL: for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ if (dist > (abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]))){ dist= abs(coord[2]-SpanWiseValue[marker_flag-1][iSpan]); @@ -5508,7 +5493,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } } break; - case AXIAL: + case TURBOMACHINERY_TYPE::AXIAL: radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]); for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ if (dist > (abs(radius - SpanWiseValue[marker_flag-1][iSpan]))){ @@ -5517,7 +5502,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } } break; - case CENTRIPETAL_AXIAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL_AXIAL: if(marker_flag == OUTFLOW){ radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]); for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ @@ -5536,7 +5521,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } break; - case AXIAL_CENTRIFUGAL: + case TURBOMACHINERY_TYPE::AXIAL_CENTRIFUGAL: if(marker_flag == INFLOW){ radius = sqrt(coord[0]*coord[0]+coord[1]*coord[1]); for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ @@ -5591,7 +5576,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone /*--- find nodes at minimum pitch among all nodes---*/ if (coord[1]GetKind_TurboMachinery(val_iZone) == AXIAL){ + if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == TURBOMACHINERY_TYPE::AXIAL){ MinAngularCoord[iMarker][iSpan] = coord[1]; } else{ @@ -5605,7 +5590,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone if (coord[1]GetDomain(iPoint)){ minInt = coord[1]; - if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == AXIAL){ + if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == TURBOMACHINERY_TYPE::AXIAL){ minIntAngPitch[iSpan] = coord[1]; } else{ @@ -5618,7 +5603,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone if (coord[1]>max){ if(nodes->GetDomain(iPoint)){ max =coord[1]; - if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == AXIAL){ + if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == TURBOMACHINERY_TYPE::AXIAL){ MaxAngularCoord[iMarker][iSpan] = coord[1]; } else{ @@ -5638,7 +5623,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone checkAssign[iSpan][kSpanVertex] = true; coord = nodes->GetCoord(ordered[iSpan][iSpanVertex]); target = coord[1]; - if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == AXIAL){ + if (nDim == 2 && config->GetKind_TurboMachinery(val_iZone) == TURBOMACHINERY_TYPE::AXIAL){ angPitch[iSpan][iSpanVertex]=coord[1]; } else{ @@ -5661,7 +5646,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone turbovertex[iMarker][iSpan][iInternalVertex]->SetAngularCoord(angPitch[iSpan][iSpanVertex]); turbovertex[iMarker][iSpan][iInternalVertex]->SetDeltaAngularCoord(deltaAngPitch[iSpan][iSpanVertex]); switch (config->GetKind_TurboMachinery(val_iZone)){ - case CENTRIFUGAL: + case TURBOMACHINERY_TYPE::CENTRIFUGAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if (marker_flag == INFLOW){ @@ -5674,7 +5659,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone TurboNormal[2] = 0.0; } break; - case CENTRIPETAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if (marker_flag == OUTFLOW){ @@ -5687,7 +5672,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone TurboNormal[2] = 0.0; } break; - case AXIAL: + case TURBOMACHINERY_TYPE::AXIAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if(nDim == 3){ @@ -5714,7 +5699,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } break; - case CENTRIPETAL_AXIAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL_AXIAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if (marker_flag == INFLOW){ @@ -5728,7 +5713,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } break; - case AXIAL_CENTRIFUGAL: + case TURBOMACHINERY_TYPE::AXIAL_CENTRIFUGAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if (marker_flag == INFLOW){ @@ -6015,7 +6000,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone myfile.width(20); myfile << y_loc[iSpan][iSpanVertex]; myfile.width(20); myfile << z_loc[iSpan][iSpanVertex]; myfile.width(20); myfile << radius; - if (nDim ==2 && config->GetKind_TurboMachinery(val_iZone)){ + if (nDim ==2 && config->GetBoolTurbomachinery()){ myfile.width(20); myfile << angCoord_loc[iSpan][iSpanVertex]; myfile.width(20); myfile << deltaAngCoord_loc[iSpan][iSpanVertex]; } @@ -6084,7 +6069,7 @@ void CPhysicalGeometry::UpdateTurboVertex(CConfig *config, unsigned short val_iZ coord = nodes->GetCoord(iPoint); /*--- compute appropriate turbo normal ---*/ switch (config->GetKind_TurboMachinery(val_iZone)){ - case CENTRIFUGAL: + case TURBOMACHINERY_TYPE::CENTRIFUGAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if (marker_flag == INFLOW){ @@ -6097,7 +6082,7 @@ void CPhysicalGeometry::UpdateTurboVertex(CConfig *config, unsigned short val_iZ TurboNormal[2] = 0.0; } break; - case CENTRIPETAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if (marker_flag == OUTFLOW){ @@ -6110,7 +6095,7 @@ void CPhysicalGeometry::UpdateTurboVertex(CConfig *config, unsigned short val_iZ TurboNormal[2] = 0.0; } break; - case AXIAL: + case TURBOMACHINERY_TYPE::AXIAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if(nDim == 3){ @@ -6137,7 +6122,7 @@ void CPhysicalGeometry::UpdateTurboVertex(CConfig *config, unsigned short val_iZ } break; - case CENTRIPETAL_AXIAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL_AXIAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if (marker_flag == INFLOW){ @@ -6151,7 +6136,7 @@ void CPhysicalGeometry::UpdateTurboVertex(CConfig *config, unsigned short val_iZ } break; - case AXIAL_CENTRIFUGAL: + case TURBOMACHINERY_TYPE::AXIAL_CENTRIFUGAL: Normal2 = 0.0; for(iDim = 0; iDim < 2; iDim++) Normal2 +=coord[iDim]*coord[iDim]; if (marker_flag == INFLOW){ @@ -6328,7 +6313,7 @@ void CPhysicalGeometry::SetAvgTurboValue(CConfig *config, unsigned short val_iZo AverageGridVel[iMarker][iSpan][iDim] =TotalGridVel[iDim]/nTotVertexSpan[iMarker][iSpan]; } switch (config->GetKind_TurboMachinery(val_iZone)){ - case CENTRIFUGAL:case CENTRIPETAL: + case TURBOMACHINERY_TYPE::CENTRIFUGAL:case TURBOMACHINERY_TYPE::CENTRIPETAL: if (marker_flag == INFLOW ){ AverageTangGridVel[iMarker][iSpan]= -(AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]); } @@ -6336,7 +6321,7 @@ void CPhysicalGeometry::SetAvgTurboValue(CConfig *config, unsigned short val_iZo AverageTangGridVel[iMarker][iSpan]= AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]; } break; - case AXIAL: + case TURBOMACHINERY_TYPE::AXIAL: if (marker_flag == INFLOW && nDim == 2){ AverageTangGridVel[iMarker][iSpan]= -AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1] + AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]; } @@ -6344,7 +6329,7 @@ void CPhysicalGeometry::SetAvgTurboValue(CConfig *config, unsigned short val_iZo AverageTangGridVel[iMarker][iSpan]= AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]; } break; - case CENTRIPETAL_AXIAL: + case TURBOMACHINERY_TYPE::CENTRIPETAL_AXIAL: if (marker_flag == OUTFLOW){ AverageTangGridVel[iMarker][iSpan]= (AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]); } @@ -6352,7 +6337,7 @@ void CPhysicalGeometry::SetAvgTurboValue(CConfig *config, unsigned short val_iZo AverageTangGridVel[iMarker][iSpan]= -(AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]); } break; - case AXIAL_CENTRIFUGAL: + case TURBOMACHINERY_TYPE::AXIAL_CENTRIFUGAL: if (marker_flag == INFLOW) { AverageTangGridVel[iMarker][iSpan]= AverageTurboNormal[iMarker][iSpan][0]*AverageGridVel[iMarker][iSpan][1]-AverageTurboNormal[iMarker][iSpan][1]*AverageGridVel[iMarker][iSpan][0]; @@ -6583,7 +6568,7 @@ void CPhysicalGeometry::GatherInOutAverageValues(CConfig *config, bool allocate) if (iSpan == nSpanWiseSections) { config->SetFreeStreamTurboNormal(turboNormal); - if (config->GetKind_TurboMachinery(config->GetiZone()) == AXIAL && nDim == 2){ + if (config->GetKind_TurboMachinery(config->GetiZone()) == TURBOMACHINERY_TYPE::AXIAL && nDim == 2){ nBlades = 1/Pitch; } else{ diff --git a/SU2_CFD/include/iteration/CFluidIteration.hpp b/SU2_CFD/include/iteration/CFluidIteration.hpp index 72979a1804f9..1e471472d7a3 100644 --- a/SU2_CFD/include/iteration/CFluidIteration.hpp +++ b/SU2_CFD/include/iteration/CFluidIteration.hpp @@ -106,6 +106,21 @@ class CFluidIteration : public CIteration { CVolumetricMovement*** grid_movement, CFreeFormDefBox*** FFDBox, unsigned short val_iZone, unsigned short val_iInst) override; + /*! + * \brief Monitors turbo computation (pressure and turbo ramps). + */ + void TurboMonitor(CGeometry**** geometry_container, CConfig** config_container, unsigned long ExtIter) override; + + /*! + * \brief Monitors turbo computation (pressure and turbo ramps). + */ + void ComputeTurboPerformance(CSolver***** solver, CGeometry**** geometry_container, CConfig** config_container, unsigned long ExtIter) override; + + /*! + * \brief Monitors turbo computation (pressure and turbo ramps). + */ + //void InitTurboPerformance(CGeometry *geometry, CConfig *config, CFluidModel *fluid) override; + /*! * \brief Postprocesses the fluid system before heading to another physics system or the next iteration. * \param[in] solver - Container vector with all the solutions. diff --git a/SU2_CFD/include/iteration/CIteration.hpp b/SU2_CFD/include/iteration/CIteration.hpp index 7ccdffc45d4f..3a285417fc96 100644 --- a/SU2_CFD/include/iteration/CIteration.hpp +++ b/SU2_CFD/include/iteration/CIteration.hpp @@ -58,6 +58,9 @@ class CIteration { su2double StartTime{0.0}, /*!< \brief Tracking wall time. */ StopTime{0.0}, UsedTime{0.0}; + std::shared_ptr TurbomachineryPerformance; /*!< \brief turbo performance calculator. */ + CTurbomachineryStagePerformance* TurbomachineryStagePerformance; /*!< \brief turbo stage performance calculator. */ + public: /*! * \brief Constructor of the class. @@ -247,6 +250,21 @@ class CIteration { return false; } + /*! + * \brief Monitors turbo computation (pressure and turbo ramps). + */ + virtual void TurboMonitor(CGeometry**** geometry_container, CConfig** config_container, unsigned long ExtIter) {}; + + /*! + * \brief Monitors turbo computation (pressure and turbo ramps). + */ + virtual void ComputeTurboPerformance(CSolver***** solver, CGeometry**** geometry_container, CConfig** config_container, unsigned long ExtIter) {}; + + /*! + * \brief Monitors turbo computation (pressure and turbo ramps). + */ + virtual void InitTurboPerformance(CGeometry *geometry, CConfig *config, CFluidModel *fluid) {}; + /*! * \brief A virtual member. * \param[in] output - Pointer to the COutput class. diff --git a/SU2_CFD/include/iteration/CTurboIteration.hpp b/SU2_CFD/include/iteration/CTurboIteration.hpp index 75e9d737ca53..9c3d358b8bf0 100644 --- a/SU2_CFD/include/iteration/CTurboIteration.hpp +++ b/SU2_CFD/include/iteration/CTurboIteration.hpp @@ -62,4 +62,9 @@ class CTurboIteration : public CFluidIteration { CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, CVolumetricMovement*** grid_movement, CFreeFormDefBox*** FFDBox, unsigned short val_iZone, unsigned short val_iInst) override; + + /*! + * \brief Monitors turbo computation (pressure and turbo ramps). + */ + void InitTurboPerformance(CGeometry *geometry, CConfig *config, CFluidModel *fluid) override; }; diff --git a/SU2_CFD/include/iteration_structure.hpp b/SU2_CFD/include/iteration_structure.hpp new file mode 100644 index 000000000000..705d59bac6de --- /dev/null +++ b/SU2_CFD/include/iteration_structure.hpp @@ -0,0 +1,1807 @@ +/*! + * \file iteration_structure.hpp + * \brief Headers of the iteration classes used by SU2_CFD. + * Each CIteration class represents an available physics package. + * \author F. Palacios, T. Economon + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, 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 "../../Common/include/mpi_structure.hpp" +#include "../../Common/include/geometry/CGeometry.hpp" +#include "../../Common/include/grid_movement_structure.hpp" +#include "output/COutput.hpp" +#include "../../Common/include/CConfig.hpp" +#include "../include/integration/CIntegration.hpp" + +using namespace std; + +/*! + * \class CIteration + * \brief Parent class for defining a single iteration of a physics problem. + * \author T. Economon + */ +class CIteration { +protected: + int rank, /*!< \brief MPI Rank. */ + size; /*!< \brief MPI Size. */ + unsigned short nZone; /*!< \brief Total number of zones in the problem. */ + unsigned short nInst; /*!< \brief Total number of instances in the problem. */ + + bool multizone, /*!< \brief Flag for multizone problems. */ + singlezone; /*!< \brief Flag for singlezone problems. */ + + su2double StartTime, /*!< \brief Tracking wall time. */ + StopTime, + UsedTime; + +public: + + /*! + * \brief Constructor of the class. + */ + CIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + virtual ~CIteration(void); + + /*! + * \brief Updates the positions and grid velocities for dynamic meshes between physical time steps. + * \author T. Economon + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] IntIter - Current sudo time iteration number. + * \param[in] ExtIter - Current physical time iteration number. + */ + virtual void SetGrid_Movement(CGeometry **geometry, CSurfaceMovement *surface_movement, + CVolumetricMovement *grid_movement, + CSolver ***solver, CConfig *config, unsigned long IntIter, unsigned long TimeIter); + /*! + * \brief Run the mesh deformation algorithms. + * \author R. Sanchez + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] kind_recording - Current kind of recording. + */ + void SetMesh_Deformation(CGeometry **geometry, + CSolver **solver_container, + CNumerics ***numerics_container, + CConfig *config_container, + unsigned short kind_recording); + + /*! + * \brief A virtual member. + * \param[in] ??? - Description here. + */ + virtual void Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief A virtual member. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + virtual void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief A virtual member. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + virtual void Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief A virtual member. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + virtual void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief A virtual member. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + virtual void Predictor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief A virtual member. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + virtual void Relaxation(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief A virtual member. + * \param[in] ??? - Description here. + */ + virtual bool Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief A virtual member. + * \param[in] ??? - Description here. + */ + void Output(COutput *output, + CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned long InnerIter, + bool StopCalc, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief A virtual member. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + virtual void Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + virtual void InitializeAdjoint(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short iZone, + unsigned short iInst){} + + virtual void InitializeAdjoint_CrossTerm(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short iZone, + unsigned short iInst){} + + virtual void RegisterInput(CSolver *****solver, + CGeometry ****geometry, + CConfig** config, + unsigned short iZone, + unsigned short iInst, + unsigned short kind_recording){} + + virtual void SetDependencies(CSolver *****solver, + CGeometry ****geometry, + CNumerics ******numerics, + CConfig **config, + unsigned short iZone, + unsigned short iInst, + unsigned short kind_recording){} + + virtual void RegisterOutput(CSolver *****solver, + CGeometry ****geometry, + CConfig** config, + COutput* output, + unsigned short iZone, + unsigned short iInst){} + + virtual void LoadUnsteady_Solution(CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + int val_DirectIter){} + + virtual void LoadDynamic_Solution(CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + int val_DirectIter){} + + virtual void SetRecording(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording) { } + +}; + + +/*! + * \class CFluidIteration + * \brief Class for driving an iteration of the fluid system. + * \author T. Economon + */ +class CFluidIteration : public CIteration { +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CFluidIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CFluidIteration(void); + + /*! + * \brief Preprocessing to prepare for an iteration of the physics. + * \param[in] ??? - Description here. + */ + virtual void Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Perform a single iteration of the fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + virtual void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Iterate the fluid system for a number of Inner_Iter iterations. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + virtual void Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Updates the containers for the fluid system. + * \param[in] ??? - Description here. + */ + virtual void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Monitors the convergence and other metrics for the fluid system. + * \param[in] ??? - Description here. + */ + virtual bool Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Postprocesses the fluid system before heading to another physics system or the next iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + virtual void Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Imposes a gust via the grid velocities. + * \author S. Padron + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + */ + void SetWind_GustField(CConfig *config, CGeometry **geometry, CSolver ***solver); + + /*! + * \brief Reads and initializes the vortex positions, strengths and gradient. + * \author S. Padron + * \param[in] nVortex - number of vortices. + * \param[in] x0 - Vector of x-loc of the vortices. + * \param[in] y0 - Vector of y-loc of the vortices. + * \param[in] vort_strength - Vector of vortex strengths. + * \param[in] r_core - Vector of vortex core size. + */ + void InitializeVortexDistribution(unsigned long &nVortex, vector& x0, vector& y0, vector& vort_strength, vector& r_core); + + + /*! + * \brief Fixed CL monitoring function + * \author J. Mukhopadhaya + * \param[in] output - Pointer to the COutput class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Pointer to the flow solver + * \param[in] config - Definition of the particular problem. + * \return Boolean indicating weather calculation should be stopped + */ + bool MonitorFixed_CL(COutput *output, CGeometry *geometry, CSolver **solver, CConfig *config); +}; + +/*! + * \class CFEMFluidIteration + * \brief Class for driving an iteration of the finite element flow system. + * \author T. Economon, E. van der Weide + * \version 7.0.2 "Blackbird" + */ +class CFEMFluidIteration : public CFluidIteration { +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CFEMFluidIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CFEMFluidIteration(void); + + /*! + * \brief Preprocessing to prepare for an iteration of the physics. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + void Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + /*! + * \brief Perform a single iteration of the finite element flow system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Updates the containers for the finite element flow system. + * \param[in] ??? - Description here. + */ + void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Postprocess routine for the finite element flow system. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); +}; + +/*! + * \class CHeatIteration + * \brief Class for driving an iteration of the heat system. + * \author T. Economon + */ +class CHeatIteration : public CFluidIteration { + +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CHeatIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CHeatIteration(void); + + /*! + * \brief Perform a single iteration of the heat system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Iterate the heat system for a number of Inner_Iter iterations. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + void Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Updates the containers for the heat system. + * \param[in] ??? - Description here. + */ + void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); +}; + +/*! + * \class CFEAIteration + * \brief Class for driving an iteration of structural analysis. + * \author R. Sanchez + * \version 7.0.2 "Blackbird" + */ +class CFEAIteration : public CIteration { +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CFEAIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CFEAIteration(void); + + /*! + * \brief Preprocessing to prepare for an iteration of the physics. + * \param[in] ??? - Description here. + */ + void Preprocess(); + using CIteration::Preprocess; + + + /*! + * \brief Perform a single iteration for structural analysis using the Finite Element Method. + * \author R. Sanchez. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Iterate the structural system for a number of Inner_Iter iterations. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - zone of the problem. + */ + void Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Updates the containers for the FEM system. + * \param[in] ??? - Description here. + */ + void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Predictor. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + void Predictor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Relaxation. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + void Relaxation(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Monitors the convergence and other metrics for the FEM system. + * \param[in] ??? - Description here. + */ + bool Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Postprocess ???. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + +}; + +/*! + * \class CAdjFluidIteration + * \brief Class for driving an iteration of the adjoint fluid system. + * \author T. Economon + */ +class CAdjFluidIteration : public CFluidIteration { +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CAdjFluidIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CAdjFluidIteration(void); + + /*! + * \brief Preprocessing to prepare for an iteration of the physics. + * \param[in] ??? - Description here. + */ + void Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Perform a single iteration of the adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + */ + void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Updates the containers for the adjoint fluid system. + * \param[in] ??? - Description here. + */ + void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + + +}; + +/*! + * \class CDiscAdjFluidIteration + * \brief Class for driving an iteration of the discrete adjoint fluid system. + * \author T. Economon + */ +class CDiscAdjFluidIteration : public CIteration { + +private: + + CFluidIteration* meanflow_iteration; /*!< \brief Pointer to the mean flow iteration class. */ + unsigned short CurrentRecording; /*!< \brief Stores the current status of the recording. */ + bool turbulent; /*!< \brief Stores the turbulent flag. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CDiscAdjFluidIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CDiscAdjFluidIteration(void); + + /*! + * \brief Preprocessing to prepare for an iteration of the physics. + * \brief Perform a single iteration of the adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance + */ + void Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Perform a single iteration of the adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance + */ + void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + + /*! + * \brief Updates the containers for the discrete adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance + */ + void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Monitors the convergence and other metrics for the discrete adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance + */ + bool Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Postprocess the discrete adjoint fluid iteration. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + */ + void Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Registers all input variables of the fluid iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the instance. + */ + void InitializeAdjoint(CSolver *****solver, + CGeometry ****geometry, + CConfig** config, + unsigned short iZone, + unsigned short iInst); + + /*! + * \brief Registers all output variables of the fluid iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the instance. + * \param[in] kind_recording - Kind of recording, either FLOW_CONS_VARS or MESH_COORDS + */ + void RegisterInput(CSolver *****solver, + CGeometry ****geometry, + CConfig** config, + unsigned short iZone, + unsigned short iInst, + unsigned short kind_recording); + + /*! + * \brief Initializes the adjoints of the output variables of the fluid iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the instance. + */ + void RegisterOutput(CSolver *****solver, + CGeometry ****geometry, + CConfig** config, + COutput* output, + unsigned short iZone, + unsigned short iInst); + + /*! + * \brief Initializes the adjoints of the output variables of the meanflow iteration - without the contribution of the objective function + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the instance. + */ + void InitializeAdjoint_CrossTerm(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst); + + /*! + * \brief Record a single iteration of the direct mean flow system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + * \param[in] kind_recording - The kind of recording (geometry or flow). + */ + void SetRecording(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording); + + /*! + * \brief Record a single iteration of the direct mean flow system. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + * \param[in] kind_recording - The kind of recording (geometry or flow). + */ + + void SetRecording(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording); + + /*! + * \brief Compute necessary variables that depend on the conservative variables or the mesh node positions + * (e.g. turbulent variables, normals, volumes). + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the zone. + * \param[in] kind_recording - The kind of recording (geometry or flow). + */ + void SetDependencies(CSolver *****solver, + CGeometry ****geometry, + CNumerics ******numerics, + CConfig **config, + unsigned short iZone, + unsigned short iInst, + unsigned short kind_recording); + + /*! + * \brief load unsteady solution for unsteady problems + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + * \param[in] val_DirectIter - Direct iteration to load. + */ + void LoadUnsteady_Solution(CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + int val_DirectIter); + + + +}; + +/*! + * \class CDiscAdjFEAIteration + * \brief Class for driving an iteration of the discrete adjoint FEM system. + * \author R. Sanchez + */ +class CDiscAdjFEAIteration : public CIteration { + +private: + + CFEAIteration* fem_iteration; /*!< \brief Pointer to the primal iteration class. */ + unsigned short CurrentRecording; /*!< \brief Stores the current status of the recording. */ + + +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CDiscAdjFEAIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CDiscAdjFEAIteration(void); + + /*! + * \brief Preprocessing to prepare for an iteration of the physics. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + */ + void Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Perform a single iteration of the adjoint mean flow system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + */ + void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Updates the containers for the discrete adjoint mean flow system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + */ + void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Monitors the convergence and other metrics for the discrete adjoint mean flow system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + */ + bool Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Postprocesses the discrete adjoint mean flow system before heading to another physics system or the next iteration. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + */ + void Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Registers all input variables of the FEM iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] kind_recording - Kind of recording, either FEM_VARIABLES or MESH_COORDS + */ + void RegisterInput(CSolver *****solver, CGeometry ****geometry, CConfig** config, unsigned short iZone, unsigned short iInst, unsigned short kind_recording); + + /*! + * \brief Registers all output variables of the FEM iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the zone. + */ + void RegisterOutput(CSolver *****solver, CGeometry ****geometry, CConfig** config, unsigned short iZone, unsigned short iInst); + using CIteration::RegisterOutput; + + /*! + * \brief Initializes the adjoints of the output variables of the FEM iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the zone. + */ + void InitializeAdjoint(CSolver *****solver, CGeometry ****geometry, CConfig** config, unsigned short iZone, unsigned short iInst); + + /*! + * \brief Initializes the adjoints of the output variables of the FEM iteration - without the contribution of the objective function + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the zone. + */ + void InitializeAdjoint_CrossTerm(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst); + + /*! + * \brief Record a single iteration of the direct FEM system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + * \param[in] kind_recording - The kind of recording (geometry or flow). + */ + void SetRecording(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording); + + /*! + * \brief Record a single iteration of the direct FEM system. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + * \param[in] kind_recording - The kind of recording (geometry or flow). + */ + + void SetRecording(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording); + + /*! + * \brief Compute necessary variables that depend on the variables in the numerics (E, Nu...) + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] iInst - Index of the zone. + * \param[in] kind_recording - The kind of recording (geometry or flow). + */ + void SetDependencies(CSolver *****solver, + CGeometry ****geometry, + CNumerics ******numerics, + CConfig **config, + unsigned short iZone, + unsigned short iInst, + unsigned short kind_recording); + + /*! + * \brief load solution for dynamic problems + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance. + * \param[in] val_DirectIter - Direct iteration to load. + */ + void LoadDynamic_Solution(CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + int val_DirectIter); + +}; + +/*! + * \class CDiscAdjHeatIteration + * \brief Class for driving an iteration of the discrete adjoint heat equation. + * \author O. Burghardt + */ +class CDiscAdjHeatIteration : public CIteration { + +private: + + CHeatIteration* mean_iteration; /*!< \brief Pointer to the mean flow iteration class. */ + unsigned short CurrentRecording; /*!< \brief Stores the current status of the recording. */ + +public: + + /*! + * \brief Constructor of the class. + * \param[in] config - Definition of the particular problem. + */ + CDiscAdjHeatIteration(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CDiscAdjHeatIteration(void); + + /*! + * \brief Perform a single iteration of the adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + */ + void Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Perform a single iteration of the adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + */ + void Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Perform a single iteration of the adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + */ + void Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, unsigned short val_iInst); + + /*! + * \brief Monitors the convergence and other metrics for the discrete adjoint fluid system. + */ + bool Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst); + + /*! + * \brief Outputs desired files and quantities for the discrete adjoint fluid system. + */ + void Output(COutput *output, + CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned long InnerIter, + bool StopCalc, + unsigned short val_iZone, + unsigned short val_iInst); + + + /*! + * \brief Perform a single iteration of the adjoint fluid system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + */ + void Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, unsigned short val_iInst); + + /*! + * \brief Registers all input variables of the fluid iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + */ + void InitializeAdjoint(CSolver *****solver, + CGeometry ****geometry, + CConfig** config, + unsigned short iZone, unsigned short iInst); + + /*! + * \brief Registers all output variables of the fluid iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + * \param[in] kind_recording - Kind of recording. + */ + void RegisterInput(CSolver *****solver, + CGeometry ****geometry, + CConfig** config, + unsigned short iZone, unsigned short iInst, + unsigned short kind_recording); + + /*! + * \brief Initializes the adjoints of the output variables of the fluid iteration. + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + */ + void RegisterOutput(CSolver *****solver, + CGeometry ****geometry, + CConfig** config, + COutput* output, + unsigned short iZone, unsigned short iInst); + + /*! + * \brief Record a single iteration of the direct heat system. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. + * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] kind_recording - The kind of recording. + */ + void SetRecording(COutput *output, + CIntegration ***integration, + CGeometry ***geometry, + CSolver ****solver, + CNumerics *****numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short kind_recording); + + /*! + * \brief Record a single iteration of the direct heat system. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iZone - Index of the instance. + * \param[in] kind_recording - The kind of recording (geometry or flow). + */ + + void SetRecording(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording) { } + + /*! + * \brief Compute necessary variables that depend on the conservative variables or the mesh node positions + * (e.g. turbulent variables, normals, volumes). + * \param[in] solver - Container vector with all the solutions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + * \param[in] kind_recording - The kind of recording. + */ + void SetDependencies(CSolver *****solver, + CGeometry ****geometry, + CNumerics ******numerics, + CConfig **config, + unsigned short iZone, unsigned short iInst, + unsigned short kind_recording); + + /*! + * \brief load unsteady solution for unsteady problems + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. + * \param[in] val_DirectIter - Direct iteration to load. + */ + void LoadUnsteady_Solution(CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + int val_DirectIter); +}; diff --git a/SU2_CFD/include/objectives/turbomachinery/CTurbomachineryPerformance.hpp b/SU2_CFD/include/objectives/turbomachinery/CTurbomachineryPerformance.hpp new file mode 100644 index 000000000000..3e9ec4ff7697 --- /dev/null +++ b/SU2_CFD/include/objectives/turbomachinery/CTurbomachineryPerformance.hpp @@ -0,0 +1,262 @@ +/*! + * \file CTurbomachineryPerformance.hpp + * \brief Headers of the Turbomachinery Performance class. + * \author S. Vitale, N. Anand + * \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-2019, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + + +#pragma once + +#include +#include +#include +#include +#include +#include "../../../../Common/include/geometry/CGeometry.hpp" +#include "../../../../Common/include/CConfig.hpp" +#include "../../fluid/CFluidModel.hpp" + + +class CTurbomachineryPrimitiveState { + private: + su2double Density, Pressure, TangVelocity; + vector Velocity; + public: + CTurbomachineryPrimitiveState(); + + CTurbomachineryPrimitiveState(vector TurboPrimitives, + unsigned short nDim, + su2double tangVel); + + su2double GetDensity() const & { return Density; } + + su2double GetPressure() const & { return Pressure; } + + su2double GetTangVelocity() const & { return TangVelocity; } + + vector GetVelocity() const & { return Velocity; } + +}; + +class CTurbomachineryCombinedPrimitiveStates { + private: + CTurbomachineryPrimitiveState InletPrimitiveState; + CTurbomachineryPrimitiveState OutletPrimitiveState; + public: + + CTurbomachineryCombinedPrimitiveStates(const CTurbomachineryPrimitiveState &inletPrimitiveState, + const CTurbomachineryPrimitiveState &outletPrimitiveState); + + CTurbomachineryPrimitiveState GetInletPrimitiveState() const & { return InletPrimitiveState; } + + CTurbomachineryPrimitiveState GetOutletPrimitiveState() const & { return OutletPrimitiveState; } +}; + +class CTurbomachineryState { + private: + su2double Density, Pressure, Entropy, Enthalpy, Temperature, TotalTemperature, TotalPressure, TotalEnthalpy; + su2double AbsFlowAngle, FlowAngle, MassFlow, Rothalpy, TotalRelPressure; + vector Velocity, RelVelocity, Mach, RelMach; + su2double Area, Radius; + + + public: + CTurbomachineryState(); + + CTurbomachineryState(unsigned short nDim, su2double area, su2double radius); + + void ComputeState(CFluidModel& fluidModel, const CTurbomachineryPrimitiveState &primitiveState); + + su2double GetDensity() const { return Density; } + + su2double GetPressure() const { return Pressure; } + + su2double GetEntropy() const { return Entropy; } + + su2double GetEnthalpy() const { return Enthalpy; } + + su2double GetTemperature() const { return Temperature; } + + su2double GetTotalTemperature() const { return TotalTemperature; } + + su2double GetTotalPressure() const { return TotalPressure; } + + su2double GetTotalRelPressure() const { return TotalRelPressure; } + + su2double GetTotalEnthalpy() const { return TotalEnthalpy; } + + su2double GetAbsFlowAngle() const { return AbsFlowAngle; } + + su2double GetFlowAngle() const { return FlowAngle; } + + su2double GetMassFlow() const { return MassFlow; } + + su2double GetRothalpy() const { return Rothalpy; } + + vector GetVelocity() const { return Velocity; } + + vector GetMach() const { return Mach; } + + su2double GetVelocityValue() const { + return Norm(Velocity); + } + + su2double GetMachValue() const { + return Norm(Mach); + } + + su2double GetRelVelocityValue() const { + return Norm(RelVelocity); + } + + su2double GetRelMachValue() const { + return Norm(RelMach); + } + + su2double Norm(vector const& u) const { + su2double accum = 0.; + for (int i = 0; i < u.size(); ++i) { + accum += u[i] * u[i]; + } + return sqrt(accum); + } +}; + + +class CTurbomachineryBladePerformance { + protected: + CTurbomachineryState InletState; + CTurbomachineryState OutletState; + su2double KineticEnergyLoss, TotalPressureLoss, EntropyGen, PressureRatio, EulerianWork; + CFluidModel &FluidModel; + + public: + CTurbomachineryBladePerformance(CFluidModel& fluidModel, + unsigned short nDim, + su2double areaIn, + su2double radiusIn, + su2double areaOut, + su2double radiusOut); + + virtual void ComputePerformance(const CTurbomachineryCombinedPrimitiveStates &primitives) {}; + + const CTurbomachineryState& GetInletState() { return InletState; } + + const CTurbomachineryState& GetOutletState() { return OutletState; } + + su2double GetKineticEnergyLoss() const { return KineticEnergyLoss; } + + su2double GetTotalPressureLoss() const { return TotalPressureLoss; } + + su2double GetEntropyGen() const { return EntropyGen; } + + su2double GetPressureRatio() const { return PressureRatio; } + + su2double GetEulerianWork() const { return EulerianWork; } + +}; + +class CTurbineBladePerformance : public CTurbomachineryBladePerformance { + + public: + CTurbineBladePerformance(CFluidModel& fluidModel, + unsigned short nDim, + su2double areaIn, + su2double radiusIn, + su2double areaOut, + su2double radiusOut); + + void ComputePerformance(const CTurbomachineryCombinedPrimitiveStates &primitives) override; + +}; + +class CCompressorBladePerformance : public CTurbomachineryBladePerformance { + + public: + CCompressorBladePerformance(CFluidModel& fluidModel, + unsigned short nDim, + su2double areaIn, + su2double radiusIn, + su2double areaOut, + su2double radiusOut); + + void ComputePerformance(const CTurbomachineryCombinedPrimitiveStates &primitives) override; + +}; + +class CPropellorBladePerformance : public CTurbomachineryBladePerformance { + + public: + CPropellorBladePerformance(CFluidModel& fluidModel, + unsigned short nDim, + su2double areaIn, + su2double radiusIn, + su2double areaOut, + su2double radiusOut); + + void ComputePerformance(const CTurbomachineryCombinedPrimitiveStates &primitives) override; + +}; + +class CTurbomachineryStagePerformance { + protected: + su2double TotalStaticEfficiency, TotalTotalEfficiency, NormEntropyGen, TotalStaticPressureRatio, TotalTotalPressureRatio, EulerianWork; + CFluidModel &fluidModel; + public: + CTurbomachineryStagePerformance(CFluidModel& fluid); + virtual ~CTurbomachineryStagePerformance() = default; + virtual void ComputePerformanceStage(CTurbomachineryState InState, CTurbomachineryState OutState, const CConfig* config); + virtual void ComputeTurbineStagePerformance(CTurbomachineryState InState, CTurbomachineryState OutState); + virtual void ComputeCompressorStagePerformance(CTurbomachineryState InState, CTurbomachineryState OutState); + su2double GetTotalStaticEfficiency() const { return TotalStaticEfficiency; } + su2double GetTotalTotalEfficiency() const { return TotalTotalEfficiency; } + su2double GetEulerianWork() const { return EulerianWork; } + su2double GetNormEntropyGen() const { return NormEntropyGen; } + su2double GetTotalStaticPressureRatio() const { return TotalStaticPressureRatio; } + su2double GetTotalTotalPressureRatio() const { return TotalTotalPressureRatio; } +}; + +class CTurbomachineryPerformance { + private: + vector >> + BladesPerformances; + + static void ComputePerBlade(vector > const bladePerformances, + vector const bladePrimitives); + + static void ComputePerSpan(shared_ptr const spanPerformances, + const CTurbomachineryCombinedPrimitiveStates &spanPrimitives); + // vector> StagePerformances; + // shared_ptr MachinePerformances; + public: + CTurbomachineryPerformance(const CConfig& config, const CGeometry& geometry, CFluidModel& fluidModel); + + vector >> + + GetBladesPerformances() const { return BladesPerformances; } + + // vector> GetStagePerformances() const { return StagePerformances; } + // shared_ptr GetMachinePerformances() const { return MachinePerformances; } + void ComputeTurbomachineryPerformance(vector > const primitives); +}; diff --git a/SU2_CFD/include/output/COutput.hpp b/SU2_CFD/include/output/COutput.hpp index 403b614fc3ec..b22b9dd0f967 100644 --- a/SU2_CFD/include/output/COutput.hpp +++ b/SU2_CFD/include/output/COutput.hpp @@ -38,6 +38,7 @@ #include "../../../Common/include/toolboxes/printing_toolbox.hpp" #include "tools/CWindowingTools.hpp" #include "../../../Common/include/option_structure.hpp" +#include "../../include/objectives/turbomachinery/CTurbomachineryPerformance.hpp" class CGeometry; class CSolver; @@ -294,6 +295,22 @@ class COutput { void SetHistory_Output(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned long TimeIter, unsigned long OuterIter, unsigned long InnerIter); + /*! + * \brief Collects Turbomachinery Performance data from the solvers and prints the data in tabular format on screen. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + * \param[in] TimeIter - Value of the time iteration index + * \param[in] OuterIter - Value of outer iteration index + * \param[in] InnerIter - Value of the inner iteration index + */ + void SetTurboPerformance_Output(std::shared_ptr TurboPerf, CConfig *config, + unsigned long TimeIter, unsigned long OuterIter, unsigned long InnerIter, unsigned short val_iZone); + + void SetTurboMultiZonePerformance_Output(CTurbomachineryStagePerformance* TurboStagePerf, + std::shared_ptr TurboPerf, + CConfig *config); + /*! * \brief Collects history data from the solvers and monitors the convergence. Does not write to screen or file. * \param[in] geometry - Geometrical definition of the problem. diff --git a/SU2_CFD/include/solvers/CEulerSolver.hpp b/SU2_CFD/include/solvers/CEulerSolver.hpp index d4a91b3d9838..f0c347fe9f76 100644 --- a/SU2_CFD/include/solvers/CEulerSolver.hpp +++ b/SU2_CFD/include/solvers/CEulerSolver.hpp @@ -107,6 +107,8 @@ class CEulerSolver : public CFVMFlowSolverBase TurbomachineryPerformance; /*!< \brief turbo performance calculator. */ + vector FluidModel; /*!< \brief fluid model used in the solver. */ /*--- Turbomachinery Solver Variables ---*/ @@ -130,6 +132,7 @@ class CEulerSolver : public CFVMFlowSolverBase AverageMassFlowRate; /*!< \brief Integral value of mass flow rate computed over each boundary */ su2activematrix DensityIn; su2activematrix PressureIn; @@ -1084,6 +1087,35 @@ class CEulerSolver : public CFVMFlowSolverBase GetTurboPrimitive(unsigned short iBlade, unsigned short iSpan, bool INLET) { + TurboPrimitive.clear(); + if (INLET) { + TurboPrimitive.push_back(DensityIn[iBlade][iSpan]); TurboPrimitive.push_back(PressureIn[iBlade][iSpan]); + TurboPrimitive.push_back(TurboVelocityIn[iBlade][iSpan][0]);TurboPrimitive.push_back(TurboVelocityIn[iBlade][iSpan][1]); + if (nDim==3) + TurboPrimitive.push_back(TurboVelocityIn[iBlade][iSpan][2]); + } + else { + TurboPrimitive.push_back(DensityOut[iBlade][iSpan]); TurboPrimitive.push_back(PressureOut[iBlade][iSpan]); + TurboPrimitive.push_back(TurboVelocityOut[iBlade][iSpan][0]);TurboPrimitive.push_back(TurboVelocityOut[iBlade][iSpan][1]); + if (nDim==3) + TurboPrimitive.push_back(TurboVelocityOut[iBlade][iSpan][2]); + } + return TurboPrimitive; + } + /*! * \brief Set the solution using the Freestream values. * \param[in] config - Definition of the particular problem. @@ -1136,6 +1168,13 @@ class CEulerSolver : public CFVMFlowSolverBaseval_marker. + */ + inline su2double GetAverageMassFlowRate(unsigned short valMarker) const final { + return AverageMassFlowRate[valMarker]; + } + /*! * \brief Provide the average pressure at the boundary of interest. * \param[in] val_marker - bound marker. @@ -1349,6 +1397,12 @@ class CEulerSolver : public CFVMFlowSolverBase GetTurbomachineryPerformance() const {return TurbomachineryPerformance;} + /*! * \brief Provide the inlet density to check convergence of conservative mixing-plane. * \param[in] inMarkerTP - bound marker. diff --git a/SU2_CFD/include/solvers/CSolver.hpp b/SU2_CFD/include/solvers/CSolver.hpp index f7175ec8e0a3..92be3c62e982 100644 --- a/SU2_CFD/include/solvers/CSolver.hpp +++ b/SU2_CFD/include/solvers/CSolver.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ #include "../../../Common/include/graph_coloring_structure.hpp" #include "../../../Common/include/toolboxes/MMS/CVerificationSolution.hpp" #include "../variables/CVariable.hpp" +#include "../objectives/turbomachinery/CTurbomachineryPerformance.hpp" using namespace std; @@ -125,6 +127,8 @@ class CSolver { su2activevector iPoint_UndLapl; /*!< \brief Auxiliary variable for the undivided Laplacians. */ su2activevector jPoint_UndLapl; /*!< \brief Auxiliary variable for the undivided Laplacians. */ + vector TurboPrimitive; + int *Restart_Vars; /*!< \brief Auxiliary structure for holding the number of variables and points in a restart. */ int Restart_ExtIter; /*!< \brief Auxiliary structure for holding the external iteration offset from a restart. */ passivedouble *Restart_Data; /*!< \brief Auxiliary structure for holding the data values from a restart. */ @@ -3859,6 +3863,14 @@ class CSolver { */ inline virtual void InitTurboContainers(CGeometry *geometry, CConfig *config) { } + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void InitTurboPerformance(CGeometry *geometry, CConfig *config) { } + /*! * \brief virtual member. * \param[in] geometry - Geometrical definition of the problem. @@ -3890,6 +3902,13 @@ class CSolver { */ inline virtual void GatherInOutAverageValues(CConfig *config, CGeometry *geometry) { } + /*! + * \brief virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + */ + // inline virtual void ComputeTurboPerformance(CConfig *config, CGeometry *geometry) { } + /*! * \brief A virtual member. * \param[in] val_marker - bound marker. @@ -3897,6 +3916,13 @@ class CSolver { */ inline virtual su2double GetAverageDensity(unsigned short valMarker, unsigned short valSpan) const { return 0.0; } + /*! + * \brief A virtual member. + * \param[in] val_marker - bound marker. + * \return Value of the Average Mass Flow Rate on the surface val_marker. + */ + inline virtual su2double GetAverageMassFlowRate(unsigned short valMarker) const { return 0.0; } + /*! * \brief A virtual member. * \param[in] val_marker - bound marker. @@ -4008,6 +4034,12 @@ class CSolver { unsigned short valSpan, su2double valOmega) { } + /*! + * \brief Getter for TurbomachineryPerformance + * \return TurbomachineryPerformance container + */ + inline virtual shared_ptr GetTurbomachineryPerformance() const {return 0;} + /*! * \brief A virtual member. * \param[in] inMarkerTP - bound marker. @@ -4321,6 +4353,13 @@ class CSolver { */ inline virtual bool GetHasHybridParallel() const { return false; } + /*! + * \brief Get Primal variables for turbo performance computation + * iteration can be executed by multiple threads. + * \return returns Density, pressure and TurboVelocity (IN/OUTLET) + */ + virtual vector GetTurboPrimitive(unsigned short iBlade, unsigned short iSpan, bool INLET) {return TurboPrimitive;} + /*! * \brief Get values for streamwise periodc flow: delta P, m_dot, inlet T, integrated heat. * \return Struct holding 4 su2doubles. diff --git a/SU2_CFD/src/SU2_CFD.cpp b/SU2_CFD/src/SU2_CFD.cpp index 99f7003d048c..6418159c4279 100644 --- a/SU2_CFD/src/SU2_CFD.cpp +++ b/SU2_CFD/src/SU2_CFD.cpp @@ -150,9 +150,11 @@ int main(int argc, char *argv[]) { else if (turbo) { /*--- Turbomachinery problem. ---*/ - driver = new CTurbomachineryDriver(config_file_name, nZone, MPICommunicator); - - } /*--- These are all the possible cases ---*/ + if (multizone) + driver = new CMultizoneDriver(config_file_name, nZone, MPICommunicator); + else + driver = new CSinglezoneDriver(config_file_name, nZone, MPICommunicator); + } /*--- Launch the main external loop of the solver. ---*/ diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 677f19a7bb8d..edd125b7e8a2 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -2312,6 +2312,9 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe const bool fluid_donor = config[donor]->GetFluidProblem(); const bool structural_donor = config[donor]->GetStructuralProblem(); + /*--- Turbomachinery Bool for MIXING PLANE ---*/ + const bool turbo = config[donor]->GetBoolTurbomachinery(); + /*--- Initialize the appropriate transfer strategy. ---*/ if (rank == MASTER_NODE) cout << " Transferring "; @@ -2338,10 +2341,22 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe 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; + /*--- 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; + } + } + else{ + auto nVar = solver[donor][INST_0][MESH_0][FLOW_SOL]->GetnPrimVar(); + interface_type = SLIDING_INTERFACE; + 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) @@ -2376,18 +2391,6 @@ void CDriver::Interface_Preprocessing(CConfig **config, CSolver***** solver, CGe } } - /*--- 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; - } - } - } } @@ -2544,7 +2547,7 @@ void CDriver::Turbomachinery_Preprocessing(CConfig** config, CGeometry**** geome nSpanMax = config[iZone]->GetnSpanWiseSections(); } - config[ZONE_0]->SetnSpan_iZones(config[iZone]->GetnSpanWiseSections(), iZone); + config[nZone-1]->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); @@ -2553,14 +2556,14 @@ void CDriver::Turbomachinery_Preprocessing(CConfig** config, CGeometry**** geome /*--- Set maximum number of Span among all zones ---*/ for (iZone = 0; iZone < nZone; iZone++) { - if (config[iZone]->GetBoolTurbomachinery()){ + 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; + if (rank == MASTER_NODE) cout<<"Initialize solver containers for average 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]); } @@ -2578,17 +2581,17 @@ void CDriver::Turbomachinery_Preprocessing(CConfig** config, CGeometry**** geome 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){ + if (interface_types[donorZone][targetZone]==MIXING_PLANE){ 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); - } + // This gives segmentation fault, but we have to add it, to fix the mass flow computation in the first two zones + // for (iZone = 0; iZone < nZone-1; iZone++) { + // interface[iZone][nZone-1]->GatherAverageTurboGeoValues(geometry[iZone][INST_0][MESH_0],geometry[nZone-1][INST_0][MESH_0], iZone); + // } /*--- Transfer number of blade to ZONE_0 to correctly compute turbo performance---*/ for (iZone = 1; iZone < nZone; iZone++) { @@ -2614,7 +2617,7 @@ void CDriver::Turbomachinery_Preprocessing(CConfig** config, CGeometry**** geome nMarkerInt = config_container[donorZone]->GetnMarker_MixingPlaneInterface()/2; for (iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++){ for (targetZone = 0; targetZone < nZone; targetZone++) { - if (targetZone != donorZone){ + if (interface_types[donorZone][targetZone]==MIXING_PLANE){ interface[donorZone][targetZone]->PreprocessAverage(geometry[donorZone][INST_0][MESH_0], geometry[targetZone][INST_0][MESH_0], config[donorZone], config[targetZone], iMarkerInt); @@ -2911,6 +2914,113 @@ void CFluidDriver::Output(unsigned long InnerIter) { } +// void CFluidDriver::TurboMonitor(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]); +// } +// } + +// 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); +// } +// break; +// } +// } +// } +// } +// } +// } + CTurbomachineryDriver::CTurbomachineryDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunicator): diff --git a/SU2_CFD/src/drivers/CMultizoneDriver.cpp b/SU2_CFD/src/drivers/CMultizoneDriver.cpp index ea5af8b59457..73df2f1dc07a 100644 --- a/SU2_CFD/src/drivers/CMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CMultizoneDriver.cpp @@ -413,8 +413,6 @@ bool CMultizoneDriver::OuterConvergence(unsigned long OuterIter) { } - /*--- Print out the convergence data to screen and history file. ---*/ - driver_output->SetMultizoneHistory_Output(output_container, config_container, driver_config, driver_config->GetTimeIter(), driver_config->GetOuterIter()); @@ -599,6 +597,30 @@ bool CMultizoneDriver::Transfer_Data(unsigned short donorZone, unsigned short ta targetSolver = FEA_SOL; break; } + case MIXING_PLANE: + { + donorSolver = FLOW_SOL; + targetSolver = FLOW_SOL; + + auto nMarkerInt = config_container[donorZone]->GetnMarker_MixingPlaneInterface()/2; + + /* --- transfer the average value from the donorZone to the targetZone*/ + for (auto iMarkerInt = 1; iMarkerInt <= nMarkerInt; iMarkerInt++) { + 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 ); + } + + for (donorZone = 0; donorZone < nZone-1; donorZone++) { + if (interface_types[donorZone][targetZone]==MIXING_PLANE) { + interface_container[donorZone][targetZone]->GatherAverageValues(solver_container[donorZone][INST_0][MESH_0][FLOW_SOL],solver_container[targetZone][INST_0][MESH_0][FLOW_SOL], donorZone); + interface_container[donorZone][targetZone]->GatherAverageTurboGeoValues(geometry_container[donorZone][INST_0][MESH_0],geometry_container[targetZone][INST_0][MESH_0], donorZone); + } + } + + return UpdateMesh; + break; + } case NO_TRANSFER: case ZONES_ARE_EQUAL: case NO_COMMON_INTERFACE: diff --git a/SU2_CFD/src/drivers/CSinglezoneDriver.cpp b/SU2_CFD/src/drivers/CSinglezoneDriver.cpp index 2b9f488d4931..4fe293d67e9a 100644 --- a/SU2_CFD/src/drivers/CSinglezoneDriver.cpp +++ b/SU2_CFD/src/drivers/CSinglezoneDriver.cpp @@ -159,7 +159,6 @@ void CSinglezoneDriver::Run() { /*--- Iterate the zone as a block, either to convergence or to a max number of iterations ---*/ iteration_container[ZONE_0][INST_0]->Solve(output_container[ZONE_0], integration_container, geometry_container, solver_container, numerics_container, config_container, surface_movement, grid_movement, FFDBox, ZONE_0, INST_0); - } void CSinglezoneDriver::Postprocess() { diff --git a/SU2_CFD/src/integration/CIntegration.cpp b/SU2_CFD/src/integration/CIntegration.cpp index 853172b48bbd..82d4a02596b5 100644 --- a/SU2_CFD/src/integration/CIntegration.cpp +++ b/SU2_CFD/src/integration/CIntegration.cpp @@ -88,6 +88,13 @@ void CIntegration::Space_Integration(CGeometry *geometry, solver_container[MainSolver]->PreprocessBC_Giles(geometry, config, conv_bound_numerics, OUTFLOW); } + if (config->GetBoolTurbomachinery()){ + /*--- Average quantities at the inflow and outflow boundaries ---*/ + + solver_container[MainSolver]->TurboAverageProcess(solver_container, geometry,config,INFLOW); + solver_container[MainSolver]->TurboAverageProcess(solver_container, geometry, config, OUTFLOW); + } + /*--- Weak boundary conditions ---*/ for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { diff --git a/SU2_CFD/src/integration/CMultiGridIntegration.cpp b/SU2_CFD/src/integration/CMultiGridIntegration.cpp index f3ae38351217..7d41198d0450 100644 --- a/SU2_CFD/src/integration/CMultiGridIntegration.cpp +++ b/SU2_CFD/src/integration/CMultiGridIntegration.cpp @@ -692,6 +692,29 @@ void CMultiGridIntegration::NonDimensional_Parameters(CGeometry **geometry, CSol solver_container[FinestMesh][FLOW_SOL]->Momentum_Forces(geometry[FinestMesh], config); solver_container[FinestMesh][FLOW_SOL]->Friction_Forces(geometry[FinestMesh], config); + /*--- Calculate the turbo performance ---*/ + if (config->GetBoolTurbomachinery()){ + + /*--- Average quantities at the inflow and outflow boundaries ---*/ + + solver_container[FinestMesh][FLOW_SOL]->TurboAverageProcess(solver_container[FinestMesh], geometry[FinestMesh],config,INFLOW); + solver_container[FinestMesh][FLOW_SOL]->TurboAverageProcess(solver_container[FinestMesh], geometry[FinestMesh], config, OUTFLOW); + + /*--- Gather Inflow and Outflow quantities on the Master Node to compute performance ---*/ + + solver_container[FinestMesh][FLOW_SOL]->GatherInOutAverageValues(config, geometry[FinestMesh]); + + /* --- compute turboperformance for each stage and the global machine ---*/ + //TODO: for multi-zone turbo this should be move to the last zone ---*/ + // solver_container[FinestMesh][FLOW_SOL]->ComputeTurboPerformance(config, geometry[FinestMesh]); + } + + /*--- Evaluate the buffet metric if requested ---*/ + /* + if(config->GetnMarker_Monitoring() || config->GetKind_ObjFunc() == BUFFET_SENSOR){ + solver_container[FinestMesh][FLOW_SOL]->Buffet_Monitoring(geometry[FinestMesh], config); + } + */ break; case RUNTIME_ADJFLOW_SYS: diff --git a/SU2_CFD/src/interfaces/cfd/CMixingPlaneInterface.cpp b/SU2_CFD/src/interfaces/cfd/CMixingPlaneInterface.cpp index 5f791504dc79..d86cc7d62b83 100644 --- a/SU2_CFD/src/interfaces/cfd/CMixingPlaneInterface.cpp +++ b/SU2_CFD/src/interfaces/cfd/CMixingPlaneInterface.cpp @@ -60,7 +60,7 @@ void CMixingPlaneInterface::GetDonor_Variable(CSolver *donor_solution, CGeometry unsigned short nDim = nVar - 2; bool turbulent = (donor_config->GetKind_Turb_Model() != NONE); - + // iSpan = 0; Donor_Variable[0] = donor_solution->GetAverageDensity(Marker_Donor, iSpan); Donor_Variable[1] = donor_solution->GetAveragePressure(Marker_Donor, iSpan); diff --git a/SU2_CFD/src/iteration/CFluidIteration.cpp b/SU2_CFD/src/iteration/CFluidIteration.cpp index dccc21497526..18802258d87a 100644 --- a/SU2_CFD/src/iteration/CFluidIteration.cpp +++ b/SU2_CFD/src/iteration/CFluidIteration.cpp @@ -226,10 +226,34 @@ bool CFluidIteration::Monitor(COutput* output, CIntegration**** integration, CGe UsedTime = StopTime - StartTime; - if (config[val_iZone]->GetMultizone_Problem() || config[val_iZone]->GetSinglezone_Driver()) { - output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], solver[val_iZone][INST_0][MESH_0], config[val_iZone], + unsigned long Iter= config[val_iZone]->GetInnerIter(); + + + output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], solver[val_iZone][INST_0][MESH_0], config[val_iZone], + config[val_iZone]->GetTimeIter(), config[val_iZone]->GetOuterIter(), + config[val_iZone]->GetInnerIter()); + + /*--- Turbomachinery Specific Montior ---*/ + if (config[ZONE_0]->GetBoolTurbomachinery()){ + + /*--- Turbomachinery Performance Computation ---*/ + if (val_iZone == config[ZONE_0]->GetnZone()-1) + ComputeTurboPerformance(solver, geometry, config, config[val_iZone]->GetInnerIter()); + + if (config[ZONE_0]->GetMultizone_Problem()) + Iter = config[ZONE_0]->GetOuterIter(); + + /*--- Turbomachinery Performance Screen summary output---*/ + if (val_iZone == config[ZONE_0]->GetnZone()-1 && Iter%100 == 0) { + output->SetTurboPerformance_Output(TurbomachineryPerformance, config[val_iZone], config[val_iZone]->GetTimeIter(), config[val_iZone]->GetOuterIter(), - config[val_iZone]->GetInnerIter()); + config[val_iZone]->GetInnerIter(), val_iZone); + if (rank == MASTER_NODE) + output->SetTurboMultiZonePerformance_Output(TurbomachineryStagePerformance, TurbomachineryPerformance, config[val_iZone]); + } + + /*--- Turbomachinery Rotation and Pressure Ramps ---*/ + TurboMonitor(geometry, config, config[val_iZone]->GetInnerIter()); } /*--- If convergence was reached --*/ @@ -245,6 +269,112 @@ bool CFluidIteration::Monitor(COutput* output, CIntegration**** integration, CGe return StopCalc; } +void CFluidIteration::TurboMonitor(CGeometry**** geometry_container, CConfig** config_container, 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; + unsigned short iZone; + string Marker_Tag; + + bool print; + if (config_container[ZONE_0]->GetMultizone_Problem()) + ExtIter = config_container[ZONE_0]->GetOuterIter(); + + for(iZone = 0; iZone < nZone; iZone++) { + /*--- ROTATING FRAME Ramp: Compute the updated rotational velocity. ---*/ + if (config_container[iZone]->GetGrid_Movement() && config_container[iZone]->GetRampRotatingFrame()) { + rampFreq = SU2_TYPE::Int(config_container[iZone]->GetRampRotatingFrame_Coeff(1)); + finalRamp_Iter = SU2_TYPE::Int(config_container[iZone]->GetRampRotatingFrame_Coeff(2)); + rot_z_ini = config_container[iZone]->GetRampRotatingFrame_Coeff(0); + print = false; + if(ExtIter % rampFreq == 0 && ExtIter <= finalRamp_Iter){ + 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); + + } + } + } + } + + + /*--- 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; + } + } + } + } + } +} + +void CFluidIteration::ComputeTurboPerformance(CSolver***** solver, CGeometry**** geometry_container, CConfig** config_container, unsigned long ExtIter) { + unsigned short nDim = geometry_container[ZONE_0][INST_0][MESH_0]->GetnDim(); + unsigned short nBladesRow = config_container[ZONE_0]->GetnMarker_Turbomachinery(); + unsigned short iBlade=0, iSpan; + vector TurboPrimitiveIn, TurboPrimitiveOut; + std::vector> bladesPrimitives; + + if (rank == MASTER_NODE) { + for (iBlade = 0; iBlade < nBladesRow; iBlade++){ + /* Blade Primitive initialized per blade */ + std::vector bladePrimitives; + auto nSpan = config_container[iBlade]->GetnSpanWiseSections(); + for (iSpan = 0; iSpan < nSpan + 1; iSpan++) { + TurboPrimitiveIn= solver[iBlade][INST_0][MESH_0][FLOW_SOL]->GetTurboPrimitive(iBlade, iSpan, true); + TurboPrimitiveOut= solver[iBlade][INST_0][MESH_0][FLOW_SOL]->GetTurboPrimitive(iBlade, iSpan, false); + auto spanInletPrimitive = CTurbomachineryPrimitiveState(TurboPrimitiveIn, nDim, geometry_container[iBlade][INST_0][MESH_0]->GetTangGridVelIn(iBlade, iSpan)); + auto spanOutletPrimitive = CTurbomachineryPrimitiveState(TurboPrimitiveOut, nDim, geometry_container[iBlade][INST_0][MESH_0]->GetTangGridVelOut(iBlade, iSpan)); + auto spanCombinedPrimitive = CTurbomachineryCombinedPrimitiveStates(spanInletPrimitive, spanOutletPrimitive); + bladePrimitives.push_back(spanCombinedPrimitive); + } + bladesPrimitives.push_back(bladePrimitives); + } + TurbomachineryPerformance->ComputeTurbomachineryPerformance(bladesPrimitives); + } +} + void CFluidIteration::Postprocess(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, CVolumetricMovement*** grid_movement, diff --git a/SU2_CFD/src/iteration/CTurboIteration.cpp b/SU2_CFD/src/iteration/CTurboIteration.cpp index ef00fd01cc14..a68068324d3f 100644 --- a/SU2_CFD/src/iteration/CTurboIteration.cpp +++ b/SU2_CFD/src/iteration/CTurboIteration.cpp @@ -27,6 +27,7 @@ #include "../../include/iteration/CTurboIteration.hpp" #include "../../include/output/COutput.hpp" +#include "../../include/objectives/turbomachinery/CTurbomachineryPerformance.hpp" void CTurboIteration::Preprocess(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, @@ -37,6 +38,10 @@ void CTurboIteration::Preprocess(COutput* output, CIntegration**** integration, solver[val_iZone][val_iInst][MESH_0], geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], INFLOW); solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->TurboAverageProcess( solver[val_iZone][val_iInst][MESH_0], geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], OUTFLOW); + + if (config[val_iZone]->GetBoolTurbomachinery()) { + InitTurboPerformance(geometry[val_iZone][INST_0][MESH_0], config[val_iZone], solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->GetFluidModel()); + } } void CTurboIteration::Postprocess(COutput* output, CIntegration**** integration, CGeometry**** geometry, @@ -53,3 +58,8 @@ void CTurboIteration::Postprocess(COutput* output, CIntegration**** integration, solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->GatherInOutAverageValues(config[val_iZone], geometry[val_iZone][val_iInst][MESH_0]); } + +void CTurboIteration::InitTurboPerformance(CGeometry *geometry, CConfig *config, CFluidModel *fluid){ + TurbomachineryPerformance = std::make_shared(*config, *geometry, *fluid); + TurbomachineryStagePerformance = new CTurbomachineryStagePerformance(*fluid); +} \ No newline at end of file diff --git a/SU2_CFD/src/iteration_structure.cpp b/SU2_CFD/src/iteration_structure.cpp new file mode 100644 index 000000000000..50bcb24db5a4 --- /dev/null +++ b/SU2_CFD/src/iteration_structure.cpp @@ -0,0 +1,3497 @@ +/*! + * \file iteration_structure.cpp + * \brief Main subroutines used by SU2_CFD + * \author F. Palacios, T. Economon + * \version 7.0.2 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2020, 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/iteration_structure.hpp" +#include "../include/solvers/CFEASolver.hpp" + +CIteration::CIteration(CConfig *config) { + rank = SU2_MPI::GetRank(); + size = SU2_MPI::GetSize(); + + nInst = config->GetnTimeInstances(); + nZone = config->GetnZone(); + + multizone = config->GetMultizone_Problem(); + singlezone = !(config->GetMultizone_Problem()); + +} + +CIteration::~CIteration(void) { } + +void CIteration::SetGrid_Movement(CGeometry **geometry, + CSurfaceMovement *surface_movement, + CVolumetricMovement *grid_movement, + CSolver ***solver, + CConfig *config, + unsigned long IntIter, + unsigned long TimeIter) { + + unsigned short Kind_Grid_Movement = config->GetKind_GridMovement(); + unsigned long nIterMesh; + bool stat_mesh = true; + bool adjoint = config->GetContinuous_Adjoint(); + bool discrete_adjoint = config->GetDiscrete_Adjoint(); + + /*--- Only write to screen if this option is enabled ---*/ + bool Screen_Output = config->GetDeform_Output(); + + unsigned short val_iZone = config->GetiZone(); + + /*--- Perform mesh movement depending on specified type ---*/ + switch (Kind_Grid_Movement) { + + case RIGID_MOTION: + + if (rank == MASTER_NODE) { + cout << endl << " Performing rigid mesh transformation." << endl; + } + + /*--- Move each node in the volume mesh using the specified type + of rigid mesh motion. These routines also compute analytic grid + velocities for the fine mesh. ---*/ + + grid_movement->Rigid_Translation(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Plunging(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Pitching(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Rotation(geometry[MESH_0], + config, val_iZone, TimeIter); + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry, config); + + break; + + /*--- Already initialized in the static mesh movement routine at driver level. ---*/ + case STEADY_TRANSLATION: case ROTATING_FRAME: + break; + + } + + if (config->GetSurface_Movement(DEFORMING)){ + if (rank == MASTER_NODE) + cout << endl << " Updating surface positions." << endl; + + /*--- Translating ---*/ + + /*--- Compute the new node locations for moving markers ---*/ + + surface_movement->Surface_Translating(geometry[MESH_0], + config, TimeIter, val_iZone); + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + + /*--- Plunging ---*/ + + /*--- Compute the new node locations for moving markers ---*/ + + surface_movement->Surface_Plunging(geometry[MESH_0], + config, TimeIter, val_iZone); + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + + /*--- Pitching ---*/ + + /*--- Compute the new node locations for moving markers ---*/ + + surface_movement->Surface_Pitching(geometry[MESH_0], + config, TimeIter, val_iZone); + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + + /*--- Rotating ---*/ + + /*--- Compute the new node locations for moving markers ---*/ + + surface_movement->Surface_Rotating(geometry[MESH_0], + config, TimeIter, val_iZone); + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + + /*--- Update the grid velocities on the fine mesh using finite + differencing based on node coordinates at previous times. ---*/ + + if (!adjoint) { + if (rank == MASTER_NODE) + cout << " Computing grid velocities by finite differencing." << endl; + geometry[MESH_0]->SetGridVelocity(config, TimeIter); + } + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry, config); + + } + + if (config->GetSurface_Movement(AEROELASTIC) + || config->GetSurface_Movement(AEROELASTIC_RIGID_MOTION)){ + + /*--- Apply rigid mesh transformation to entire grid first, if necessary ---*/ + if (IntIter == 0) { + if (Kind_Grid_Movement == AEROELASTIC_RIGID_MOTION) { + + if (rank == MASTER_NODE) { + cout << endl << " Performing rigid mesh transformation." << endl; + } + + /*--- Move each node in the volume mesh using the specified type + of rigid mesh motion. These routines also compute analytic grid + velocities for the fine mesh. ---*/ + + grid_movement->Rigid_Translation(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Plunging(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Pitching(geometry[MESH_0], + config, val_iZone, TimeIter); + grid_movement->Rigid_Rotation(geometry[MESH_0], + config, val_iZone, TimeIter); + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry, config); + } + + } + + /*--- Use the if statement to move the grid only at selected dual time step iterations. ---*/ + else if (IntIter % config->GetAeroelasticIter() == 0) { + + if (rank == MASTER_NODE) + cout << endl << " Solving aeroelastic equations and updating surface positions." << endl; + + /*--- Solve the aeroelastic equations for the new node locations of the moving markers(surfaces) ---*/ + + solver[MESH_0][FLOW_SOL]->Aeroelastic(surface_movement, geometry[MESH_0], config, TimeIter); + + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid due to the aeroelastic movement." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + + /*--- Update the grid velocities on the fine mesh using finite + differencing based on node coordinates at previous times. ---*/ + + if (rank == MASTER_NODE) + cout << " Computing grid velocities by finite differencing." << endl; + geometry[MESH_0]->SetGridVelocity(config, TimeIter); + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry, config); + } + } + if (config->GetSurface_Movement(FLUID_STRUCTURE)){ + if (rank == MASTER_NODE && Screen_Output) + cout << endl << "Deforming the grid for Fluid-Structure Interaction applications." << endl; + + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE && Screen_Output) + cout << "Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true, false); + + nIterMesh = grid_movement->Get_nIterMesh(); + stat_mesh = (nIterMesh == 0); + + if (!adjoint && !stat_mesh) { + if (rank == MASTER_NODE && Screen_Output) + cout << "Computing grid velocities by finite differencing." << endl; + geometry[MESH_0]->SetGridVelocity(config, TimeIter); + } + else if (stat_mesh) { + if (rank == MASTER_NODE && Screen_Output) + cout << "The mesh is up-to-date. Using previously stored grid velocities." << endl; + } + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry, config); + + } + if (config->GetSurface_Movement(FLUID_STRUCTURE_STATIC)){ + + if ((rank == MASTER_NODE) && (!discrete_adjoint) && Screen_Output) + cout << endl << "Deforming the grid for static Fluid-Structure Interaction applications." << endl; + + /*--- Deform the volume grid around the new boundary locations ---*/ + + if ((rank == MASTER_NODE) && (!discrete_adjoint)&& Screen_Output) + cout << "Deforming the volume grid." << endl; + + grid_movement->SetVolume_Deformation_Elas(geometry[MESH_0], config, true, false); + + if ((rank == MASTER_NODE) && (!discrete_adjoint)&& Screen_Output) + cout << "There is no grid velocity." << endl; + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry, config); + + } + if (config->GetSurface_Movement(EXTERNAL) || config->GetSurface_Movement(EXTERNAL_ROTATION)){ + /*--- Apply rigid rotation to entire grid first, if necessary ---*/ + + if (Kind_Grid_Movement == EXTERNAL_ROTATION) { + if (rank == MASTER_NODE) + cout << " Updating node locations by rigid rotation." << endl; + grid_movement->Rigid_Rotation(geometry[MESH_0], + config, val_iZone, TimeIter); + } + + /*--- Load new surface node locations from external files ---*/ + + if (rank == MASTER_NODE) + cout << " Updating surface locations from file." << endl; + surface_movement->SetExternal_Deformation(geometry[MESH_0], + config, val_iZone, TimeIter); + + /*--- Deform the volume grid around the new boundary locations ---*/ + + if (rank == MASTER_NODE) + cout << " Deforming the volume grid." << endl; + grid_movement->SetVolume_Deformation(geometry[MESH_0], + config, true); + + /*--- Update the grid velocities on the fine mesh using finite + differencing based on node coordinates at previous times. ---*/ + + if (!adjoint) { + if (rank == MASTER_NODE) + cout << " Computing grid velocities by finite differencing." << endl; + geometry[MESH_0]->SetGridVelocity(config, TimeIter); + } + + /*--- Update the multigrid structure after moving the finest grid, + including computing the grid velocities on the coarser levels. ---*/ + + grid_movement->UpdateMultiGrid(geometry, config); + + } +} + +void CIteration::SetMesh_Deformation(CGeometry **geometry, + CSolver **solver, + CNumerics ***numerics, + CConfig *config, + unsigned short kind_recording) { + + bool ActiveTape = NO; + + /*--- Perform the elasticity mesh movement ---*/ + if (config->GetDeform_Mesh()) { + + if ((kind_recording != MESH_DEFORM) && !config->GetMultizone_Problem()) { + /*--- In a primal run, AD::TapeActive returns a false ---*/ + /*--- In any other recordings, the tape is passive during the deformation ---*/ + ActiveTape = AD::TapeActive(); + AD::StopRecording(); + } + + /*--- Set the stiffness of each element mesh into the mesh numerics ---*/ + + solver[MESH_SOL]->SetMesh_Stiffness(geometry, numerics[MESH_SOL], config); + + /*--- Deform the volume grid around the new boundary locations ---*/ + + solver[MESH_SOL]->DeformMesh(geometry, numerics[MESH_SOL], config); + + if (ActiveTape) { + /*--- Start recording if it was stopped ---*/ + AD::StartRecording(); + } + } + +} + + + +void CIteration::Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } +void CIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } +void CIteration::Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } +void CIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } +void CIteration::Predictor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } +void CIteration::Relaxation(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } +bool CIteration::Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { return false; } + +void CIteration::Output(COutput *output, + CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned long InnerIter, + bool StopCalc, + unsigned short val_iZone, + unsigned short val_iInst) { + + output->SetResult_Files(geometry[val_iZone][INST_0][MESH_0], + config[val_iZone], + solver[val_iZone][INST_0][MESH_0], + InnerIter); + +} +void CIteration::Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } + + + +CFluidIteration::CFluidIteration(CConfig *config) : CIteration(config) { } +CFluidIteration::~CFluidIteration(void) { } + +void CFluidIteration::Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned long TimeIter = config[val_iZone]->GetTimeIter(); + + bool fsi = config[val_iZone]->GetFSI_Simulation(); + unsigned long OuterIter = config[val_iZone]->GetOuterIter(); + + + /*--- Set the initial condition for FSI problems with subiterations ---*/ + /*--- This is done only in the first block subiteration.---*/ + /*--- From then on, the solver reuses the partially converged solution obtained in the previous subiteration ---*/ + if( fsi && ( OuterIter == 0 ) ){ + solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->SetInitialCondition(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], TimeIter); + } + + /*--- Apply a Wind Gust ---*/ + + if (config[val_iZone]->GetWind_Gust()) { + SetWind_GustField(config[val_iZone], geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst]); + } + +} + +void CFluidIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + unsigned long InnerIter, TimeIter; + + bool unsteady = (config[val_iZone]->GetTime_Marching() == DT_STEPPING_1ST) || (config[val_iZone]->GetTime_Marching() == DT_STEPPING_2ND); + bool frozen_visc = (config[val_iZone]->GetContinuous_Adjoint() && config[val_iZone]->GetFrozen_Visc_Cont()) || + (config[val_iZone]->GetDiscrete_Adjoint() && config[val_iZone]->GetFrozen_Visc_Disc()); + TimeIter = config[val_iZone]->GetTimeIter(); + + /* --- Setting up iteration values depending on if this is a + steady or an unsteady simulaiton */ + + InnerIter = config[val_iZone]->GetInnerIter(); + + /*--- Update global parameters ---*/ + + switch( config[val_iZone]->GetKind_Solver() ) { + + case EULER: case DISC_ADJ_EULER: case INC_EULER: case DISC_ADJ_INC_EULER: + config[val_iZone]->SetGlobalParam(EULER, RUNTIME_FLOW_SYS); break; + + case NAVIER_STOKES: case DISC_ADJ_NAVIER_STOKES: case INC_NAVIER_STOKES: case DISC_ADJ_INC_NAVIER_STOKES: + config[val_iZone]->SetGlobalParam(NAVIER_STOKES, RUNTIME_FLOW_SYS); break; + + case RANS: case DISC_ADJ_RANS: case INC_RANS: case DISC_ADJ_INC_RANS: + config[val_iZone]->SetGlobalParam(RANS, RUNTIME_FLOW_SYS); break; + + } + + + /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ + + integration[val_iZone][val_iInst][FLOW_SOL]->MultiGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_FLOW_SYS, val_iZone, val_iInst); + + if ((config[val_iZone]->GetKind_Solver() == RANS || + config[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS || + config[val_iZone]->GetKind_Solver() == INC_RANS || + config[val_iZone]->GetKind_Solver() == DISC_ADJ_INC_RANS ) && !frozen_visc) { + + /*--- Solve the turbulence model ---*/ + + config[val_iZone]->SetGlobalParam(RANS, RUNTIME_TURB_SYS); + integration[val_iZone][val_iInst][TURB_SOL]->SingleGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_TURB_SYS, val_iZone, val_iInst); + + /*--- Solve transition model ---*/ + + if (config[val_iZone]->GetKind_Trans_Model() == LM) { + config[val_iZone]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS); + integration[val_iZone][val_iInst][TRANS_SOL]->SingleGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_TRANS_SYS, val_iZone, val_iInst); + } + + } + + if (config[val_iZone]->GetWeakly_Coupled_Heat()){ + config[val_iZone]->SetGlobalParam(RANS, RUNTIME_HEAT_SYS); + integration[val_iZone][val_iInst][HEAT_SOL]->SingleGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_HEAT_SYS, val_iZone, val_iInst); + } + + /*--- Incorporate a weakly-coupled radiation model to the analysis ---*/ + if (config[val_iZone]->AddRadiation()){ + config[val_iZone]->SetGlobalParam(RANS, RUNTIME_RADIATION_SYS); + integration[val_iZone][val_iInst][RAD_SOL]->SingleGrid_Iteration(geometry, solver, numerics, config, + RUNTIME_RADIATION_SYS, val_iZone, val_iInst); + } + + /*--- Adapt the CFL number using an exponential progression + with under-relaxation approach. ---*/ + + if (config[val_iZone]->GetCFL_Adapt() == YES) { + solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->AdaptCFLNumber(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone]); + } + + /*--- Call Dynamic mesh update if AEROELASTIC motion was specified ---*/ + + if ((config[val_iZone]->GetGrid_Movement()) && (config[val_iZone]->GetAeroelastic_Simulation()) && unsteady) { + + SetGrid_Movement(geometry[val_iZone][val_iInst], surface_movement[val_iZone], grid_movement[val_iZone][val_iInst], + solver[val_iZone][val_iInst], config[val_iZone], InnerIter, TimeIter); + + /*--- Apply a Wind Gust ---*/ + + if (config[val_iZone]->GetWind_Gust()) { + if (InnerIter % config[val_iZone]->GetAeroelasticIter() == 0 && InnerIter != 0) + SetWind_GustField(config[val_iZone], geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst]); + } + + } +} + +void CFluidIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned short iMesh; + + /*--- Dual time stepping strategy ---*/ + + if ((config[val_iZone]->GetTime_Marching() == DT_STEPPING_1ST) || + (config[val_iZone]->GetTime_Marching() == DT_STEPPING_2ND)) { + + /*--- Update dual time solver on all mesh levels ---*/ + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + integration[val_iZone][val_iInst][FLOW_SOL]->SetDualTime_Solver(geometry[val_iZone][val_iInst][iMesh], solver[val_iZone][val_iInst][iMesh][FLOW_SOL], config[val_iZone], iMesh); + integration[val_iZone][val_iInst][FLOW_SOL]->SetConvergence(false); + } + + /*--- Update dual time solver for the dynamic mesh solver ---*/ + if (config[val_iZone]->GetDeform_Mesh()) { + solver[val_iZone][val_iInst][MESH_0][MESH_SOL]->SetDualTime_Mesh(); + } + + /*--- Update dual time solver for the turbulence model ---*/ + + if ((config[val_iZone]->GetKind_Solver() == RANS) || + (config[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS) || + (config[val_iZone]->GetKind_Solver() == INC_RANS) || + (config[val_iZone]->GetKind_Solver() == DISC_ADJ_INC_RANS)) { + integration[val_iZone][val_iInst][TURB_SOL]->SetDualTime_Solver(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0][TURB_SOL], config[val_iZone], MESH_0); + integration[val_iZone][val_iInst][TURB_SOL]->SetConvergence(false); + } + + /*--- Update dual time solver for the transition model ---*/ + + if (config[val_iZone]->GetKind_Trans_Model() == LM) { + integration[val_iZone][val_iInst][TRANS_SOL]->SetDualTime_Solver(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0][TRANS_SOL], config[val_iZone], MESH_0); + integration[val_iZone][val_iInst][TRANS_SOL]->SetConvergence(false); + } + } +} + +bool CFluidIteration::Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + bool StopCalc = false; + +#ifndef HAVE_MPI + StopTime = su2double(clock())/su2double(CLOCKS_PER_SEC); +#else + StopTime = MPI_Wtime(); +#endif + UsedTime = StopTime - StartTime; + + + if (config[val_iZone]->GetMultizone_Problem() || config[val_iZone]->GetSinglezone_Driver()){ + output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], + solver[val_iZone][INST_0][MESH_0], + config[val_iZone], + config[val_iZone]->GetTimeIter(), + config[val_iZone]->GetOuterIter(), + config[val_iZone]->GetInnerIter()); + } + + /*--- If convergence was reached --*/ + StopCalc = output->GetConvergence(); + + /* --- Checking convergence of Fixed CL mode to target CL, and perform finite differencing if needed --*/ + + if (config[val_iZone]->GetFixed_CL_Mode()){ + StopCalc = MonitorFixed_CL(output, geometry[val_iZone][INST_0][MESH_0], solver[val_iZone][INST_0][MESH_0], config[val_iZone]); + } + + return StopCalc; + +} + +void CFluidIteration::Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + /*--- Temporary: enable only for single-zone driver. This should be removed eventually when generalized. ---*/ + + if(config[val_iZone]->GetSinglezone_Driver()){ + + /*--- Compute the tractions at the vertices ---*/ + solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->ComputeVertexTractions( + geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + + if (config[val_iZone]->GetKind_Solver() == DISC_ADJ_EULER || + config[val_iZone]->GetKind_Solver() == DISC_ADJ_NAVIER_STOKES || + config[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS){ + + /*--- Read the target pressure ---*/ + +// if (config[val_iZone]->GetInvDesign_Cp() == YES) +// output->SetCp_InverseDesign(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL],geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], config[val_iZone]->GetExtIter()); + +// /*--- Read the target heat flux ---*/ + +// if (config[val_iZone]->GetInvDesign_HeatFlux() == YES) +// output->SetHeatFlux_InverseDesign(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL],geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], config[val_iZone]->GetExtIter()); + + } + + } + + +} + +void CFluidIteration::Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + /*--- Boolean to determine if we are running a static or dynamic case ---*/ + bool steady = !config[val_iZone]->GetTime_Domain(); + + unsigned long Inner_Iter, nInner_Iter = config[val_iZone]->GetnInner_Iter(); + bool StopCalc = false; + + /*--- Synchronization point before a single solver iteration. + Compute the wall clock time required. ---*/ + +#ifndef HAVE_MPI + StartTime = su2double(clock())/su2double(CLOCKS_PER_SEC); +#else + StartTime = MPI_Wtime(); +#endif + + /*--- Preprocess the solver ---*/ + Preprocess(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*--- For steady-state flow simulations, we need to loop over ExtIter for the number of time steps ---*/ + /*--- However, ExtIter is the number of FSI iterations, so nIntIter is used in this case ---*/ + + for (Inner_Iter = 0; Inner_Iter < nInner_Iter; Inner_Iter++){ + + config[val_iZone]->SetInnerIter(Inner_Iter); + + /*--- Run a single iteration of the solver ---*/ + Iterate(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*--- Monitor the pseudo-time ---*/ + StopCalc = Monitor(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*--- Output files at intermediate iterations if the problem is single zone ---*/ + + if (singlezone && steady) { + Output(output, geometry, solver, config, Inner_Iter, StopCalc, val_iZone, val_iInst); + } + + /*--- If the iteration has converged, break the loop ---*/ + if (StopCalc) break; + } + + if (multizone && steady) { + Output(output, geometry, solver, config, + config[val_iZone]->GetOuterIter(), + StopCalc, val_iZone, val_iInst); + + /*--- Set the fluid convergence to false (to make sure outer subiterations converge) ---*/ + + integration[val_iZone][INST_0][FLOW_SOL]->SetConvergence(false); + } +} + +void CFluidIteration::SetWind_GustField(CConfig *config, CGeometry **geometry, CSolver ***solver) { + // The gust is imposed on the flow field via the grid velocities. This method called the Field Velocity Method is described in the + // NASA TM–2012-217771 - Development, Verification and Use of Gust Modeling in the NASA Computational Fluid Dynamics Code FUN3D + // the desired gust is prescribed as the negative of the grid velocity. + + // If a source term is included to account for the gust field, the method is described by Jones et al. as the Split Velocity Method in + // Simulation of Airfoil Gust Responses Using Prescribed Velocities. + // In this routine the gust derivatives needed for the source term are calculated when applicable. + // If the gust derivatives are zero the source term is also zero. + // The source term itself is implemented in the class CSourceWindGust + + if (rank == MASTER_NODE) + cout << endl << "Running simulation with a Wind Gust." << endl; + unsigned short iDim, nDim = geometry[MESH_0]->GetnDim(); //We assume nDim = 2 + if (nDim != 2) { + if (rank == MASTER_NODE) { + cout << endl << "WARNING - Wind Gust capability is only verified for 2 dimensional simulations." << endl; + } + } + + /*--- Gust Parameters from config ---*/ + unsigned short Gust_Type = config->GetGust_Type(); + su2double xbegin = config->GetGust_Begin_Loc(); // Location at which the gust begins. + su2double L = config->GetGust_WaveLength(); // Gust size + su2double tbegin = config->GetGust_Begin_Time(); // Physical time at which the gust begins. + su2double gust_amp = config->GetGust_Ampl(); // Gust amplitude + su2double n = config->GetGust_Periods(); // Number of gust periods + unsigned short GustDir = config->GetGust_Dir(); // Gust direction + + /*--- Variables needed to compute the gust ---*/ + unsigned short Kind_Grid_Movement = config->GetKind_GridMovement(); + unsigned long iPoint; + unsigned short iMGlevel, nMGlevel = config->GetnMGLevels(); + + su2double x, y, x_gust, dgust_dx, dgust_dy, dgust_dt; + su2double *Gust, *GridVel, *NewGridVel, *GustDer; + + su2double Physical_dt = config->GetDelta_UnstTime(); + unsigned long TimeIter = config->GetTimeIter(); + su2double Physical_t = TimeIter*Physical_dt; + + su2double Uinf = solver[MESH_0][FLOW_SOL]->GetVelocity_Inf(0); // Assumption gust moves at infinity velocity + + Gust = new su2double [nDim]; + NewGridVel = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + Gust[iDim] = 0.0; + NewGridVel[iDim] = 0.0; + } + + GustDer = new su2double [3]; + for (unsigned short i = 0; i < 3; i++) { + GustDer[i] = 0.0; + } + + // Vortex variables + unsigned long nVortex = 0; + vector x0, y0, vort_strenth, r_core; //vortex is positive in clockwise direction. + if (Gust_Type == VORTEX) { + InitializeVortexDistribution(nVortex, x0, y0, vort_strenth, r_core); + } + + /*--- Check to make sure gust lenght is not zero or negative (vortex gust doesn't use this). ---*/ + if (L <= 0.0 && Gust_Type != VORTEX) { + SU2_MPI::Error("The gust length needs to be positive", CURRENT_FUNCTION); + } + + /*--- Loop over all multigrid levels ---*/ + + for (iMGlevel = 0; iMGlevel <= nMGlevel; iMGlevel++) { + + /*--- Loop over each node in the volume mesh ---*/ + + for (iPoint = 0; iPoint < geometry[iMGlevel]->GetnPoint(); iPoint++) { + + /*--- Reset the Grid Velocity to zero if there is no grid movement ---*/ + if (Kind_Grid_Movement == GUST) { + for (iDim = 0; iDim < nDim; iDim++) + geometry[iMGlevel]->node[iPoint]->SetGridVel(iDim, 0.0); + } + + /*--- initialize the gust and derivatives to zero everywhere ---*/ + + for (iDim = 0; iDim < nDim; iDim++) {Gust[iDim]=0.0;} + dgust_dx = 0.0; dgust_dy = 0.0; dgust_dt = 0.0; + + /*--- Begin applying the gust ---*/ + + if (Physical_t >= tbegin) { + + x = geometry[iMGlevel]->node[iPoint]->GetCoord()[0]; // x-location of the node. + y = geometry[iMGlevel]->node[iPoint]->GetCoord()[1]; // y-location of the node. + + // Gust coordinate + x_gust = (x - xbegin - Uinf*(Physical_t-tbegin))/L; + + /*--- Calculate the specified gust ---*/ + switch (Gust_Type) { + + case TOP_HAT: + // Check if we are in the region where the gust is active + if (x_gust > 0 && x_gust < n) { + Gust[GustDir] = gust_amp; + // Still need to put the gust derivatives. Think about this. + } + break; + + case SINE: + // Check if we are in the region where the gust is active + if (x_gust > 0 && x_gust < n) { + Gust[GustDir] = gust_amp*(sin(2*PI_NUMBER*x_gust)); + + // Gust derivatives + //dgust_dx = gust_amp*2*PI_NUMBER*(cos(2*PI_NUMBER*x_gust))/L; + //dgust_dy = 0; + //dgust_dt = gust_amp*2*PI_NUMBER*(cos(2*PI_NUMBER*x_gust))*(-Uinf)/L; + } + break; + + case ONE_M_COSINE: + // Check if we are in the region where the gust is active + if (x_gust > 0 && x_gust < n) { + Gust[GustDir] = gust_amp*(1-cos(2*PI_NUMBER*x_gust)); + + // Gust derivatives + //dgust_dx = gust_amp*2*PI_NUMBER*(sin(2*PI_NUMBER*x_gust))/L; + //dgust_dy = 0; + //dgust_dt = gust_amp*2*PI_NUMBER*(sin(2*PI_NUMBER*x_gust))*(-Uinf)/L; + } + break; + + case EOG: + // Check if we are in the region where the gust is active + if (x_gust > 0 && x_gust < n) { + Gust[GustDir] = -0.37*gust_amp*sin(3*PI_NUMBER*x_gust)*(1-cos(2*PI_NUMBER*x_gust)); + } + break; + + case VORTEX: + + /*--- Use vortex distribution ---*/ + // Algebraic vortex equation. + for (unsigned long i=0; iGetNodes()->SetWindGust(iPoint, Gust); + solver[iMGlevel][FLOW_SOL]->GetNodes()->SetWindGustDer(iPoint, GustDer); + + GridVel = geometry[iMGlevel]->node[iPoint]->GetGridVel(); + + /*--- Store new grid velocity ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + NewGridVel[iDim] = GridVel[iDim] - Gust[iDim]; + geometry[iMGlevel]->node[iPoint]->SetGridVel(iDim, NewGridVel[iDim]); + } + + } + } + + delete [] Gust; + delete [] GustDer; + delete [] NewGridVel; + +} + +void CFluidIteration::InitializeVortexDistribution(unsigned long &nVortex, vector& x0, vector& y0, vector& vort_strength, vector& r_core) { + /*--- Read in Vortex Distribution ---*/ + std::string line; + std::ifstream file; + su2double x_temp, y_temp, vort_strength_temp, r_core_temp; + file.open("vortex_distribution.txt"); + /*--- In case there is no vortex file ---*/ + if (file.fail()) { + SU2_MPI::Error("There is no vortex data file!!", CURRENT_FUNCTION); + } + + // Ignore line containing the header + getline(file, line); + // Read in the information of the vortices (xloc, yloc, lambda(strength), eta(size, gradient)) + while (file.good()) + { + getline(file, line); + std::stringstream ss(line); + if (line.size() != 0) { //ignore blank lines if they exist. + ss >> x_temp; + ss >> y_temp; + ss >> vort_strength_temp; + ss >> r_core_temp; + x0.push_back(x_temp); + y0.push_back(y_temp); + vort_strength.push_back(vort_strength_temp); + r_core.push_back(r_core_temp); + } + } + file.close(); + // number of vortices + nVortex = x0.size(); + +} + +bool CFluidIteration::MonitorFixed_CL(COutput *output, CGeometry *geometry, CSolver **solver, CConfig *config) { + + CSolver* flow_solver= solver[FLOW_SOL]; + + bool fixed_cl_convergence = flow_solver->FixedCL_Convergence(config, output->GetConvergence()); + + /* --- If Fixed CL mode has ended and Finite Differencing has started: --- */ + + if (flow_solver->GetStart_AoA_FD() && flow_solver->GetIter_Update_AoA() == config->GetInnerIter()){ + + /* --- Print convergence history and volume files since fixed CL mode has converged--- */ + if (rank == MASTER_NODE) output->PrintConvergenceSummary(); + + output->SetResult_Files(geometry, config, solver, + config->GetInnerIter(), true); + + /* --- Set finite difference mode in config (disables output) --- */ + config->SetFinite_Difference_Mode(true); + } + + /* --- Set convergence based on fixed CL convergence --- */ + return fixed_cl_convergence; +} + +CFEMFluidIteration::CFEMFluidIteration(CConfig *config) : CFluidIteration(config) { } +CFEMFluidIteration::~CFEMFluidIteration(void) { } + +void CFEMFluidIteration::Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned long TimeIter = config[ZONE_0]->GetTimeIter(); + const bool restart = (config[ZONE_0]->GetRestart() || + config[ZONE_0]->GetRestart_Flow()); + + /*--- Set the initial condition if this is not a restart. ---*/ + if (TimeIter == 0 && !restart) + solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->SetInitialCondition(geometry[val_iZone][val_iInst], + solver[val_iZone][val_iInst], + config[val_iZone], + TimeIter); + +} + +void CFEMFluidIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + /*--- Update global parameters ---*/ + + if (config[val_iZone]->GetKind_Solver() == FEM_EULER || config[val_iZone]->GetKind_Solver() == DISC_ADJ_FEM_EULER) + config[val_iZone]->SetGlobalParam(FEM_EULER, RUNTIME_FLOW_SYS); + + if (config[val_iZone]->GetKind_Solver() == FEM_NAVIER_STOKES || config[val_iZone]->GetKind_Solver() == DISC_ADJ_FEM_NS) + config[val_iZone]->SetGlobalParam(FEM_NAVIER_STOKES, RUNTIME_FLOW_SYS); + + if (config[val_iZone]->GetKind_Solver() == FEM_RANS || config[val_iZone]->GetKind_Solver() == DISC_ADJ_FEM_RANS) + config[val_iZone]->SetGlobalParam(FEM_RANS, RUNTIME_FLOW_SYS); + + if (config[val_iZone]->GetKind_Solver() == FEM_LES) + config[val_iZone]->SetGlobalParam(FEM_LES, RUNTIME_FLOW_SYS); + + /*--- Solve the Euler, Navier-Stokes, RANS or LES equations (one iteration) ---*/ + + integration[val_iZone][val_iInst][FLOW_SOL]->SingleGrid_Iteration(geometry, + solver, + numerics, + config, + RUNTIME_FLOW_SYS, + val_iZone, + val_iInst); +} + +void CFEMFluidIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } + +void CFEMFluidIteration::Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst){} + +CHeatIteration::CHeatIteration(CConfig *config) : CFluidIteration(config) { } + +CHeatIteration::~CHeatIteration(void) { } + +void CHeatIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + /*--- Update global parameters ---*/ + + config[val_iZone]->SetGlobalParam(HEAT_EQUATION, RUNTIME_HEAT_SYS); + + integration[val_iZone][val_iInst][HEAT_SOL]->SingleGrid_Iteration(geometry, solver, numerics, config, RUNTIME_HEAT_SYS, val_iZone, val_iInst); + +} + +void CHeatIteration::Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + /*--- Boolean to determine if we are running a static or dynamic case ---*/ + bool steady = !config[val_iZone]->GetTime_Domain(); + + unsigned long Inner_Iter, nInner_Iter = config[val_iZone]->GetnInner_Iter(); + bool StopCalc = false; + + /*--- Synchronization point before a single solver iteration. + Compute the wall clock time required. ---*/ + +#ifndef HAVE_MPI + StartTime = su2double(clock())/su2double(CLOCKS_PER_SEC); +#else + StartTime = MPI_Wtime(); +#endif + + /*--- Preprocess the solver ---*/ + + Preprocess(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*--- For steady-state flow simulations, we need to loop over ExtIter for the number of time steps ---*/ + /*--- However, ExtIter is the number of FSI iterations, so nIntIter is used in this case ---*/ + + for (Inner_Iter = 0; Inner_Iter < nInner_Iter; Inner_Iter++){ + + config[val_iZone]->SetInnerIter(Inner_Iter); + + /*--- Run a single iteration of the solver ---*/ + Iterate(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*--- Monitor the pseudo-time ---*/ + StopCalc = Monitor(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*--- Output files at intermediate iterations if the problem is single zone ---*/ + + if (singlezone && steady) { + Output(output, geometry, solver, config, Inner_Iter, StopCalc, val_iZone, val_iInst); + } + + /*--- If the iteration has converged, break the loop ---*/ + if (StopCalc) break; + } + + if (multizone && steady) { + Output(output, geometry, solver, config, + config[val_iZone]->GetOuterIter(), + StopCalc, val_iZone, val_iInst); + + /*--- Set the fluid convergence to false (to make sure outer subiterations converge) ---*/ + + integration[val_iZone][INST_0][HEAT_SOL]->SetConvergence(false); + } +} + +void CHeatIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned short iMesh; + + /*--- Dual time stepping strategy ---*/ + + if ((config[val_iZone]->GetTime_Marching() == DT_STEPPING_1ST) || + (config[val_iZone]->GetTime_Marching() == DT_STEPPING_2ND)) { + + /*--- Update dual time solver ---*/ + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + integration[val_iZone][val_iInst][HEAT_SOL]->SetDualTime_Solver(geometry[val_iZone][val_iInst][iMesh], solver[val_iZone][val_iInst][iMesh][HEAT_SOL], config[val_iZone], iMesh); + integration[val_iZone][val_iInst][HEAT_SOL]->SetConvergence(false); + } + } +} + +CFEAIteration::CFEAIteration(CConfig *config) : CIteration(config) { } +CFEAIteration::~CFEAIteration(void) { } +void CFEAIteration::Preprocess() { } +void CFEAIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst + ) { + + su2double loadIncrement; + unsigned long IntIter = 0; + unsigned long TimeIter = config[val_iZone]->GetTimeIter(); + bool StopCalc; + unsigned long iIncrement; + unsigned long nIncrements = config[val_iZone]->GetNumberIncrements(); + + bool nonlinear = (config[val_iZone]->GetGeometricConditions() == LARGE_DEFORMATIONS); // Geometrically non-linear problems + bool linear = (config[val_iZone]->GetGeometricConditions() == SMALL_DEFORMATIONS); // Geometrically non-linear problems + + bool disc_adj_fem = (config[val_iZone]->GetKind_Solver() == DISC_ADJ_FEM); + + bool incremental_load = config[val_iZone]->GetIncrementalLoad(); // If an incremental load is applied + + /*--- This is to prevent problems when running a linear solver ---*/ + if (!nonlinear) incremental_load = false; + + /*--- Set the convergence monitor to false, to prevent the solver to stop in intermediate FSI subiterations ---*/ + integration[val_iZone][val_iInst][FEA_SOL]->SetConvergence(false); + + if (linear) { + + config[val_iZone]->SetInnerIter(0); + + /*--- FEA equations ---*/ + + config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); + + /*--- Run the iteration ---*/ + + integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, + config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + + if (!disc_adj_fem){ + Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*--- Set the convergence monitor to true, to prevent the solver to stop in intermediate FSI subiterations ---*/ + output->SetConvergence(true); + } + + } + /*--- If the structure is held static and the solver is nonlinear, we don't need to solve for static time, but we need to compute Mass Matrix and Integration constants ---*/ + else if (nonlinear) { + + /*--- THIS IS THE DIRECT APPROACH (NO INCREMENTAL LOAD APPLIED) ---*/ + + if (!incremental_load) { + + /*--- Keep the current inner iter, we need to restore it in discrete adjoint cases as file output depends on it ---*/ + unsigned long CurIter = config[val_iZone]->GetInnerIter(); + + IntIter = 0; + config[val_iZone]->SetInnerIter(IntIter); + + /*--- FEA equations ---*/ + + config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); + + /*--- Run the iteration ---*/ + + integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, + config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + + if (!disc_adj_fem) + Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*----------------- If the solver is non-linear, we need to subiterate using a Newton-Raphson approach ----------------------*/ + + for (IntIter = 1; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { + + /*--- Limit to only one iteration for the discrete adjoint recording, restore inner iter (see above) ---*/ + if (disc_adj_fem) { + config[val_iZone]->SetInnerIter(CurIter); + break; + } + + config[val_iZone]->SetInnerIter(IntIter); + + integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, + config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + + StopCalc = Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + + if (StopCalc) break; + + } + + } + /*--- The incremental load is only used in nonlinear cases ---*/ + else if (incremental_load) { + + /*--- Set the initial condition: store the current solution as Solution_Old ---*/ + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->SetInitialCondition(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], TimeIter); + + /*--- The load increment is 1.0 ---*/ + + loadIncrement = 1.0; + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->SetLoad_Increment(loadIncrement); + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->SetForceCoeff(loadIncrement); + + /*--- Set the value of the internal iteration ---*/ + + IntIter = 0; + config[val_iZone]->SetInnerIter(IntIter); + + /*--- FEA equations ---*/ + + config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); + + /*--- Run the first iteration ---*/ + + integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, + config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + + /*--- Write the convergence history (first, compute Von Mises stress) ---*/ + + Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + /*--- Run the second iteration ---*/ + + IntIter = 1; + config[val_iZone]->SetInnerIter(IntIter); + + integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, + config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + + /*--- Write the convergence history (first, compute Von Mises stress) ---*/ + Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + bool meetCriteria; + su2double Residual_UTOL, Residual_RTOL, Residual_ETOL; + su2double Criteria_UTOL, Criteria_RTOL, Criteria_ETOL; + + Criteria_UTOL = config[val_iZone]->GetIncLoad_Criteria(0); + Criteria_RTOL = config[val_iZone]->GetIncLoad_Criteria(1); + Criteria_ETOL = config[val_iZone]->GetIncLoad_Criteria(2); + + Residual_UTOL = log10(solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LinSysSol.norm()); + Residual_RTOL = log10(solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LinSysRes.norm()); + Residual_ETOL = log10(solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LinSysSol.dot( + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LinSysRes)); + + meetCriteria = ( ( Residual_UTOL < Criteria_UTOL ) && + ( Residual_RTOL < Criteria_RTOL ) && + ( Residual_ETOL < Criteria_ETOL ) ); + + /*--- If the criteria is met and the load is not "too big", do the regular calculation ---*/ + if (meetCriteria) { + + for (IntIter = 2; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { + + integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, + config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + + /*--- Write the convergence history (first, compute Von Mises stress) ---*/ + StopCalc = Monitor(output, integration, geometry, solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + if (StopCalc) break; + + } + + } + + /*--- If the criteria is not met, a whole set of subiterations for the different loads must be done ---*/ + + else { + + /*--- Here we have to restart the solution to the original one of the iteration ---*/ + /*--- Retrieve the Solution_Old as the current solution before subiterating ---*/ + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->ResetInitialCondition(geometry[val_iZone][val_iInst], + solver[val_iZone][val_iInst], config[val_iZone], TimeIter); + + /*--- For the number of increments ---*/ + for (iIncrement = 0; iIncrement < nIncrements; iIncrement++) { + + loadIncrement = (iIncrement + 1.0) * (1.0 / nIncrements); + + /*--- Set the load increment and the initial condition, and output the parameters of UTOL, RTOL, ETOL for the previous iteration ---*/ + + /*--- Set the convergence monitor to false, to force se solver to converge every subiteration ---*/ + output->SetConvergence(false); + + /*--- FEA equations ---*/ + + config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->SetLoad_Increment(loadIncrement); + + if (rank == MASTER_NODE) { + cout << endl; + cout << "Incremental load: increment " << iIncrement + 1 << endl; + } + + /*--- Set the value of the internal iteration ---*/ + IntIter = 0; + config[val_iZone]->SetInnerIter(IntIter); + + /*--- FEA equations ---*/ + + config[val_iZone]->SetGlobalParam(FEM_ELASTICITY, RUNTIME_FEA_SYS); + + /*--- Run the iteration ---*/ + + integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, + config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + + Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + + /*----------------- If the solver is non-linear, we need to subiterate using a Newton-Raphson approach ----------------------*/ + + for (IntIter = 1; IntIter < config[val_iZone]->GetnInner_Iter(); IntIter++) { + + config[val_iZone]->SetInnerIter(IntIter); + + integration[val_iZone][val_iInst][FEA_SOL]->Structural_Iteration(geometry, solver, numerics, + config, RUNTIME_FEA_SYS, val_iZone, val_iInst); + + /*--- Write the convergence history (first, compute Von Mises stress) ---*/ + StopCalc = Monitor(output, integration, geometry, solver, numerics, config, surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + if (StopCalc) break; + + } + + } + + } + + } + + } + + /*--- Finally, we need to compute the objective function, in case that we are running a discrete adjoint solver... ---*/ + + switch (config[val_iZone]->GetKind_ObjFunc()){ + case REFERENCE_GEOMETRY: + if ((config[val_iZone]->GetDV_FEA() == YOUNG_MODULUS) || (config[val_iZone]->GetDV_FEA() == DENSITY_VAL)){ + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Stiffness_Penalty(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], + numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); + } + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_OFRefGeom(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + break; + case REFERENCE_NODE: + if ((config[val_iZone]->GetDV_FEA() == YOUNG_MODULUS) || (config[val_iZone]->GetDV_FEA() == DENSITY_VAL)){ + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Stiffness_Penalty(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], + numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); + } + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_OFRefNode(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + break; + case VOLUME_FRACTION: + case TOPOL_DISCRETENESS: + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_OFVolFrac(geometry[val_iZone][val_iInst][MESH_0],solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + break; + case TOPOL_COMPLIANCE: + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_OFCompliance(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + break; + } + +} + +void CFEAIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + su2double Physical_dt, Physical_t; + unsigned long TimeIter = config[val_iZone]->GetTimeIter(); + bool dynamic = (config[val_iZone]->GetTime_Domain()); // Dynamic problems + bool static_fem = (!config[val_iZone]->GetTime_Domain()); // Static problems + bool fsi = config[val_iZone]->GetFSI_Simulation(); // Fluid-Structure Interaction problems + + /*----------------- Compute averaged nodal stress and reactions ------------------------*/ + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_NodalStress(geometry[val_iZone][val_iInst][MESH_0], numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); + + /*----------------- Update structural solver ----------------------*/ + + if (dynamic) { + + integration[val_iZone][val_iInst][FEA_SOL]->SetStructural_Solver(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone], MESH_0); + integration[val_iZone][val_iInst][FEA_SOL]->SetConvergence(false); + + /*--- Verify convergence criteria (based on total time) ---*/ + + Physical_dt = config[val_iZone]->GetDelta_DynTime(); + Physical_t = (TimeIter+1)*Physical_dt; + if (Physical_t >= config[val_iZone]->GetTotal_DynTime()) + integration[val_iZone][val_iInst][FEA_SOL]->SetConvergence(true); + + } else if ( static_fem && fsi) { + + /*--- For FSI problems, output the relaxed result, which is the one transferred into the fluid domain (for restart purposes) ---*/ + switch (config[val_iZone]->GetKind_TimeIntScheme_FEA()) { + case (NEWMARK_IMPLICIT): + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->ImplicitNewmark_Relaxation(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone]); + break; + } + } + +} + +void CFEAIteration::Predictor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + /*--- Predict displacements ---*/ + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->PredictStruct_Displacement(geometry[val_iZone][val_iInst], config[val_iZone], + solver[val_iZone][val_iInst]); + + /*--- For parallel simulations we need to communicate the predicted solution before updating the fluid mesh ---*/ + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->InitiateComms(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], SOLUTION_PRED); + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->CompleteComms(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], SOLUTION_PRED); + +} +void CFEAIteration::Relaxation(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned long OuterIter = config[val_iZone]->GetOuterIter(); + + /*-------------------- Aitken's relaxation ------------------------*/ + + /*------------------- Compute the coefficient ---------------------*/ + + solver[val_iZone][INST_0][MESH_0][FEA_SOL]->ComputeAitken_Coefficient(geometry[val_iZone][INST_0], config[val_iZone], + solver[val_iZone][INST_0], OuterIter); + + /*----------------- Set the relaxation parameter ------------------*/ + + solver[val_iZone][INST_0][MESH_0][FEA_SOL]->SetAitken_Relaxation(geometry[val_iZone][INST_0], config[val_iZone], + solver[val_iZone][INST_0]); + + /*----------------- Communicate the predicted solution and the old one ------------------*/ + + solver[val_iZone][INST_0][MESH_0][FEA_SOL]->InitiateComms(geometry[val_iZone][INST_0][MESH_0], config[val_iZone], SOLUTION_PRED_OLD); + solver[val_iZone][INST_0][MESH_0][FEA_SOL]->CompleteComms(geometry[val_iZone][INST_0][MESH_0], config[val_iZone], SOLUTION_PRED_OLD); + +} + +bool CFEAIteration::Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + bool StopCalc = false; + +#ifndef HAVE_MPI + StopTime = su2double(clock())/su2double(CLOCKS_PER_SEC); +#else + StopTime = MPI_Wtime(); +#endif + UsedTime = StopTime - StartTime; + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->Compute_NodalStress(geometry[val_iZone][val_iInst][MESH_0], + numerics[val_iZone][val_iInst][MESH_0][FEA_SOL], config[val_iZone]); + + if (config[val_iZone]->GetMultizone_Problem() || config[val_iZone]->GetSinglezone_Driver()){ + output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], solver[val_iZone][INST_0][MESH_0], config[val_iZone], + config[val_iZone]->GetTimeIter(), config[val_iZone]->GetOuterIter(), config[val_iZone]->GetInnerIter()); + } + + StopCalc = output->GetConvergence(); + + return StopCalc; + +} + +void CFEAIteration::Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } + +void CFEAIteration::Solve(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst + ) { + + /*------------------ Structural subiteration ----------------------*/ + Iterate(output, integration, geometry, + solver, numerics, config, + surface_movement, grid_movement, FFDBox, val_iZone, INST_0); + + + /*--- Write the convergence history for the structure (only screen output) ---*/ +// if (multizone) output->SetConvHistory_Body(geometry, solver, config, integration, false, 0.0, val_iZone, INST_0); + + /*--- Set the structural convergence to false (to make sure outer subiterations converge) ---*/ + integration[val_iZone][INST_0][FEA_SOL]->SetConvergence(false); + +} + +CAdjFluidIteration::CAdjFluidIteration(CConfig *config) : CFluidIteration(config) { } +CAdjFluidIteration::~CAdjFluidIteration(void) { } +void CAdjFluidIteration::Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned short iMesh; + bool harmonic_balance = (config[ZONE_0]->GetTime_Marching() == HARMONIC_BALANCE); + bool dynamic_mesh = config[ZONE_0]->GetGrid_Movement(); + unsigned long InnerIter = 0; + unsigned long TimeIter = config[ZONE_0]->GetTimeIter(); + + /*--- For the unsteady adjoint, load a new direct solution from a restart file. ---*/ + + if (((dynamic_mesh && TimeIter == 0) || config[val_iZone]->GetTime_Marching()) && !harmonic_balance) { + int Direct_Iter = SU2_TYPE::Int(config[val_iZone]->GetUnst_AdjointIter()) - SU2_TYPE::Int(TimeIter) - 1; + if (rank == MASTER_NODE && val_iZone == ZONE_0 && config[val_iZone]->GetTime_Marching()) + cout << endl << " Loading flow solution from direct iteration " << Direct_Iter << "." << endl; + solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->LoadRestart(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], Direct_Iter, true); + } + + /*--- Continuous adjoint Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations ---*/ + + if ((InnerIter == 0) || config[val_iZone]->GetTime_Marching()) { + + if (config[val_iZone]->GetKind_Solver() == ADJ_EULER) + config[val_iZone]->SetGlobalParam(ADJ_EULER, RUNTIME_FLOW_SYS); + if (config[val_iZone]->GetKind_Solver() == ADJ_NAVIER_STOKES) + config[val_iZone]->SetGlobalParam(ADJ_NAVIER_STOKES, RUNTIME_FLOW_SYS); + if (config[val_iZone]->GetKind_Solver() == ADJ_RANS) + config[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_FLOW_SYS); + + /*--- Solve the Euler, Navier-Stokes or Reynolds-averaged Navier-Stokes (RANS) equations (one iteration) ---*/ + + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << "Begin direct solver to store flow data (single iteration)." << endl; + + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << "Compute residuals to check the convergence of the direct problem." << endl; + + integration[val_iZone][val_iInst][FLOW_SOL]->MultiGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_FLOW_SYS, val_iZone, val_iInst); + + if (config[val_iZone]->GetKind_Solver() == ADJ_RANS) { + + /*--- Solve the turbulence model ---*/ + + config[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_TURB_SYS); + integration[val_iZone][val_iInst][TURB_SOL]->SingleGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_TURB_SYS, val_iZone, val_iInst); + + /*--- Solve transition model ---*/ + + if (config[val_iZone]->GetKind_Trans_Model() == LM) { + config[val_iZone]->SetGlobalParam(RANS, RUNTIME_TRANS_SYS); + integration[val_iZone][val_iInst][TRANS_SOL]->SingleGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_TRANS_SYS, val_iZone, val_iInst); + } + + } + + /*--- Output the residual (visualization purpouses to identify if + the direct solution is converged)---*/ + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << "log10[Maximum residual]: " << log10(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->GetRes_Max(0)) + <<", located at point "<< solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->GetPoint_Max(0) << "." << endl; + + /*--- Compute gradients of the flow variables, this is necessary for sensitivity computation, + note that in the direct Euler problem we are not computing the gradients of the primitive variables ---*/ + + if (config[val_iZone]->GetKind_Gradient_Method() == GREEN_GAUSS) + solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->SetPrimitive_Gradient_GG(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + if (config[val_iZone]->GetKind_Gradient_Method() == WEIGHTED_LEAST_SQUARES) + solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->SetPrimitive_Gradient_LS(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + + /*--- Set contribution from cost function for boundary conditions ---*/ + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + + /*--- Set the value of the non-dimensional coefficients in the coarse levels, using the fine level solution ---*/ + + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->SetTotal_CD(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->GetTotal_CD()); + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->SetTotal_CL(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->GetTotal_CL()); + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->SetTotal_CT(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->GetTotal_CT()); + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->SetTotal_CQ(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->GetTotal_CQ()); + + /*--- Compute the adjoint boundary condition on Euler walls ---*/ + + solver[val_iZone][val_iInst][iMesh][ADJFLOW_SOL]->SetForceProj_Vector(geometry[val_iZone][val_iInst][iMesh], solver[val_iZone][val_iInst][iMesh], config[val_iZone]); + + /*--- Set the internal boundary condition on nearfield surfaces ---*/ + + if ((config[val_iZone]->GetKind_ObjFunc() == EQUIVALENT_AREA) || + (config[val_iZone]->GetKind_ObjFunc() == NEARFIELD_PRESSURE)) + solver[val_iZone][val_iInst][iMesh][ADJFLOW_SOL]->SetIntBoundary_Jump(geometry[val_iZone][val_iInst][iMesh], solver[val_iZone][val_iInst][iMesh], config[val_iZone]); + + } + + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << "End direct solver, begin adjoint problem." << endl; + + } + +} +void CAdjFluidIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + switch( config[val_iZone]->GetKind_Solver() ) { + + case ADJ_EULER: + config[val_iZone]->SetGlobalParam(ADJ_EULER, RUNTIME_ADJFLOW_SYS); break; + + case ADJ_NAVIER_STOKES: + config[val_iZone]->SetGlobalParam(ADJ_NAVIER_STOKES, RUNTIME_ADJFLOW_SYS); break; + + case ADJ_RANS: + config[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_ADJFLOW_SYS); break; + } + + /*--- Iteration of the flow adjoint problem ---*/ + + integration[val_iZone][val_iInst][ADJFLOW_SOL]->MultiGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_ADJFLOW_SYS, val_iZone, val_iInst); + + /*--- Iteration of the turbulence model adjoint ---*/ + + if ((config[val_iZone]->GetKind_Solver() == ADJ_RANS) && (!config[val_iZone]->GetFrozen_Visc_Cont())) { + + /*--- Adjoint turbulence model solution ---*/ + + config[val_iZone]->SetGlobalParam(ADJ_RANS, RUNTIME_ADJTURB_SYS); + integration[val_iZone][val_iInst][ADJTURB_SOL]->SingleGrid_Iteration(geometry, solver, numerics, + config, RUNTIME_ADJTURB_SYS, val_iZone, val_iInst); + + } + +} +void CAdjFluidIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + su2double Physical_dt, Physical_t; + unsigned short iMesh; + unsigned long TimeIter = config[ZONE_0]->GetTimeIter(); + + /*--- Dual time stepping strategy ---*/ + + if ((config[val_iZone]->GetTime_Marching() == DT_STEPPING_1ST) || + (config[val_iZone]->GetTime_Marching() == DT_STEPPING_2ND)) { + + /*--- Update dual time solver ---*/ + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + integration[val_iZone][val_iInst][ADJFLOW_SOL]->SetDualTime_Solver(geometry[val_iZone][val_iInst][iMesh], solver[val_iZone][val_iInst][iMesh][ADJFLOW_SOL], config[val_iZone], iMesh); + integration[val_iZone][val_iInst][ADJFLOW_SOL]->SetConvergence(false); + } + + Physical_dt = config[val_iZone]->GetDelta_UnstTime(); Physical_t = (TimeIter+1)*Physical_dt; + if (Physical_t >= config[val_iZone]->GetTotal_UnstTime()) integration[val_iZone][val_iInst][ADJFLOW_SOL]->SetConvergence(true); + + } +} + + +CDiscAdjFluidIteration::CDiscAdjFluidIteration(CConfig *config) : CIteration(config) { + + turbulent = ( config->GetKind_Solver() == DISC_ADJ_RANS || config->GetKind_Solver() == DISC_ADJ_INC_RANS); + +} + +CDiscAdjFluidIteration::~CDiscAdjFluidIteration(void) { } + +void CDiscAdjFluidIteration::Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + +#ifndef HAVE_MPI + StartTime = su2double(clock())/su2double(CLOCKS_PER_SEC); +#else + StartTime = MPI_Wtime(); +#endif + + unsigned long iPoint; + unsigned short TimeIter = config[val_iZone]->GetTimeIter(); + bool dual_time_1st = (config[val_iZone]->GetTime_Marching() == DT_STEPPING_1ST); + bool dual_time_2nd = (config[val_iZone]->GetTime_Marching() == DT_STEPPING_2ND); + bool dual_time = (dual_time_1st || dual_time_2nd); + unsigned short iMesh; + int Direct_Iter; + bool heat = config[val_iZone]->GetWeakly_Coupled_Heat(); + bool grid_IsMoving = config[val_iZone]->GetGrid_Movement(); + +// /*--- Read the target pressure for inverse design. ---------------------------------------------*/ +// if (config[val_iZone]->GetInvDesign_Cp() == YES) +// output->SetCp_InverseDesign(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL], geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], ExtIter); + +// /*--- Read the target heat flux ----------------------------------------------------------------*/ +// if (config[ZONE_0]->GetInvDesign_HeatFlux() == YES) +// output->SetHeatFlux_InverseDesign(solver[val_iZone][val_iInst][MESH_0][FLOW_SOL], geometry[val_iZone][val_iInst][MESH_0], config[val_iZone], ExtIter); + + /*--- For the unsteady adjoint, load direct solutions from restart files. ---*/ + + if (config[val_iZone]->GetTime_Marching()) { + + Direct_Iter = SU2_TYPE::Int(config[val_iZone]->GetUnst_AdjointIter()) - SU2_TYPE::Int(TimeIter) - 2; + + /*--- For dual-time stepping we want to load the already converged solution at timestep n ---*/ + + if (dual_time) { + Direct_Iter += 1; + } + + if (TimeIter == 0){ + + if (dual_time_2nd) { + + /*--- Load solution at timestep n-2 ---*/ + LoadUnsteady_Solution(geometry, solver,config, val_iZone, val_iInst, Direct_Iter-2); + + /*--- Push solution back to correct array ---*/ + + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(); + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n1(); + if (turbulent) { + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(); + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n1(); + } + if (heat) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n(); + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n1(); + } + if (grid_IsMoving) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->SetCoord_n(); + geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->SetCoord_n1(); + } + } + } + } + if (dual_time) { + + /*--- Load solution at timestep n-1 ---*/ + LoadUnsteady_Solution(geometry, solver,config, val_iZone, val_iInst, Direct_Iter-1); + + /*--- Push solution back to correct array ---*/ + + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(); + if (turbulent) { + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(); + } + if (heat) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n(); + } + if (grid_IsMoving) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->SetCoord_n(); + } + } + } + } + + /*--- Load solution timestep n ---*/ + + LoadUnsteady_Solution(geometry, solver,config, val_iInst, val_iZone, Direct_Iter); + + } else if ((TimeIter > 0) && dual_time) { + + /*--- + Here the primal solutions (only working variables) are loaded and put in the correct order + into containers. For ALE the mesh coordinates have to be put into the + correct containers as well, i.e. follow the same logic for the solution. + Afterwards the GridVelocity is computed based on the Coordinates. + ---*/ + + /*--- Load solution timestep n-1 | n-2 for DualTimestepping 1st | 2nd order ---*/ + if (dual_time_1st){ + LoadUnsteady_Solution(geometry, solver,config, val_iInst, val_iZone, Direct_Iter - 1); + } else { + LoadUnsteady_Solution(geometry, solver,config, val_iInst, val_iZone, Direct_Iter - 2); + } + + + /*--- Temporarily store the loaded solution in the Solution_Old array ---*/ + + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->Set_OldSolution(); + if (turbulent) { + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->Set_OldSolution(); + } + if (heat) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_OldSolution(); + } + if (grid_IsMoving) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->SetCoord_Old(); + } + } + } + + /*--- Set Solution at timestep n to solution at n-1 ---*/ + + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->SetSolution(iPoint, solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->GetSolution_time_n(iPoint)); + + if (grid_IsMoving) { + geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->SetCoord(geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->GetCoord_n()); + } + if (turbulent) { + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->SetSolution(iPoint, solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->GetSolution_time_n(iPoint)); + } + if (heat) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->SetSolution(iPoint, solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->GetSolution_time_n(iPoint)); + } + } + } + if (dual_time_1st){ + /*--- Set Solution at timestep n-1 to the previously loaded solution ---*/ + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->GetSolution_Old(iPoint)); + + if (grid_IsMoving) { + geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->SetCoord_n(geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->GetCoord_Old()); + } + if (turbulent) { + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->GetSolution_Old(iPoint)); + } + if (heat) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->GetSolution_Old(iPoint)); + } + } + } + } + if (dual_time_2nd){ + /*--- Set Solution at timestep n-1 to solution at n-2 ---*/ + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); + + if (grid_IsMoving) { + geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->SetCoord_n(geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->GetCoord_n1()); + } + if (turbulent) { + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); + } + if (heat) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); + } + } + } + /*--- Set Solution at timestep n-2 to the previously loaded solution ---*/ + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n1(iPoint, solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->GetSolution_Old(iPoint)); + + if (grid_IsMoving) { + geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->SetCoord_n1(geometry[val_iZone][val_iInst][iMesh]->node[iPoint]->GetCoord_Old()); + } + if (turbulent) { + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n1(iPoint, solver[val_iZone][val_iInst][iMesh][TURB_SOL]->GetNodes()->GetSolution_Old(iPoint)); + } + if (heat) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n1(iPoint, solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->GetSolution_Old(iPoint)); + } + } + } + } + + }//else if Ext_Iter > 0 + + /*--- Compute & set Grid Velocity via finite differences of the Coordinates. ---*/ + if (grid_IsMoving) + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) + geometry[val_iZone][val_iInst][iMesh]->SetGridVelocity(config[val_iZone], TimeIter); + + }//if unsteady + + /*--- Store flow solution also in the adjoint solver in order to be able to reset it later ---*/ + + if (TimeIter == 0 || dual_time) { + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][iMesh]->GetnPoint(); iPoint++) { + solver[val_iZone][val_iInst][iMesh][ADJFLOW_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->GetNodes()->GetSolution(iPoint)); + } + } + if (turbulent && !config[val_iZone]->GetFrozen_Visc_Disc()) { + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++) { + solver[val_iZone][val_iInst][MESH_0][ADJTURB_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver[val_iZone][val_iInst][MESH_0][TURB_SOL]->GetNodes()->GetSolution(iPoint)); + } + } + if (heat) { + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++) { + solver[val_iZone][val_iInst][MESH_0][ADJHEAT_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver[val_iZone][val_iInst][MESH_0][HEAT_SOL]->GetNodes()->GetSolution(iPoint)); + } + } + if (config[val_iZone]->AddRadiation()) { + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++) { + solver[val_iZone][val_iInst][MESH_0][ADJRAD_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver[val_iZone][val_iInst][MESH_0][RAD_SOL]->GetNodes()->GetSolution(iPoint)); + } + } + } + + solver[val_iZone][val_iInst][MESH_0][ADJFLOW_SOL]->Preprocessing(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone] , MESH_0, 0, RUNTIME_ADJFLOW_SYS, false); + if (turbulent && !config[val_iZone]->GetFrozen_Visc_Disc()){ + solver[val_iZone][val_iInst][MESH_0][ADJTURB_SOL]->Preprocessing(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone] , MESH_0, 0, RUNTIME_ADJTURB_SYS, false); + } + if (heat) { + solver[val_iZone][val_iInst][MESH_0][ADJHEAT_SOL]->Preprocessing(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone] , MESH_0, 0, RUNTIME_ADJHEAT_SYS, false); + } + if (config[val_iZone]->AddRadiation()){ + solver[val_iZone][val_iInst][MESH_0][ADJRAD_SOL]->Preprocessing(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone] , MESH_0, 0, RUNTIME_ADJRAD_SYS, false); + } + +} + + + +void CDiscAdjFluidIteration::LoadUnsteady_Solution(CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + int val_DirectIter) { + unsigned short iMesh; + bool heat = config[val_iZone]->GetWeakly_Coupled_Heat(); + + if (val_DirectIter >= 0) { + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << " Loading flow solution from direct iteration " << val_DirectIter << "." << endl; + solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->LoadRestart(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], val_DirectIter, true); + if (turbulent) { + solver[val_iZone][val_iInst][MESH_0][TURB_SOL]->LoadRestart(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], val_DirectIter, false); + } + if (heat) { + solver[val_iZone][val_iInst][MESH_0][HEAT_SOL]->LoadRestart(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], val_DirectIter, false); + } + } else { + /*--- If there is no solution file we set the freestream condition ---*/ + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << " Setting freestream conditions at direct iteration " << val_DirectIter << "." << endl; + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->SetFreeStream_Solution(config[val_iZone]); + solver[val_iZone][val_iInst][iMesh][FLOW_SOL]->Preprocessing(geometry[val_iZone][val_iInst][iMesh],solver[val_iZone][val_iInst][iMesh], config[val_iZone], iMesh, val_DirectIter, RUNTIME_FLOW_SYS, false); + if (turbulent) { + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->SetFreeStream_Solution(config[val_iZone]); + solver[val_iZone][val_iInst][iMesh][TURB_SOL]->Postprocessing(geometry[val_iZone][val_iInst][iMesh],solver[val_iZone][val_iInst][iMesh], config[val_iZone], iMesh); + } + if (heat) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->SetFreeStream_Solution(config[val_iZone]); + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->Postprocessing(geometry[val_iZone][val_iInst][iMesh],solver[val_iZone][val_iInst][iMesh], config[val_iZone], iMesh); + } + } + } +} + + +void CDiscAdjFluidIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***volume_grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned short Kind_Solver = config[val_iZone]->GetKind_Solver(); + bool frozen_visc = config[val_iZone]->GetFrozen_Visc_Disc(); + bool heat = config[val_iZone]->GetWeakly_Coupled_Heat(); + + + /*--- Extract the adjoints of the conservative input variables and store them for the next iteration ---*/ + + if ((Kind_Solver == DISC_ADJ_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_RANS) || (Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_INC_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_INC_RANS) || (Kind_Solver == DISC_ADJ_INC_EULER)) { + + solver[val_iZone][val_iInst][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Solution(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + + solver[val_iZone][val_iInst][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Variables(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + + } + if (turbulent && !frozen_visc) { + + solver[val_iZone][val_iInst][MESH_0][ADJTURB_SOL]->ExtractAdjoint_Solution(geometry[val_iZone][val_iInst][MESH_0], + config[val_iZone]); + } + if (heat) { + + solver[val_iZone][val_iInst][MESH_0][ADJHEAT_SOL]->ExtractAdjoint_Solution(geometry[val_iZone][val_iInst][MESH_0], + config[val_iZone]); + } + if (config[val_iZone]->AddRadiation()) { + + solver[val_iZone][val_iInst][MESH_0][ADJRAD_SOL]->ExtractAdjoint_Solution(geometry[val_iZone][val_iInst][MESH_0], + config[val_iZone]); + + solver[val_iZone][val_iInst][MESH_0][ADJRAD_SOL]->ExtractAdjoint_Variables(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + + } +} + + +void CDiscAdjFluidIteration::InitializeAdjoint(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst){ + + unsigned short Kind_Solver = config[iZone]->GetKind_Solver(); + bool frozen_visc = config[iZone]->GetFrozen_Visc_Disc(); + bool heat = config[iZone]->GetWeakly_Coupled_Heat(); + bool interface_boundary = (config[iZone]->GetnMarker_Fluid_Load() > 0); + + /*--- Initialize the adjoints the conservative variables ---*/ + + if ((Kind_Solver == DISC_ADJ_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_RANS) || (Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_INC_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_INC_RANS) || (Kind_Solver == DISC_ADJ_INC_EULER)) { + + solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], config[iZone]); + } + + if (turbulent && !frozen_visc) { + solver[iZone][iInst][MESH_0][ADJTURB_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], config[iZone]); + } + + if (heat) { + solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], config[iZone]); + } + + if (config[iZone]->AddRadiation()) { + solver[iZone][iInst][MESH_0][ADJRAD_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], config[iZone]); + } + + if (interface_boundary) { + solver[iZone][iInst][MESH_0][FLOW_SOL]->SetVertexTractionsAdjoint(geometry[iZone][iInst][MESH_0], config[iZone]); + } + +} + + +void CDiscAdjFluidIteration::RegisterInput(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst, unsigned short kind_recording){ + + unsigned short Kind_Solver = config[iZone]->GetKind_Solver(); + bool frozen_visc = config[iZone]->GetFrozen_Visc_Disc(); + bool heat = config[iZone]->GetWeakly_Coupled_Heat(); + + if (kind_recording == FLOW_CONS_VARS || kind_recording == COMBINED){ + + /*--- Register flow and turbulent variables as input ---*/ + + if ((Kind_Solver == DISC_ADJ_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_RANS) || (Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_INC_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_INC_RANS) || (Kind_Solver == DISC_ADJ_INC_EULER)) { + + solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + + solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->RegisterVariables(geometry[iZone][iInst][MESH_0], config[iZone]); + } + + if (turbulent && !frozen_visc) { + solver[iZone][iInst][MESH_0][ADJTURB_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + } + if (heat) { + solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + } + if (config[iZone]->AddRadiation()) { + solver[iZone][iInst][MESH_0][ADJRAD_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + + solver[iZone][iInst][MESH_0][ADJRAD_SOL]->RegisterVariables(geometry[iZone][iInst][MESH_0], config[iZone]); + } + } + if (kind_recording == MESH_COORDS){ + + /*--- Register node coordinates as input ---*/ + + geometry[iZone][iInst][MESH_0]->RegisterCoordinates(config[iZone]); + + } + + if (kind_recording == FLOW_CROSS_TERM){ + + /*--- Register flow and turbulent variables as input ---*/ + + solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + + if (turbulent && !frozen_visc){ + solver[iZone][iInst][MESH_0][ADJTURB_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + } + if (config[iZone]->AddRadiation()) { + solver[iZone][iInst][MESH_0][ADJRAD_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + } + } + + if (kind_recording == GEOMETRY_CROSS_TERM){ + + /*--- Register node coordinates as input ---*/ + + geometry[iZone][iInst][MESH_0]->RegisterCoordinates(config[iZone]); + + } + + /*--- Register the variables of the mesh deformation ---*/ + if (kind_recording == MESH_DEFORM){ + + /*--- Undeformed mesh coordinates ---*/ + solver[iZone][iInst][MESH_0][ADJMESH_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + + /*--- Boundary displacements ---*/ + solver[iZone][iInst][MESH_0][ADJMESH_SOL]->RegisterVariables(geometry[iZone][iInst][MESH_0], config[iZone]); + + } + +} + +void CDiscAdjFluidIteration::SetRecording(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording) { + + unsigned short iMesh; + + /*--- Prepare for recording by resetting the solution to the initial converged solution ---*/ + + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->SetRecording(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++){ + solver[val_iZone][val_iInst][iMesh][ADJFLOW_SOL]->SetRecording(geometry[val_iZone][val_iInst][iMesh], config[val_iZone]); + } + if ((config[val_iZone]->GetKind_Solver() == DISC_ADJ_RANS || config[val_iZone]->GetKind_Solver() == DISC_ADJ_INC_RANS) && !config[val_iZone]->GetFrozen_Visc_Disc()) { + solver[val_iZone][val_iInst][MESH_0][ADJTURB_SOL]->SetRecording(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + } + if (config[val_iZone]->GetWeakly_Coupled_Heat()) { + solver[val_iZone][val_iInst][MESH_0][ADJHEAT_SOL]->SetRecording(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + } + if (config[val_iZone]->GetKind_RadiationModel() != NONE) { + solver[val_iZone][INST_0][MESH_0][ADJRAD_SOL]->SetRecording(geometry[val_iZone][INST_0][MESH_0], config[val_iZone]); + } + +} + +void CDiscAdjFluidIteration::SetDependencies(CSolver *****solver, + CGeometry ****geometry, + CNumerics ******numerics, + CConfig **config, + unsigned short iZone, + unsigned short iInst, + unsigned short kind_recording){ + + bool frozen_visc = config[iZone]->GetFrozen_Visc_Disc(); + bool heat = config[iZone]->GetWeakly_Coupled_Heat(); + if ((kind_recording == MESH_COORDS) || (kind_recording == NONE) || + (kind_recording == GEOMETRY_CROSS_TERM) || (kind_recording == ALL_VARIABLES)){ + + /*--- Update geometry to get the influence on other geometry variables (normals, volume etc) ---*/ + + geometry[iZone][iInst][MESH_0]->UpdateGeometry(geometry[iZone][iInst], config[iZone]); + + } + + /*--- Compute coupling between flow and turbulent equations ---*/ + solver[iZone][iInst][MESH_0][FLOW_SOL]->Preprocessing(geometry[iZone][iInst][MESH_0], solver[iZone][iInst][MESH_0], config[iZone], MESH_0, NO_RK_ITER, RUNTIME_FLOW_SYS, true); + solver[iZone][iInst][MESH_0][FLOW_SOL]->InitiateComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + solver[iZone][iInst][MESH_0][FLOW_SOL]->CompleteComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + + if (turbulent && !frozen_visc){ + solver[iZone][iInst][MESH_0][TURB_SOL]->Postprocessing(geometry[iZone][iInst][MESH_0],solver[iZone][iInst][MESH_0], config[iZone], MESH_0); + solver[iZone][iInst][MESH_0][TURB_SOL]->InitiateComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + solver[iZone][iInst][MESH_0][TURB_SOL]->CompleteComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + } + + if (heat){ + solver[iZone][iInst][MESH_0][HEAT_SOL]->Set_Heatflux_Areas(geometry[iZone][iInst][MESH_0], config[iZone]); + solver[iZone][iInst][MESH_0][HEAT_SOL]->Preprocessing(geometry[iZone][iInst][MESH_0],solver[iZone][iInst][MESH_0], config[iZone], MESH_0, NO_RK_ITER, RUNTIME_HEAT_SYS, true); + solver[iZone][iInst][MESH_0][HEAT_SOL]->Postprocessing(geometry[iZone][iInst][MESH_0],solver[iZone][iInst][MESH_0], config[iZone], MESH_0); + solver[iZone][iInst][MESH_0][HEAT_SOL]->InitiateComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + solver[iZone][iInst][MESH_0][HEAT_SOL]->CompleteComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + } + if (config[iZone]->AddRadiation()){ + solver[iZone][iInst][MESH_0][RAD_SOL]->Postprocessing(geometry[iZone][iInst][MESH_0],solver[iZone][iInst][MESH_0], config[iZone], MESH_0); + solver[iZone][iInst][MESH_0][RAD_SOL]->InitiateComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + solver[iZone][iInst][MESH_0][RAD_SOL]->CompleteComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + } +} + +void CDiscAdjFluidIteration::RegisterOutput(CSolver *****solver, CGeometry ****geometry, CConfig **config, COutput* output, unsigned short iZone, unsigned short iInst){ + + unsigned short Kind_Solver = config[iZone]->GetKind_Solver(); + bool frozen_visc = config[iZone]->GetFrozen_Visc_Disc(); + bool heat = config[iZone]->GetWeakly_Coupled_Heat(); + bool interface_boundary = (config[iZone]->GetnMarker_Fluid_Load() > 0); + + if ((Kind_Solver == DISC_ADJ_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_RANS) || (Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_INC_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_INC_RANS) || (Kind_Solver == DISC_ADJ_INC_EULER)) { + + /*--- Register conservative variables as output of the iteration ---*/ + + solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->RegisterOutput(geometry[iZone][iInst][MESH_0],config[iZone]); + + } + if (turbulent && !frozen_visc){ + solver[iZone][iInst][MESH_0][ADJTURB_SOL]->RegisterOutput(geometry[iZone][iInst][MESH_0], + config[iZone]); + } + if (heat){ + solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->RegisterOutput(geometry[iZone][iInst][MESH_0], + config[iZone]); + } + if (config[iZone]->AddRadiation()){ + solver[iZone][iInst][MESH_0][ADJRAD_SOL]->RegisterOutput(geometry[iZone][iInst][MESH_0], config[iZone]); + } + if (interface_boundary){ + solver[iZone][iInst][MESH_0][FLOW_SOL]->RegisterVertexTractions(geometry[iZone][iInst][MESH_0], config[iZone]); + } +} + +void CDiscAdjFluidIteration::InitializeAdjoint_CrossTerm(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst){ + + unsigned short Kind_Solver = config[iZone]->GetKind_Solver(); + bool frozen_visc = config[iZone]->GetFrozen_Visc_Disc(); + + /*--- Initialize the adjoint of the objective function (typically with 1.0) ---*/ + + solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->SetAdj_ObjFunc(geometry[iZone][iInst][MESH_0], config[iZone]); + + /*--- Initialize the adjoints the conservative variables ---*/ + + if ((Kind_Solver == DISC_ADJ_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_RANS) || (Kind_Solver == DISC_ADJ_EULER) || + (Kind_Solver == DISC_ADJ_INC_NAVIER_STOKES) || (Kind_Solver == DISC_ADJ_INC_RANS) || (Kind_Solver == DISC_ADJ_INC_EULER)) { + + solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], + config[iZone]); +} + + if (turbulent && !frozen_visc) { + solver[iZone][iInst][MESH_0][ADJTURB_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], + config[iZone]); + } + + if (config[iZone]->AddRadiation()) { + solver[iZone][iInst][MESH_0][ADJRAD_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], config[iZone]); + } +} + + +void CDiscAdjFluidIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned short iMesh; + + /*--- Dual time stepping strategy ---*/ + + if ((config[val_iZone]->GetTime_Marching() == DT_STEPPING_1ST) || + (config[val_iZone]->GetTime_Marching() == DT_STEPPING_2ND)) { + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + integration[val_iZone][val_iInst][ADJFLOW_SOL]->SetConvergence(false); + } + } +} +bool CDiscAdjFluidIteration::Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + +#ifndef HAVE_MPI + StopTime = su2double(clock())/su2double(CLOCKS_PER_SEC); +#else + StopTime = MPI_Wtime(); +#endif + UsedTime = StopTime - StartTime; + + /*--- Write the convergence history for the fluid (only screen output) ---*/ + + output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], + solver[val_iZone][INST_0][MESH_0], + config[val_iZone], + config[val_iZone]->GetTimeIter(), + config[val_iZone]->GetOuterIter(), + config[val_iZone]->GetInnerIter()); + + return output->GetConvergence(); + +} +void CDiscAdjFluidIteration::Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } + + +CDiscAdjFEAIteration::CDiscAdjFEAIteration(CConfig *config) : CIteration(config), CurrentRecording(NONE){ + + fem_iteration = new CFEAIteration(config); + + // TEMPORARY output only for standalone structural problems + if ((!config->GetFSI_Simulation()) && (rank == MASTER_NODE)){ + + bool de_effects = config->GetDE_Effects(); + unsigned short iVar; + + /*--- Header of the temporary output file ---*/ + ofstream myfile_res; + myfile_res.open ("Results_Reverse_Adjoint.txt"); + + myfile_res << "Obj_Func" << " "; + for (iVar = 0; iVar < config->GetnElasticityMod(); iVar++) + myfile_res << "Sens_E_" << iVar << "\t"; + + for (iVar = 0; iVar < config->GetnPoissonRatio(); iVar++) + myfile_res << "Sens_Nu_" << iVar << "\t"; + + if (config->GetTime_Domain()){ + for (iVar = 0; iVar < config->GetnMaterialDensity(); iVar++) + myfile_res << "Sens_Rho_" << iVar << "\t"; + } + + if (de_effects){ + for (iVar = 0; iVar < config->GetnElectric_Field(); iVar++) + myfile_res << "Sens_EField_" << iVar << "\t"; + } + + myfile_res << endl; + + myfile_res.close(); + } + +} + +CDiscAdjFEAIteration::~CDiscAdjFEAIteration(void) { } +void CDiscAdjFEAIteration::Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned long iPoint; + unsigned short TimeIter = config[val_iZone]->GetTimeIter(); + bool dynamic = (config[val_iZone]->GetTime_Domain()); + + int Direct_Iter; + + /*--- For the dynamic adjoint, load direct solutions from restart files. ---*/ + + if (dynamic) { + + Direct_Iter = SU2_TYPE::Int(config[val_iZone]->GetUnst_AdjointIter()) - SU2_TYPE::Int(TimeIter) - 1; + + /*--- We want to load the already converged solution at timesteps n and n-1 ---*/ + + /*--- Load solution at timestep n-1 ---*/ + + LoadDynamic_Solution(geometry, solver,config, val_iZone, val_iInst, Direct_Iter-1); + + /*--- Push solution back to correct array ---*/ + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->Set_Solution_time_n(); + + /*--- Push solution back to correct array ---*/ + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Accel_time_n(); + + /*--- Push solution back to correct array ---*/ + + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Vel_time_n(); + + /*--- Load solution timestep n ---*/ + + LoadDynamic_Solution(geometry, solver,config, val_iZone, val_iInst, Direct_Iter); + + /*--- Store FEA solution also in the adjoint solver in order to be able to reset it later ---*/ + + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++){ + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->GetSolution(iPoint)); + } + + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++){ + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetNodes()->SetSolution_Accel_Direct(iPoint, solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->GetSolution_Accel(iPoint)); + } + + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++){ + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetNodes()->SetSolution_Vel_Direct(iPoint, solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->GetSolution_Vel(iPoint)); + } + + } + else{ + /*--- Store FEA solution also in the adjoint solver in order to be able to reset it later ---*/ + + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++){ + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->GetSolution(iPoint)); + } + + } + + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->Preprocessing(geometry[val_iZone][val_iInst][MESH_0], solver[val_iZone][val_iInst][MESH_0], config[val_iZone] , MESH_0, 0, RUNTIME_ADJFEA_SYS, false); + +} + + + +void CDiscAdjFEAIteration::LoadDynamic_Solution(CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + int val_DirectIter) { + unsigned short iVar; + unsigned long iPoint; + bool update_geo = false; //TODO: check + + if (val_DirectIter >= 0){ + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << " Loading FEA solution from direct iteration " << val_DirectIter << "." << endl; + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LoadRestart(geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], val_DirectIter, update_geo); + } else { + /*--- If there is no solution file we set the freestream condition ---*/ + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << " Setting static conditions at direct iteration " << val_DirectIter << "." << endl; + /*--- Push solution back to correct array ---*/ + for(iPoint=0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint();iPoint++){ + for (iVar = 0; iVar < solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetnVar(); iVar++){ + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution(iPoint, iVar, 0.0); + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Accel(iPoint, iVar, 0.0); + solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Vel(iPoint, iVar, 0.0); + } + } + } +} + + +void CDiscAdjFEAIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***volume_grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + + bool dynamic = (config[val_iZone]->GetTime_Domain()); + + /*--- Extract the adjoints of the conservative input variables and store them for the next iteration ---*/ + + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->ExtractAdjoint_Solution(geometry[val_iZone][val_iInst][MESH_0], + config[val_iZone]); + + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->ExtractAdjoint_Variables(geometry[val_iZone][val_iInst][MESH_0], + config[val_iZone]); + if (dynamic){ + integration[val_iZone][val_iInst][ADJFEA_SOL]->SetConvergence(false); + } + +} + +void CDiscAdjFEAIteration::SetRecording(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording) { + + unsigned long InnerIter = config[ZONE_0]->GetInnerIter(); + unsigned long TimeIter = config[val_iZone]->GetTimeIter(), DirectTimeIter; + bool dynamic = (config[val_iZone]->GetTime_Domain()); + + DirectTimeIter = 0; + if (dynamic){ + DirectTimeIter = SU2_TYPE::Int(config[val_iZone]->GetUnst_AdjointIter()) - SU2_TYPE::Int(TimeIter) - 1; + } + + /*--- Reset the tape ---*/ + + AD::Reset(); + + /*--- We only need to reset the indices if the current recording is different from the recording we want to have ---*/ + + if (CurrentRecording != kind_recording && (CurrentRecording != NONE) ){ + + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->SetRecording(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + + /*--- Clear indices of coupling variables ---*/ + + SetDependencies(solver, geometry, numerics, config, val_iZone, val_iInst, ALL_VARIABLES); + + /*--- Run one iteration while tape is passive - this clears all indices ---*/ + + fem_iteration->Iterate(output,integration,geometry,solver,numerics, + config,surface_movement,grid_movement,FFDBox,val_iZone, val_iInst); + + } + + /*--- Prepare for recording ---*/ + + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->SetRecording(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + + /*--- Start the recording of all operations ---*/ + + AD::StartRecording(); + + /*--- Register FEA variables ---*/ + + RegisterInput(solver, geometry, config, val_iZone, val_iInst, kind_recording); + + /*--- Compute coupling or update the geometry ---*/ + + SetDependencies(solver, geometry, numerics, config, val_iZone, val_iInst, kind_recording); + + /*--- Set the correct direct iteration number ---*/ + + if (dynamic){ + config[val_iZone]->SetTimeIter(DirectTimeIter); + } + + /*--- Run the direct iteration ---*/ + + fem_iteration->Iterate(output,integration,geometry,solver,numerics, + config,surface_movement,grid_movement,FFDBox, val_iZone, val_iInst); + + config[val_iZone]->SetTimeIter(TimeIter); + + /*--- Register structural variables and objective function as output ---*/ + + RegisterOutput(solver, geometry, config, val_iZone, val_iInst); + + /*--- Stop the recording ---*/ + + AD::StopRecording(); + + /*--- Set the recording status ---*/ + + CurrentRecording = kind_recording; + + /* --- Reset the number of the internal iterations---*/ + + config[ZONE_0]->SetInnerIter(InnerIter); + +} + + +void CDiscAdjFEAIteration::SetRecording(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + unsigned short kind_recording) { + + /*--- Prepare for recording by resetting the solution to the initial converged solution ---*/ + + solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->SetRecording(geometry[val_iZone][val_iInst][MESH_0], config[val_iZone]); + +} + +void CDiscAdjFEAIteration::RegisterInput(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst, unsigned short kind_recording){ + + if(kind_recording != MESH_COORDS) { + + /*--- Register structural displacements as input ---*/ + + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + + /*--- Register variables as input ---*/ + + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->RegisterVariables(geometry[iZone][iInst][MESH_0], config[iZone]); + + /*--- Both need to be registered regardless of kind_recording for structural shape derivatives to work properly. + Otherwise, the code simply diverges as the FEM_CROSS_TERM_GEOMETRY breaks! (no idea why) for this term we register but do not extract! ---*/ + } + else { + /*--- Register topology optimization densities (note direct solver) ---*/ + + solver[iZone][iInst][MESH_0][FEA_SOL]->RegisterVariables(geometry[iZone][iInst][MESH_0], config[iZone]); + + /*--- Register mesh coordinates for geometric sensitivities ---*/ + + geometry[iZone][iInst][MESH_0]->RegisterCoordinates(config[iZone]); + } +} + +void CDiscAdjFEAIteration::SetDependencies(CSolver *****solver, CGeometry ****geometry, CNumerics ******numerics, CConfig **config, + unsigned short iZone, unsigned short iInst, unsigned short kind_recording){ + + auto dir_solver = solver[iZone][iInst][MESH_0][FEA_SOL]; + auto adj_solver = solver[iZone][iInst][MESH_0][ADJFEA_SOL]; + auto structural_geometry = geometry[iZone][iInst][MESH_0]; + auto structural_numerics = numerics[iZone][iInst][MESH_0][FEA_SOL]; + + /*--- Some numerics are only instanciated under these conditions ---*/ + bool fsi = config[iZone]->GetFSI_Simulation(); + bool nonlinear = config[iZone]->GetGeometricConditions() == LARGE_DEFORMATIONS; + bool de_effects = config[iZone]->GetDE_Effects() && nonlinear; + bool element_based = dir_solver->IsElementBased() && nonlinear; + + for (unsigned short iProp = 0; iProp < config[iZone]->GetnElasticityMod(); iProp++){ + + su2double E = adj_solver->GetVal_Young(iProp); + su2double nu = adj_solver->GetVal_Poisson(iProp); + su2double rho = adj_solver->GetVal_Rho(iProp); + su2double rhoDL = adj_solver->GetVal_Rho_DL(iProp); + + /*--- Add dependencies for E and Nu ---*/ + + structural_numerics[FEA_TERM]->SetMaterial_Properties(iProp, E, nu); + + /*--- Add dependencies for Rho and Rho_DL ---*/ + + structural_numerics[FEA_TERM]->SetMaterial_Density(iProp, rho, rhoDL); + + /*--- Add dependencies for element-based simulations. ---*/ + + if (element_based){ + + /*--- Neo Hookean Compressible ---*/ + structural_numerics[MAT_NHCOMP]->SetMaterial_Properties(iProp, E, nu); + structural_numerics[MAT_NHCOMP]->SetMaterial_Density(iProp, rho, rhoDL); + + /*--- Ideal DE ---*/ + structural_numerics[MAT_IDEALDE]->SetMaterial_Properties(iProp, E, nu); + structural_numerics[MAT_IDEALDE]->SetMaterial_Density(iProp, rho, rhoDL); + + /*--- Knowles ---*/ + structural_numerics[MAT_KNOWLES]->SetMaterial_Properties(iProp, E, nu); + structural_numerics[MAT_KNOWLES]->SetMaterial_Density(iProp, rho, rhoDL); + } + } + + if (de_effects){ + for (unsigned short iEField = 0; iEField < adj_solver->GetnEField(); iEField++){ + structural_numerics[FEA_TERM]->Set_ElectricField(iEField, adj_solver->GetVal_EField(iEField)); + structural_numerics[DE_TERM]->Set_ElectricField(iEField, adj_solver->GetVal_EField(iEField)); + } + } + + /*--- Add dependencies for element-based simulations. ---*/ + + switch (config[iZone]->GetDV_FEA()) { + case YOUNG_MODULUS: + case POISSON_RATIO: + case DENSITY_VAL: + case DEAD_WEIGHT: + case ELECTRIC_FIELD: + + for (unsigned short iDV = 0; iDV < adj_solver->GetnDVFEA(); iDV++) { + + su2double dvfea = adj_solver->GetVal_DVFEA(iDV); + + structural_numerics[FEA_TERM]->Set_DV_Val(iDV, dvfea); + + if (de_effects) + structural_numerics[DE_TERM]->Set_DV_Val(iDV, dvfea); + + if (element_based){ + structural_numerics[MAT_NHCOMP]->Set_DV_Val(iDV, dvfea); + structural_numerics[MAT_IDEALDE]->Set_DV_Val(iDV, dvfea); + structural_numerics[MAT_KNOWLES]->Set_DV_Val(iDV, dvfea); + } + } + break; + } + + /*--- FSI specific dependencies. ---*/ + if (fsi) { + /*--- Set relation between solution and predicted displacements, which are the transferred ones. ---*/ + dir_solver->PredictStruct_Displacement(nullptr, config[iZone], solver[iZone][iInst]); + } + + /*--- MPI dependencies. ---*/ + + dir_solver->InitiateComms(structural_geometry, config[iZone], SOLUTION_FEA); + dir_solver->CompleteComms(structural_geometry, config[iZone], SOLUTION_FEA); + + if (kind_recording == MESH_COORDS) { + structural_geometry->InitiateComms(structural_geometry, config[iZone], COORDINATES); + structural_geometry->CompleteComms(structural_geometry, config[iZone], COORDINATES); + } + + /*--- Topology optimization dependencies. ---*/ + + /*--- We only differentiate wrt to this variable in the adjoint secondary recording. ---*/ + if (config[iZone]->GetTopology_Optimization() && (kind_recording == MESH_COORDS)) { + /*--- The filter may require the volumes of the elements. ---*/ + structural_geometry->SetElemVolume(config[iZone]); + /// TODO: Ideally there would be a way to capture this dependency without the `static_cast`, but + /// making it a virtual method of CSolver does not feel "right" as its purpose could be confused. + static_cast(dir_solver)->FilterElementDensities(structural_geometry, config[iZone]); + } + +} + +void CDiscAdjFEAIteration::RegisterOutput(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst){ + + /*--- Register conservative variables as output of the iteration ---*/ + + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->RegisterOutput(geometry[iZone][iInst][MESH_0],config[iZone]); + +} + +void CDiscAdjFEAIteration::InitializeAdjoint(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst){ + + /*--- Initialize the adjoint of the objective function (typically with 1.0) ---*/ + + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->SetAdj_ObjFunc(geometry[iZone][iInst][MESH_0], config[iZone]); + + /*--- Initialize the adjoints the conservative variables ---*/ + + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], config[iZone]); + +} + + +void CDiscAdjFEAIteration::InitializeAdjoint_CrossTerm(CSolver *****solver, CGeometry ****geometry, CConfig **config, unsigned short iZone, unsigned short iInst){ + + /*--- Initialize the adjoint of the objective function (typically with 1.0) ---*/ + + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->SetAdj_ObjFunc(geometry[iZone][iInst][MESH_0], config[iZone]); + + /*--- Initialize the adjoints the conservative variables ---*/ + + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], config[iZone]); + +} + +void CDiscAdjFEAIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { } + +bool CDiscAdjFEAIteration::Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + /*--- Write the convergence history (only screen output) ---*/ + + output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], + solver[val_iZone][INST_0][MESH_0], + config[val_iZone], + config[val_iZone]->GetTimeIter(), + config[val_iZone]->GetOuterIter(), + config[val_iZone]->GetInnerIter()); + + return output->GetConvergence(); + +} +void CDiscAdjFEAIteration::Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + bool dynamic = (config[val_iZone]->GetTime_Domain()); + + // TEMPORARY output only for standalone structural problems + if ((!config[val_iZone]->GetFSI_Simulation()) && (rank == MASTER_NODE)){ + + unsigned short iVar; + + bool de_effects = config[val_iZone]->GetDE_Effects(); + + /*--- Header of the temporary output file ---*/ + ofstream myfile_res; + myfile_res.open ("Results_Reverse_Adjoint.txt", ios::app); + + myfile_res.precision(15); + + myfile_res << config[val_iZone]->GetTimeIter() << "\t"; + + switch (config[val_iZone]->GetKind_ObjFunc()){ + case REFERENCE_GEOMETRY: + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetTotal_OFRefGeom() << "\t"; + break; + case REFERENCE_NODE: + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetTotal_OFRefNode() << "\t"; + break; + case VOLUME_FRACTION: + case TOPOL_DISCRETENESS: + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetTotal_OFVolFrac() << "\t"; + break; + case TOPOL_COMPLIANCE: + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetTotal_OFCompliance() << "\t"; + break; + } + + for (iVar = 0; iVar < config[val_iZone]->GetnElasticityMod(); iVar++) + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetTotal_Sens_E(iVar) << "\t"; + for (iVar = 0; iVar < config[val_iZone]->GetnPoissonRatio(); iVar++) + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetTotal_Sens_Nu(iVar) << "\t"; + if (dynamic){ + for (iVar = 0; iVar < config[val_iZone]->GetnMaterialDensity(); iVar++) + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetTotal_Sens_Rho(iVar) << "\t"; + } + + if (de_effects){ + for (iVar = 0; iVar < config[val_iZone]->GetnElectric_Field(); iVar++) + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetTotal_Sens_EField(iVar) << "\t"; + } + + for (iVar = 0; iVar < solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetnDVFEA(); iVar++){ + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetTotal_Sens_DVFEA(iVar) << "\t"; + } + + myfile_res << endl; + + myfile_res.close(); + } + + // TEST: for implementation of python framework in standalone structural problems + if ((!config[val_iZone]->GetFSI_Simulation()) && (rank == MASTER_NODE)){ + + /*--- Header of the temporary output file ---*/ + ofstream myfile_res; + bool outputDVFEA = false; + + switch (config[val_iZone]->GetDV_FEA()) { + case YOUNG_MODULUS: + myfile_res.open("grad_young.opt"); + outputDVFEA = true; + break; + case POISSON_RATIO: + myfile_res.open("grad_poisson.opt"); + outputDVFEA = true; + break; + case DENSITY_VAL: + case DEAD_WEIGHT: + myfile_res.open("grad_density.opt"); + outputDVFEA = true; + break; + case ELECTRIC_FIELD: + myfile_res.open("grad_efield.opt"); + outputDVFEA = true; + break; + default: + outputDVFEA = false; + break; + } + + if (outputDVFEA){ + + unsigned short iDV; + unsigned short nDV = solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetnDVFEA(); + + myfile_res << "INDEX" << "\t" << "GRAD" << endl; + + myfile_res.precision(15); + + for (iDV = 0; iDV < nDV; iDV++){ + myfile_res << iDV; + myfile_res << "\t"; + myfile_res << scientific << solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->GetTotal_Sens_DVFEA(iDV); + myfile_res << endl; + } + + myfile_res.close(); + + } + + } + +} + +CDiscAdjHeatIteration::CDiscAdjHeatIteration(CConfig *config) : CIteration(config) { } + +CDiscAdjHeatIteration::~CDiscAdjHeatIteration(void) { } + +void CDiscAdjHeatIteration::Preprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + unsigned long iPoint; + unsigned short TimeIter = config[val_iZone]->GetTimeIter(); + bool dual_time_1st = (config[val_iZone]->GetTime_Marching() == DT_STEPPING_1ST); + bool dual_time_2nd = (config[val_iZone]->GetTime_Marching() == DT_STEPPING_2ND); + bool dual_time = (dual_time_1st || dual_time_2nd); + unsigned short iMesh; + int Direct_Iter; + + /*--- For the unsteady adjoint, load direct solutions from restart files. ---*/ + + if (config[val_iZone]->GetTime_Marching()) { + + Direct_Iter = SU2_TYPE::Int(config[val_iZone]->GetUnst_AdjointIter()) - SU2_TYPE::Int(TimeIter) - 2; + + /*--- For dual-time stepping we want to load the already converged solution at timestep n ---*/ + + if (dual_time) { + Direct_Iter += 1; + } + + if (TimeIter == 0){ + + if (dual_time_2nd) { + + /*--- Load solution at timestep n-2 ---*/ + + LoadUnsteady_Solution(geometry, solver,config, val_iZone, val_iInst, Direct_Iter-2); + + /*--- Push solution back to correct array ---*/ + + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n(); + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n1(); + } + } + if (dual_time) { + + /*--- Load solution at timestep n-1 ---*/ + + LoadUnsteady_Solution(geometry, solver,config, val_iZone, val_iInst, Direct_Iter-1); + + /*--- Push solution back to correct array ---*/ + + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n(); + } + } + + /*--- Load solution timestep n ---*/ + + LoadUnsteady_Solution(geometry, solver,config, val_iZone, val_iInst, Direct_Iter); + + } + + + if ((TimeIter > 0) && dual_time){ + + /*--- Load solution timestep n - 2 ---*/ + + LoadUnsteady_Solution(geometry, solver,config, val_iZone, val_iInst, Direct_Iter - 2); + + /*--- Temporarily store the loaded solution in the Solution_Old array ---*/ + + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_OldSolution(); + + /*--- Set Solution at timestep n to solution at n-1 ---*/ + + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->SetSolution(iPoint, solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->GetSolution_time_n(iPoint)); + } + } + if (dual_time_1st){ + /*--- Set Solution at timestep n-1 to the previously loaded solution ---*/ + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); + } + } + } + if (dual_time_2nd){ + /*--- Set Solution at timestep n-1 to solution at n-2 ---*/ + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n(iPoint, solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->GetSolution_time_n1(iPoint)); + } + } + /*--- Set Solution at timestep n-2 to the previously loaded solution ---*/ + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + for(iPoint=0; iPointGetnPoint();iPoint++) { + + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->Set_Solution_time_n1(iPoint, solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->GetNodes()->GetSolution_Old(iPoint)); + } + } + } + } + } + + /*--- Store flow solution also in the adjoint solver in order to be able to reset it later ---*/ + + if (TimeIter == 0 || dual_time) { + for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++) { + solver[val_iZone][val_iInst][MESH_0][ADJHEAT_SOL]->GetNodes()->SetSolution_Direct(iPoint, solver[val_iZone][val_iInst][MESH_0][HEAT_SOL]->GetNodes()->GetSolution(iPoint)); + } + } + + solver[val_iZone][val_iInst][MESH_0][ADJHEAT_SOL]->Preprocessing(geometry[val_iZone][val_iInst][MESH_0], + solver[val_iZone][val_iInst][MESH_0], + config[val_iZone], + MESH_0, 0, RUNTIME_ADJHEAT_SYS, false); +} + + + +void CDiscAdjHeatIteration::LoadUnsteady_Solution(CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned short val_iZone, + unsigned short val_iInst, + int val_DirectIter) { + unsigned short iMesh; + + if (val_DirectIter >= 0) { + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << " Loading heat solution from direct iteration " << val_DirectIter << "." << endl; + + solver[val_iZone][val_iInst][MESH_0][HEAT_SOL]->LoadRestart(geometry[val_iZone][val_iInst], + solver[val_iZone][val_iInst], + config[val_iZone], + val_DirectIter, false); + } + + else { + /*--- If there is no solution file we set the freestream condition ---*/ + if (rank == MASTER_NODE && val_iZone == ZONE_0) + cout << " Setting freestream conditions at direct iteration " << val_DirectIter << "." << endl; + for (iMesh=0; iMesh<=config[val_iZone]->GetnMGLevels();iMesh++) { + + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->SetFreeStream_Solution(config[val_iZone]); + solver[val_iZone][val_iInst][iMesh][HEAT_SOL]->Postprocessing(geometry[val_iZone][val_iInst][iMesh], + solver[val_iZone][val_iInst][iMesh], + config[val_iZone], + iMesh); + } + } +} + + +void CDiscAdjHeatIteration::Iterate(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***volume_grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + + solver[val_iZone][val_iInst][MESH_0][ADJHEAT_SOL]->ExtractAdjoint_Solution(geometry[val_iZone][val_iInst][MESH_0], + config[val_iZone]); +} + +void CDiscAdjHeatIteration::InitializeAdjoint(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short iZone, unsigned short iInst){ + + /*--- Initialize the adjoints the conservative variables ---*/ + + solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], + config[iZone]); +} + + +void CDiscAdjHeatIteration::RegisterInput(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, + unsigned short iZone, unsigned short iInst, + unsigned short kind_recording){ + + if (kind_recording == FLOW_CONS_VARS || kind_recording == COMBINED){ + + /*--- Register flow and turbulent variables as input ---*/ + + solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); + + solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->RegisterVariables(geometry[iZone][iInst][MESH_0], config[iZone]); + + } + if (kind_recording == MESH_COORDS){ + + /*--- Register node coordinates as input ---*/ + + geometry[iZone][iInst][MESH_0]->RegisterCoordinates(config[iZone]); + + } +} + +void CDiscAdjHeatIteration::SetDependencies(CSolver *****solver, + CGeometry ****geometry, + CNumerics ******numerics, + CConfig **config, + unsigned short iZone, unsigned short iInst, + unsigned short kind_recording){ + + if ((kind_recording == MESH_COORDS) || (kind_recording == NONE) || + (kind_recording == GEOMETRY_CROSS_TERM) || (kind_recording == ALL_VARIABLES)){ + + /*--- Update geometry to get the influence on other geometry variables (normals, volume etc) ---*/ + + geometry[iZone][iInst][MESH_0]->UpdateGeometry(geometry[iZone][iInst], config[iZone]); + + } + + solver[iZone][iInst][MESH_0][HEAT_SOL]->Set_Heatflux_Areas(geometry[iZone][iInst][MESH_0], config[iZone]); + solver[iZone][iInst][MESH_0][HEAT_SOL]->Preprocessing(geometry[iZone][iInst][MESH_0], solver[iZone][iInst][MESH_0], + config[iZone], MESH_0, NO_RK_ITER, RUNTIME_HEAT_SYS, true); + solver[iZone][iInst][MESH_0][HEAT_SOL]->Postprocessing(geometry[iZone][iInst][MESH_0], solver[iZone][iInst][MESH_0], + config[iZone], MESH_0); + solver[iZone][iInst][MESH_0][HEAT_SOL]->InitiateComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + solver[iZone][iInst][MESH_0][HEAT_SOL]->CompleteComms(geometry[iZone][iInst][MESH_0], config[iZone], SOLUTION); + +} + +void CDiscAdjHeatIteration::RegisterOutput(CSolver *****solver, + CGeometry ****geometry, + CConfig **config, COutput* output, + unsigned short iZone, unsigned short iInst){ + + solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->RegisterOutput(geometry[iZone][iInst][MESH_0], config[iZone]); + + geometry[iZone][iInst][MESH_0]->RegisterOutput_Coordinates(config[iZone]); +} + +void CDiscAdjHeatIteration::Update(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, unsigned short val_iInst) { + + unsigned short iMesh; + + /*--- Dual time stepping strategy ---*/ + + if ((config[val_iZone]->GetTime_Marching() == DT_STEPPING_1ST) || + (config[val_iZone]->GetTime_Marching() == DT_STEPPING_2ND)) { + + for (iMesh = 0; iMesh <= config[val_iZone]->GetnMGLevels(); iMesh++) { + integration[val_iZone][val_iInst][ADJHEAT_SOL]->SetConvergence(false); + } + } +} + +bool CDiscAdjHeatIteration::Monitor(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, + unsigned short val_iInst) { + + output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], + solver[val_iZone][INST_0][MESH_0], + config[val_iZone], + config[val_iZone]->GetTimeIter(), + config[val_iZone]->GetOuterIter(), + config[val_iZone]->GetInnerIter()); + + return output->GetConvergence(); +} + +void CDiscAdjHeatIteration::Output(COutput *output, + CGeometry ****geometry, + CSolver *****solver, + CConfig **config, + unsigned long InnerIter, + bool StopCalc, + unsigned short val_iZone, + unsigned short val_iInst) { } + +void CDiscAdjHeatIteration::Postprocess(COutput *output, + CIntegration ****integration, + CGeometry ****geometry, + CSolver *****solver, + CNumerics ******numerics, + CConfig **config, + CSurfaceMovement **surface_movement, + CVolumetricMovement ***grid_movement, + CFreeFormDefBox*** FFDBox, + unsigned short val_iZone, unsigned short val_iInst) { } diff --git a/SU2_CFD/src/meson.build b/SU2_CFD/src/meson.build index 736100a1b812..8ea75861ea49 100644 --- a/SU2_CFD/src/meson.build +++ b/SU2_CFD/src/meson.build @@ -179,6 +179,8 @@ su2_cfd_src += files(['iteration/CIteration.cpp', su2_cfd_src += files(['limiters/CLimiterDetails.cpp']) +su2_cfd_src += files(['objectives/turbomachinery/CTurbomachineryPerformance.cpp']) + if get_option('enable-normal') su2_cfd_lib = static_library('SU2core', su2_cfd_src, diff --git a/SU2_CFD/src/objectives/turbomachinery/CTurbomachineryPerformance.cpp b/SU2_CFD/src/objectives/turbomachinery/CTurbomachineryPerformance.cpp new file mode 100644 index 000000000000..d83c0c9fcbfd --- /dev/null +++ b/SU2_CFD/src/objectives/turbomachinery/CTurbomachineryPerformance.cpp @@ -0,0 +1,304 @@ +/*! + * \file CTurbomachineryPerformance.cpp + * \brief Source of the Turbomachinery Performance class. + * \author S. Vitale, N. Anand + * \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-2019, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#include "../../../include/objectives/turbomachinery/CTurbomachineryPerformance.hpp" + +CTurbomachineryPrimitiveState::CTurbomachineryPrimitiveState() { + Density = Pressure = TangVelocity = 0.0; +} +CTurbomachineryPrimitiveState::CTurbomachineryPrimitiveState(vector TurboPrimitive, + unsigned short nDim, + su2double tangVel) : Density(TurboPrimitive[0]), Pressure(TurboPrimitive[1]), TangVelocity(tangVel) { + // Velocity.assign(TurboPrimitive+2, TurboPrimitive + nDim+2 ); + Velocity = {TurboPrimitive.begin()+2, TurboPrimitive.end()}; +} + +CTurbomachineryCombinedPrimitiveStates::CTurbomachineryCombinedPrimitiveStates(const CTurbomachineryPrimitiveState& inletPrimitiveState, + const CTurbomachineryPrimitiveState& outletPrimitiveState) : InletPrimitiveState(inletPrimitiveState), OutletPrimitiveState(outletPrimitiveState){} + +CTurbomachineryState::CTurbomachineryState(){ + Density = Pressure = Entropy = Enthalpy = Temperature = TotalTemperature = TotalPressure = TotalEnthalpy = 0.0; + AbsFlowAngle = FlowAngle = MassFlow = Rothalpy = TotalRelPressure = 0.0; + Area = Radius = 0.0; +} + +CTurbomachineryState::CTurbomachineryState(unsigned short nDim, su2double area, su2double radius) : CTurbomachineryState() { + generate_n(back_inserter(Velocity),nDim, [] {return 0.0;}); + generate_n(back_inserter(RelVelocity),nDim, [] {return 0.0;}); + generate_n(back_inserter(Mach),nDim, [] {return 0.0;}); + generate_n(back_inserter(RelMach),nDim, [] {return 0.0;}); + Area = area; + Radius = radius; +} + +void CTurbomachineryState::ComputeState(CFluidModel& fluidModel, const CTurbomachineryPrimitiveState &primitiveState) { + + /*--- Assign new primitive values ---*/ + Density = primitiveState.GetDensity(); + Pressure = primitiveState.GetPressure(); + std::vector velocity = primitiveState.GetVelocity(); + Velocity.assign(velocity.begin(), velocity.end()); + su2double tangVel = primitiveState.GetTangVelocity(); + + /*--- Compute static TD quantities ---*/ + fluidModel.SetTDState_Prho(Pressure, Density); + Entropy = fluidModel.GetEntropy(); + Enthalpy = fluidModel.GetStaticEnergy() + Pressure / Density; + su2double soundSpeed = fluidModel.GetSoundSpeed(); + + /*--- Compute total TD quantities ---*/ + TotalEnthalpy = Enthalpy + 0.5 * GetVelocityValue() * GetVelocityValue(); + fluidModel.SetTDState_hs(TotalEnthalpy, Entropy); + TotalPressure = fluidModel.GetPressure(); + TotalTemperature = fluidModel.GetTemperature(); + + /*--- Compute absolute kinematic quantities---*/ + MassFlow = Density * Velocity[0] * Area; + AbsFlowAngle = atan(Velocity[1] / Velocity[0]); + Mach.assign(Velocity.begin(), Velocity.end()); + std::for_each(Mach.begin(), Mach.end(), [&](su2double &el) { el /= soundSpeed; }); + + /*--- Compute relative kinematic quantities ---*/ + su2double tangVel2 = tangVel * tangVel; + RelVelocity.assign(Velocity.begin(), Velocity.end()); + RelVelocity[1] -= tangVel; + su2double relVel2 = GetRelVelocityValue(); + FlowAngle = atan(RelVelocity[1] / RelVelocity[0]); + RelMach.assign(RelVelocity.begin(), RelVelocity.end()); + std::for_each(RelMach.begin(), RelMach.end(), [&](su2double &el) { el /= soundSpeed; }); + + /*--- Compute total relative TD quantities ---*/ + Rothalpy = Enthalpy + 0.5 * relVel2 - 0.5 * tangVel2; + fluidModel.SetTDState_hs(Rothalpy, Entropy); + TotalRelPressure = fluidModel.GetPressure(); + + /*--- Compute isentropic quantities ---*/ + fluidModel.SetTDState_Ps(Pressure, Entropy); + +} + +CTurbomachineryBladePerformance::CTurbomachineryBladePerformance(CFluidModel& fluidModel, + unsigned short nDim, + su2double areaIn, + su2double radiusIn, + su2double areaOut, + su2double radiusOut) : FluidModel(fluidModel) { + InletState = CTurbomachineryState(nDim, areaIn, radiusIn); + OutletState = CTurbomachineryState(nDim, areaOut,radiusOut); +} + + +CTurbineBladePerformance::CTurbineBladePerformance(CFluidModel& fluidModel, + unsigned short nDim, + su2double areaIn, + su2double radiusIn, + su2double areaOut, + su2double radiusOut) : CTurbomachineryBladePerformance(fluidModel, nDim, areaIn, radiusIn, areaOut, radiusOut){} + +void CTurbineBladePerformance::ComputePerformance(const CTurbomachineryCombinedPrimitiveStates &primitives) { + + /*--- Compute Inlet and Outlet state ---*/ + InletState.ComputeState(FluidModel, primitives.GetInletPrimitiveState()); + OutletState.ComputeState(FluidModel, primitives.GetOutletPrimitiveState()); + + /*--- Compute isentropic Outflow quantities ---*/ + FluidModel.SetTDState_Ps(OutletState.GetPressure(), InletState.GetEntropy()); + su2double enthalpyOutIs = FluidModel.GetStaticEnergy() + OutletState.GetPressure() / FluidModel.GetDensity(); + su2double tangVel = primitives.GetOutletPrimitiveState().GetTangVelocity(); + su2double relVelOutIs2 = 2 * (OutletState.GetRothalpy() - enthalpyOutIs) + tangVel * tangVel; + + /*--- Compute performance ---*/ + EntropyGen = (OutletState.GetEntropy() - InletState.GetEntropy()); // / abs(InletState.GetEntropy() + 1); + EulerianWork = InletState.GetTotalEnthalpy() - OutletState.GetTotalEnthalpy(); + TotalPressureLoss = (InletState.GetTotalRelPressure() - OutletState.GetTotalRelPressure()) / + (OutletState.GetTotalRelPressure() - OutletState.GetPressure()); + KineticEnergyLoss = 2 * (OutletState.GetEnthalpy() - enthalpyOutIs) / relVelOutIs2; +} + +CCompressorBladePerformance::CCompressorBladePerformance(CFluidModel& fluidModel, + unsigned short nDim, + su2double areaIn, + su2double radiusIn, + su2double areaOut, + su2double radiusOut) : CTurbomachineryBladePerformance(fluidModel, nDim, areaIn, radiusIn, areaOut, radiusOut){} + +void CCompressorBladePerformance::ComputePerformance(const CTurbomachineryCombinedPrimitiveStates &primitives) { + /*--- Compute Inlet and Outlet state ---*/ + InletState.ComputeState(FluidModel, primitives.GetInletPrimitiveState()); + OutletState.ComputeState(FluidModel, primitives.GetOutletPrimitiveState()); + + /*--- Compute isentropic Outflow quantities ---*/ + FluidModel.SetTDState_Ps(OutletState.GetPressure(), InletState.GetEntropy()); + su2double enthalpyOutIs = FluidModel.GetStaticEnergy() + OutletState.GetPressure() / FluidModel.GetDensity(); + su2double tangVel = primitives.GetOutletPrimitiveState().GetTangVelocity(); + su2double relVelOutIs2 = 2 * (OutletState.GetRothalpy() - enthalpyOutIs) + tangVel * tangVel; + + /*--- Compute performance ---*/ + EntropyGen = (OutletState.GetEntropy() - InletState.GetEntropy()); // / abs(InletState.GetEntropy() + 1); + EulerianWork = OutletState.GetTotalEnthalpy() - InletState.GetTotalEnthalpy(); + TotalPressureLoss = (InletState.GetTotalRelPressure() - OutletState.GetTotalRelPressure()) / + (InletState.GetTotalRelPressure() - InletState.GetPressure()); + KineticEnergyLoss = 2 * (OutletState.GetEnthalpy() - enthalpyOutIs) / relVelOutIs2; +} + +CPropellorBladePerformance::CPropellorBladePerformance(CFluidModel& fluidModel, + unsigned short nDim, + su2double areaIn, + su2double radiusIn, + su2double areaOut, + su2double radiusOut) : CTurbomachineryBladePerformance(fluidModel, nDim, areaIn, radiusIn, areaOut, radiusOut){} + +void CPropellorBladePerformance::ComputePerformance(const CTurbomachineryCombinedPrimitiveStates &primitives) { + // TODO: to be implemented +} + +CTurbomachineryPerformance::CTurbomachineryPerformance(const CConfig& config, + const CGeometry& geometry, + CFluidModel& fluidModel) { + unsigned short nBladesRow = config.GetnMarker_Turbomachinery(); + unsigned short nDim = geometry.GetnDim(); + unsigned short nStages = SU2_TYPE::Int(nBladesRow / 2); + + for (unsigned short iBladeRow = 0; iBladeRow < nBladesRow; iBladeRow++) { + vector > bladeSpanPerformances; + unsigned short nSpan = config.GetnSpanWiseSections(); + for (unsigned short iSpan = 0; iSpan < nSpan + 1; iSpan++) { + + su2double areaIn = geometry.GetSpanAreaIn(iBladeRow, iSpan); + su2double areaOut = geometry.GetSpanAreaOut(iBladeRow, iSpan); + su2double radiusIn = geometry.GetTurboRadiusIn(iBladeRow, iSpan); + su2double radiusOut = geometry.GetTurboRadiusOut(iBladeRow, iSpan); + // std::cout << "Area In " << areaIn << " Area Out " << areaOut << " blade row " << iBladeRow <(fluidModel, nDim, areaIn, radiusIn, areaOut, + radiusOut)); + break; + + case TURBO_PERF_KIND::COMPRESSOR: + bladeSpanPerformances.push_back(make_shared(fluidModel, nDim, areaIn, radiusIn, areaOut, + radiusOut)); + break; + + case TURBO_PERF_KIND::PROPELLOR: + bladeSpanPerformances.push_back(make_shared(fluidModel, nDim, areaIn, radiusIn, areaOut, + radiusOut)); + break; + + default: + bladeSpanPerformances.push_back(make_shared(fluidModel, nDim, areaIn, radiusIn, areaOut, + radiusOut)); + break; + } + } + } + BladesPerformances.push_back(bladeSpanPerformances); + } +} + +void CTurbomachineryPerformance::ComputeTurbomachineryPerformance( + vector > const bladesPrimitives) { + for(unsigned i = 0; i < BladesPerformances.size(); ++i) { + ComputePerBlade(BladesPerformances[i], bladesPrimitives[i]); + } +} + +void CTurbomachineryPerformance::ComputePerBlade( + vector > const bladePerformances, + vector const bladePrimitives) { + for(unsigned i = 0; i < bladePerformances.size(); ++i) { + ComputePerSpan(bladePerformances[i], bladePrimitives[i]); + } +} + +void CTurbomachineryPerformance::ComputePerSpan(shared_ptr const spanPerformances, + const CTurbomachineryCombinedPrimitiveStates &spanPrimitives) { + spanPerformances->ComputePerformance(spanPrimitives); +} + +CTurbomachineryStagePerformance::CTurbomachineryStagePerformance(CFluidModel& fluid) : fluidModel(fluid) { + +} + +void CTurbomachineryStagePerformance::ComputePerformanceStage(CTurbomachineryState InState, CTurbomachineryState OutState, const CConfig* config) { + + switch (config->GetKind_TurboPerf(ZONE_0)) { + case TURBO_PERF_KIND::TURBINE: + ComputeTurbineStagePerformance(InState, OutState); + break; + + case TURBO_PERF_KIND::COMPRESSOR: + ComputeCompressorStagePerformance(InState, OutState); + break; + + default: + ComputeTurbineStagePerformance(InState, OutState); + break; + } +} + +void CTurbomachineryStagePerformance::ComputeTurbineStagePerformance(CTurbomachineryState InState, CTurbomachineryState OutState) { + + /*--- Compute isentropic Outflow quantities ---*/ + fluidModel.SetTDState_Ps(OutState.GetPressure(), InState.GetEntropy()); + su2double enthalpyOutIs = fluidModel.GetStaticEnergy() + OutState.GetPressure() / fluidModel.GetDensity(); + su2double totEnthalpyOutIs = enthalpyOutIs + 0.5*OutState.GetVelocityValue()*OutState.GetVelocityValue(); + + /*--- Compute turbine stage performance ---*/ + NormEntropyGen = (OutState.GetEntropy() - InState.GetEntropy())/InState.GetEntropy(); + EulerianWork = InState.GetTotalEnthalpy() - OutState.GetTotalEnthalpy(); + TotalStaticEfficiency = EulerianWork/(InState.GetTotalEnthalpy()-enthalpyOutIs); + TotalTotalEfficiency = EulerianWork/(InState.GetTotalEnthalpy()-totEnthalpyOutIs); + TotalStaticPressureRatio = InState.GetTotalPressure()/OutState.GetPressure(); + TotalTotalPressureRatio = InState.GetTotalPressure()/OutState.GetTotalPressure(); +} + +void CTurbomachineryStagePerformance::ComputeCompressorStagePerformance(CTurbomachineryState InState, CTurbomachineryState OutState) { + + /*--- Compute isentropic Outflow quantities ---*/ + fluidModel.SetTDState_Ps(OutState.GetPressure(), InState.GetEntropy()); + su2double enthalpyOutIs = fluidModel.GetStaticEnergy() + OutState.GetPressure() / fluidModel.GetDensity(); + su2double totEnthalpyOutIs = enthalpyOutIs + 0.5*OutState.GetVelocityValue()*OutState.GetVelocityValue(); + + /*--- Compute compressor stage performance ---*/ + NormEntropyGen = (OutState.GetEntropy() - InState.GetEntropy())/InState.GetEntropy(); + EulerianWork = OutState.GetTotalEnthalpy() - InState.GetTotalEnthalpy(); + TotalStaticEfficiency = (enthalpyOutIs-InState.GetTotalEnthalpy())/EulerianWork; + TotalTotalEfficiency = (totEnthalpyOutIs-InState.GetTotalEnthalpy())/EulerianWork; + TotalStaticPressureRatio = OutState.GetPressure()/InState.GetTotalPressure(); + TotalTotalPressureRatio = OutState.GetTotalPressure()/InState.GetTotalPressure(); + +} \ No newline at end of file diff --git a/SU2_CFD/src/output/CFlowCompOutput.cpp b/SU2_CFD/src/output/CFlowCompOutput.cpp index f4bf29ed537a..d6cc968b8fcb 100644 --- a/SU2_CFD/src/output/CFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompOutput.cpp @@ -281,6 +281,13 @@ void CFlowCompOutput::SetHistoryOutputFields(CConfig *config){ Add_CpInverseDesignOutput(config); + if (config->GetBoolTurbomachinery()){ + AddHistoryOutput("TURBO_MASS", "res[Mass]", ScreenOutputFormat::SCIENTIFIC, "TURBO_PERF", "Mass Flow Convergence", HistoryFieldType::RESIDUAL); + AddHistoryOutput("TURBO_EGLC", "T.Perf[EG]", ScreenOutputFormat::SCIENTIFIC, "TURBO_PERF", "Entropy Generation Loss Coefficient", HistoryFieldType::COEFFICIENT); + AddHistoryOutput("TURBO_KELC", "T.Perf[KE]", ScreenOutputFormat::SCIENTIFIC, "TURBO_PERF", "Kinetic Energy Loss Coefficient", HistoryFieldType::COEFFICIENT); + AddHistoryOutput("TURBO_TPLC", "T.Perf[TP]", ScreenOutputFormat::SCIENTIFIC, "TURBO_PERF", "Total Pressure Loss Coefficient", HistoryFieldType::COEFFICIENT); + } + } void CFlowCompOutput::SetVolumeOutputFields(CConfig *config){ @@ -319,9 +326,12 @@ void CFlowCompOutput::SetVolumeOutputFields(CConfig *config){ } // Primitive variables - AddVolumeOutput("PRESSURE", "Pressure", "PRIMITIVE", "Pressure"); - AddVolumeOutput("TEMPERATURE", "Temperature", "PRIMITIVE", "Temperature"); - AddVolumeOutput("MACH", "Mach", "PRIMITIVE", "Mach number"); + AddVolumeOutput("PRESSURE", "Pressure", "PRIMITIVE", "Pressure"); + AddVolumeOutput("TEMPERATURE", "Temperature", "PRIMITIVE", "Temperature"); + AddVolumeOutput("ENTHALPY", "Enthalpy", "PRIMITIVE", "Enthalpy"); + AddVolumeOutput("TOT_ENTHALPY", "Total_Enthalpy", "PRIMITIVE", "Total Enthalpy"); + AddVolumeOutput("SOUND_SPEED", "Sound_Speed", "PRIMITIVE", "Speed of Sound"); + AddVolumeOutput("MACH", "Mach", "PRIMITIVE", "Mach number"); AddVolumeOutput("PRESSURE_COEFF", "Pressure_Coefficient", "PRIMITIVE", "Pressure coefficient"); if (config->GetKind_Solver() == RANS || config->GetKind_Solver() == NAVIER_STOKES){ @@ -466,6 +476,9 @@ void CFlowCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolv SetVolumeOutputValue("PRESSURE", iPoint, Node_Flow->GetPressure(iPoint)); SetVolumeOutputValue("TEMPERATURE", iPoint, Node_Flow->GetTemperature(iPoint)); + SetVolumeOutputValue("ENTHALPY", iPoint, Node_Flow->GetEnthalpy(iPoint)); + SetVolumeOutputValue("TOT_ENTHALPY", iPoint, Node_Flow->GetEnthalpy(iPoint)+0.5*Node_Flow->GetVelocity2(iPoint)); + SetVolumeOutputValue("SOUND_SPEED", iPoint, Node_Flow->GetSoundSpeed(iPoint)); SetVolumeOutputValue("MACH", iPoint, sqrt(Node_Flow->GetVelocity2(iPoint))/Node_Flow->GetSoundSpeed(iPoint)); su2double VelMag = 0.0; @@ -696,6 +709,15 @@ void CFlowCompOutput::LoadHistoryData(CConfig *config, CGeometry *geometry, CSol Set_CpInverseDesign(flow_solver, geometry, config); + // if (config->GetBoolTurbomachinery()){ + // auto m_in = flow_solver->GetTurbomachineryPerformance()->GetBladesPerformances().at(0).at(0)->GetInletState().GetMassFlow(); + // auto m_out = flow_solver->GetTurbomachineryPerformance()->GetBladesPerformances().at(0).at(0)->GetOutletState().GetMassFlow(); + // SetHistoryOutputValue("TURBO_MASS", (m_in - m_out)/m_in); + + // SetHistoryOutputValue("TURBO_EGLC", flow_solver->GetTurbomachineryPerformance()->GetBladesPerformances().at(0).at(0)->GetEntropyGen()); + // SetHistoryOutputValue("TURBO_KELC", flow_solver->GetTurbomachineryPerformance()->GetBladesPerformances().at(0).at(0)->GetKineticEnergyLoss()); + // SetHistoryOutputValue("TURBO_TPLC", flow_solver->GetTurbomachineryPerformance()->GetBladesPerformances().at(0).at(0)->GetTotalPressureLoss()); + // } } bool CFlowCompOutput::SetInit_Residuals(const CConfig *config){ diff --git a/SU2_CFD/src/output/COutput.cpp b/SU2_CFD/src/output/COutput.cpp index c37bcab5a650..1e08b107f77a 100644 --- a/SU2_CFD/src/output/COutput.cpp +++ b/SU2_CFD/src/output/COutput.cpp @@ -42,7 +42,7 @@ #include "../../include/output/filewriter/CSU2BinaryFileWriter.hpp" #include "../../include/output/filewriter/CSU2MeshFileWriter.hpp" - +#include "../../include/objectives/turbomachinery/CTurbomachineryPerformance.hpp" #include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solvers/CSolver.hpp" @@ -2162,3 +2162,94 @@ void COutput::PrintVolumeFields(){ VolumeFieldTable.PrintFooter(); } } + +void COutput::SetTurboPerformance_Output(std::shared_ptr TurboPerf, + CConfig *config, + unsigned long TimeIter, + unsigned long OuterIter, + unsigned long InnerIter, + unsigned short val_iZone) { + + curTimeIter = TimeIter; + curAbsTimeIter = TimeIter - config->GetRestart_Iter(); + curOuterIter = OuterIter; + curInnerIter = InnerIter; + stringstream TurboInOutTable, TurboPerfTable; + + if(rank == MASTER_NODE) { + auto BladePerformance = TurboPerf->GetBladesPerformances(); + auto nSpan = config->GetnSpan_iZones(val_iZone); + + /*-- Table for Turbomachinery Performance Values --*/ + PrintingToolbox::CTablePrinter TurboInOut(&TurboInOutTable); + + TurboInOutTable<<"-- Turbomachinery inlet and outlet property Summary:"<GetnSpan_iZones(iZone); + + TurboInOut<<" BLADE ROW INDEX "<GetInletState().GetEntropy() << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetEntropy(); + TurboInOut << "Total Enthalpy " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetTotalEnthalpy() << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetTotalEnthalpy(); + TurboInOut << "Total Pressure " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetTotalPressure() << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetTotalPressure(); + TurboInOut << "Pressure " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetPressure() << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetPressure(); + TurboInOut << "Density " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetDensity() << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetDensity(); + TurboInOut << "Normal Velocity " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetVelocity()[0] << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetVelocity()[0]; + TurboInOut << "Tangential Velocity " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetVelocity()[1] << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetVelocity()[1]; + TurboInOut << "Mass Flow " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetMassFlow() << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetMassFlow(); + TurboInOut << "Mach " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetMachValue() << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetMachValue(); + TurboInOut << "Flow Angle " << BladePerformance.at(iZone).at(nSpan)->GetInletState().GetAbsFlowAngle()*180/PI_NUMBER << BladePerformance.at(iZone).at(nSpan)->GetOutletState().GetAbsFlowAngle()*180/PI_NUMBER; + TurboInOut.PrintFooter(); + } + cout< TurboPerf, + CConfig *config) { + + auto nZone = config->GetnZone(); + unsigned short iStage, iZone; + auto nSpan = config->GetnSpanWiseSections(); + stringstream TurboMZPerf; + + PrintingToolbox::CTablePrinter TurboInOut(&TurboMZPerf); + + /*--- Print header for the stage performance computation ---*/ + TurboMZPerf<<"-- Turbomachinery Stage Performance --"<GetBladesPerformances().at(ZONE_0).at(nSpan)->GetInletState(); + auto OutState = TurboPerf->GetBladesPerformances().at(nZone-1).at(nSpan)->GetOutletState(); + + TurboStagePerf->ComputePerformanceStage(InState, OutState, config); + + /*--- Print Machine Performance (In future also add if the performance is TURBINE or COMPRESSOR) ---*/ + TurboInOut<<"MACHINE"<GetNormEntropyGen()*100 + <GetEulerianWork() + <GetTotalStaticEfficiency()*100 + <GetTotalTotalEfficiency()*100 + <GetTotalStaticPressureRatio() + <GetTotalTotalPressureRatio(); + TurboInOut.PrintFooter(); + cout<GetTemperature_FreeStreamND(); @@ -270,6 +274,8 @@ CEulerSolver::CEulerSolver(CGeometry *geometry, CConfig *config, Exhaust_Temperature[iMarker] = Temperature_Inf; Exhaust_Pressure[iMarker] = Pressure_Inf; Exhaust_Area[iMarker] = 0.0; + + AverageMassFlowRate[iMarker] = 0.0; } /*--- Initialize the solution to the far-field state everywhere. ---*/ @@ -364,6 +370,11 @@ void CEulerSolver::InstantiateEdgeNumerics(const CSolver* const* solver_containe SU2_OMP_BARRIER } +// TODO: This is being moved to FluidIteration +void CEulerSolver::InitTurboPerformance(CGeometry *geometry, CConfig *config){ + TurbomachineryPerformance = std::make_shared(*config, *geometry, *GetFluidModel()); +} + void CEulerSolver::InitTurboContainers(CGeometry *geometry, CConfig *config){ /*--- Initialize quantities for the average process for internal flow ---*/ @@ -6004,7 +6015,7 @@ void CEulerSolver::BC_Giles(CGeometry *geometry, CSolver **solver_container, CNu su2double *Velocity_b, Velocity2_b, Enthalpy_b, Energy_b, Density_b, Pressure_b, Temperature_b; su2double *Velocity_i, Velocity2_i, Energy_i, StaticEnergy_i, Density_i, Pressure_i; - su2double Pressure_e; + su2double Pressure_e, MassFlowRate_e, relfacMassFlowRate; su2double *V_boundary, *V_domain, *S_boundary, *S_domain; unsigned short iZone = config->GetiZone(); bool implicit = (config->GetKind_TimeIntScheme() == EULER_IMPLICIT); @@ -6240,7 +6251,7 @@ void CEulerSolver::BC_Giles(CGeometry *geometry, CSolver **solver_container, CNu } - /* --- Compute average jump of charachteristic variable at the mixing-plane interface--- */ + /* --- Compute average jump of charachteristic variable at the mixing-plane interface --- */ GetFluidModel()->SetTDState_Prho(AveragePressure[val_marker][iSpan], AverageDensity[val_marker][iSpan]); AverageSoundSpeed = GetFluidModel()->GetSoundSpeed(); conv_numerics->GetCharJump(AverageSoundSpeed, AverageDensity[val_marker][iSpan], deltaprim, c_avg); @@ -6304,6 +6315,24 @@ void CEulerSolver::BC_Giles(CGeometry *geometry, CSolver **solver_container, CNu break; + case MASS_FLOW_OUTLET: + /*--- Prescribe mass flow rate at the outlet boundary. ---*/ + // TODO: add mass flow rate normalization to allow for non-dimensional simulation + // TODO: implement adapative relfacMassFlowRate + MassFlowRate_e = config->GetGiles_Var1(Marker_Tag); + relfacMassFlowRate = config->GetGiles_Var2(Marker_Tag); + Pressure_e = AveragePressure[val_marker][nSpanWiseSections]+relfacMassFlowRate*(AverageMassFlowRate[val_marker]-MassFlowRate_e); + + /* --- Compute avg characteristic jump --- */ + if (nDim == 2){ + c_avg[3] = -2.0*(AveragePressure[val_marker][nSpanWiseSections]-Pressure_e); + } + else + { + c_avg[4] = -2.0*(AveragePressure[val_marker][nSpanWiseSections]-Pressure_e); + } + break; + } /*--- Loop over all the vertices on this boundary marker ---*/ @@ -6475,7 +6504,7 @@ void CEulerSolver::BC_Giles(CGeometry *geometry, CSolver **solver_container, CNu break; - case STATIC_PRESSURE:case STATIC_PRESSURE_1D:case MIXING_OUT:case RADIAL_EQUILIBRIUM:case MIXING_OUT_1D: + case STATIC_PRESSURE:case STATIC_PRESSURE_1D:case MIXING_OUT:case RADIAL_EQUILIBRIUM:case MIXING_OUT_1D:case MASS_FLOW_OUTLET: /* --- implementation of Giles BC---*/ if(config->GetSpatialFourier()){ @@ -6701,7 +6730,6 @@ void CEulerSolver::BC_Giles(CGeometry *geometry, CSolver **solver_container, CNu Jacobian.SubtractBlock2Diag(iPoint, residual.jacobian_i); } - } END_SU2_OMP_FOR } @@ -9096,7 +9124,7 @@ void CEulerSolver::TurboAverageProcess(CSolver **solver, CGeometry *geometry, CC /*--- Retrieve Old Solution ---*/ - /*--- Loop over the vertices to sum all the quantities pithc-wise ---*/ + /*--- Loop over the vertices to sum all the quantities pitch-wise ---*/ if(iSpan < nSpanWiseSections){ for (iVertex = 0; iVertex < geometry->GetnVertexSpan(iMarker,iSpan); iVertex++) { iPoint = geometry->turbovertex[iMarker][iSpan][iVertex]->GetNode(); @@ -9377,6 +9405,11 @@ void CEulerSolver::TurboAverageProcess(CSolver **solver, CGeometry *geometry, CC avgMixNu = avgMassNu; } + /*--- Store averaged value of mass flow rate over the prescribed boundary, as needed for the mass flow rate BC ---*/ + if (iSpan == nSpanWiseSections){ + AverageMassFlowRate[iMarker] = TotalFluxes[0]; + } + /*--- Store averaged value for the selected average method ---*/ switch(average_process){ case ALGEBRAIC: diff --git a/TestCases/rans/vki_turbine/turb_vki.cfg b/TestCases/rans/vki_turbine/turb_vki.cfg index 80837552d2c6..7b2ae3ae3fef 100644 --- a/TestCases/rans/vki_turbine/turb_vki.cfg +++ b/TestCases/rans/vki_turbine/turb_vki.cfg @@ -23,7 +23,7 @@ KIND_TURB_MODEL= SA MATH_PROBLEM= DIRECT % % Restart solution (NO, YES) -RESTART_SOL= YES +RESTART_SOL= NO % -------------------- COMPRESSIBLE FREE-STREAM DEFINITION --------------------% % @@ -108,7 +108,7 @@ CFL_ADAPT= NO CFL_ADAPT_PARAM= ( 1.5, 0.5, 1.0, 100.0 ) % % Number of total iterations -EXT_ITER= 10 +ITER= 1000 % % Linear solver for the implicit formulation (BCGSTAB, FGMRES) LINEAR_SOLVER= FGMRES @@ -199,7 +199,7 @@ CONV_CAUCHY_EPS= 1E-6 % ------------------------- INPUT/OUTPUT INFORMATION --------------------------% % % Mesh input file -MESH_FILENAME= mesh_vki_turbine_prepbc.su2 +MESH_FILENAME= mesh_vki_turbine.su2 % % Mesh input file format (SU2, CGNS, NETCDF_ASCII) MESH_FORMAT= SU2 @@ -236,6 +236,7 @@ GRAD_OBJFUNC_FILENAME= of_grad.dat % % Output file surface flow coefficient (w/o extension) SURFACE_FILENAME= surface_flow + % % Output file surface adjoint coefficient (w/o extension) SURFACE_ADJ_FILENAME= surface_adjoint diff --git a/TestCases/turbomachinery/transonic_stator_2D/transonic_stator_rst.cfg b/TestCases/turbomachinery/transonic_stator_2D/transonic_stator_rst.cfg index 48778dcf05f4..c5bf6f39d0a4 100644 --- a/TestCases/turbomachinery/transonic_stator_2D/transonic_stator_rst.cfg +++ b/TestCases/turbomachinery/transonic_stator_2D/transonic_stator_rst.cfg @@ -24,7 +24,7 @@ KIND_TURB_MODEL= SST MATH_PROBLEM= DIRECT % % Restart solution (NO, YES) -RESTART_SOL= YES +RESTART_SOL= NO % % Discard the data storaged in the solution and geometry files % e.g. AOA, dCL/dAoA, dCD/dCL, iter, etc. @@ -313,7 +313,7 @@ SOLUTION_FILENAME= solution_flow_sst.dat SOLUTION_ADJ_FILENAME= solution_adj.dat % % Output file format (PARAVIEW, TECPLOT, STL) -TABULAR_FORMAT= CSV +TABULAR_FORMAT= TECPLOT % % Output file convergence history (w/o extension) CONV_FILENAME= history