@@ -818,6 +818,234 @@ void CFVMFlowSolverBase<V, R>::SetUniformInlet(const CConfig* config, unsigned s
818818 }
819819}
820820
821+ template <class V , ENUM_REGIME R>
822+ void CFVMFlowSolverBase<V, R>::LoadRestart_impl(CGeometry **geometry, CSolver ***solver, CConfig *config,
823+ int iter, bool update_geo, su2double* SolutionRestart,
824+ unsigned short nVar_Restart) {
825+
826+ /* --- Restart the solution from file information ---*/
827+
828+ unsigned short iDim, iVar, iMesh, iMeshFine;
829+ unsigned long iPoint, index, iChildren, Point_Fine;
830+ unsigned short turb_model = config->GetKind_Turb_Model ();
831+ su2double Area_Children, Area_Parent;
832+ const su2double* Solution_Fine = nullptr ;
833+ const passivedouble* Coord = nullptr ;
834+ bool dual_time = ((config->GetTime_Marching () == DT_STEPPING_1ST) ||
835+ (config->GetTime_Marching () == DT_STEPPING_2ND));
836+ bool static_fsi = ((config->GetTime_Marching () == STEADY) && config->GetFSI_Simulation ());
837+ bool steady_restart = config->GetSteadyRestart ();
838+ bool turbulent = (config->GetKind_Turb_Model () != NONE);
839+
840+ string restart_filename = config->GetFilename (config->GetSolution_FileName (), " " , iter);
841+
842+ /* --- To make this routine safe to call in parallel most of it can only be executed by one thread. ---*/
843+ SU2_OMP_MASTER {
844+
845+ if (nVar_Restart == 0 ) nVar_Restart = nVar;
846+
847+ /* --- Skip coordinates ---*/
848+
849+ unsigned short skipVars = geometry[MESH_0]->GetnDim ();
850+
851+ /* --- Store the number of variables for the turbulence model
852+ (that could appear in the restart file before the grid velocities). ---*/
853+ unsigned short turbVars = 0 ;
854+ if (turbulent){
855+ if ((turb_model == SST) || (turb_model == SST_SUST)) turbVars = 2 ;
856+ else turbVars = 1 ;
857+ }
858+
859+ /* --- Read the restart data from either an ASCII or binary SU2 file. ---*/
860+
861+ if (config->GetRead_Binary_Restart ()) {
862+ Read_SU2_Restart_Binary (geometry[MESH_0], config, restart_filename);
863+ } else {
864+ Read_SU2_Restart_ASCII (geometry[MESH_0], config, restart_filename);
865+ }
866+
867+ /* --- Load data from the restart into correct containers. ---*/
868+
869+ unsigned long counter = 0 , iPoint_Global = 0 ;
870+ for (; iPoint_Global < geometry[MESH_0]->GetGlobal_nPointDomain (); iPoint_Global++) {
871+
872+ /* --- Retrieve local index. If this node from the restart file lives
873+ on the current processor, we will load and instantiate the vars. ---*/
874+
875+ auto iPoint_Local = geometry[MESH_0]->GetGlobal_to_Local_Point (iPoint_Global);
876+
877+ if (iPoint_Local > -1 ) {
878+
879+ /* --- We need to store this point's data, so jump to the correct
880+ offset in the buffer of data from the restart file and load it. ---*/
881+
882+ index = counter*Restart_Vars[1 ] + skipVars;
883+
884+ if (SolutionRestart == nullptr ) {
885+ nodes->SetSolution (iPoint_Local, &Restart_Data[index]);
886+ }
887+ else {
888+ /* --- Used as buffer, allows defaults for nVar > nVar_Restart. ---*/
889+ for (iVar = 0 ; iVar < nVar_Restart; iVar++)
890+ SolutionRestart[iVar] = Restart_Data[index+iVar];
891+ nodes->SetSolution (iPoint_Local, SolutionRestart);
892+ }
893+
894+ /* --- For dynamic meshes, read in and store the
895+ grid coordinates and grid velocities for each node. ---*/
896+
897+ if (dynamic_grid && update_geo) {
898+
899+ /* --- Read in the next 2 or 3 variables which are the grid velocities ---*/
900+ /* --- If we are restarting the solution from a previously computed static calculation (no grid movement) ---*/
901+ /* --- the grid velocities are set to 0. This is useful for FSI computations ---*/
902+
903+ /* --- Rewind the index to retrieve the Coords. ---*/
904+ index = counter*Restart_Vars[1 ];
905+ Coord = &Restart_Data[index];
906+
907+ su2double GridVel[MAXNDIM] = {0.0 };
908+ if (!steady_restart) {
909+ /* --- Move the index forward to get the grid velocities. ---*/
910+ index += skipVars + nVar_Restart + turbVars;
911+ for (iDim = 0 ; iDim < nDim; iDim++) { GridVel[iDim] = Restart_Data[index+iDim]; }
912+ }
913+
914+ for (iDim = 0 ; iDim < nDim; iDim++) {
915+ geometry[MESH_0]->nodes ->SetCoord (iPoint_Local, iDim, Coord[iDim]);
916+ geometry[MESH_0]->nodes ->SetGridVel (iPoint_Local, iDim, GridVel[iDim]);
917+ }
918+ }
919+
920+ /* --- For static FSI problems, grid_movement is 0 but we need to read in and store the
921+ grid coordinates for each node (but not the grid velocities, as there are none). ---*/
922+
923+ if (static_fsi && update_geo) {
924+ /* --- Rewind the index to retrieve the Coords. ---*/
925+ index = counter*Restart_Vars[1 ];
926+ Coord = &Restart_Data[index];
927+
928+ for (iDim = 0 ; iDim < nDim; iDim++) {
929+ geometry[MESH_0]->nodes ->SetCoord (iPoint_Local, iDim, Coord[iDim]);
930+ }
931+ }
932+
933+ /* --- Increment the overall counter for how many points have been loaded. ---*/
934+ counter++;
935+ }
936+
937+ }
938+
939+ /* --- Detect a wrong solution file ---*/
940+
941+ if (counter != nPointDomain) {
942+ SU2_MPI::Error (string (" The solution file " ) + restart_filename + string (" doesn't match with the mesh file!\n " ) +
943+ string (" It could be empty lines at the end of the file." ), CURRENT_FUNCTION);
944+ }
945+ } // end SU2_OMP_MASTER
946+ SU2_OMP_BARRIER
947+
948+ /* --- Update the geometry for flows on deforming meshes ---*/
949+
950+ if ((dynamic_grid || static_fsi) && update_geo) {
951+
952+ /* --- Communicate the new coordinates and grid velocities at the halos ---*/
953+
954+ geometry[MESH_0]->InitiateComms (geometry[MESH_0], config, COORDINATES);
955+ geometry[MESH_0]->CompleteComms (geometry[MESH_0], config, COORDINATES);
956+
957+ if (dynamic_grid) {
958+ geometry[MESH_0]->InitiateComms (geometry[MESH_0], config, GRID_VELOCITY);
959+ geometry[MESH_0]->CompleteComms (geometry[MESH_0], config, GRID_VELOCITY);
960+ }
961+
962+ /* --- Recompute the edges and dual mesh control volumes in the
963+ domain and on the boundaries. ---*/
964+
965+ geometry[MESH_0]->SetControlVolume (config, UPDATE);
966+ geometry[MESH_0]->SetBoundControlVolume (config, UPDATE);
967+ geometry[MESH_0]->SetMaxLength (config);
968+
969+ /* --- Update the multigrid structure after setting up the finest grid,
970+ including computing the grid velocities on the coarser levels. ---*/
971+
972+ for (iMesh = 1 ; iMesh <= config->GetnMGLevels (); iMesh++) {
973+ iMeshFine = iMesh-1 ;
974+ geometry[iMesh]->SetControlVolume (config, geometry[iMeshFine], UPDATE);
975+ geometry[iMesh]->SetBoundControlVolume (config, geometry[iMeshFine],UPDATE);
976+ geometry[iMesh]->SetCoord (geometry[iMeshFine]);
977+ if (dynamic_grid) {
978+ geometry[iMesh]->SetRestricted_GridVelocity (geometry[iMeshFine], config);
979+ }
980+ geometry[iMesh]->SetMaxLength (config);
981+ }
982+ }
983+
984+ /* --- Communicate the loaded solution on the fine grid before we transfer
985+ it down to the coarse levels. We also call the preprocessing routine
986+ on the fine level in order to have all necessary quantities updated,
987+ especially if this is a turbulent simulation (eddy viscosity). ---*/
988+
989+ solver[MESH_0][FLOW_SOL]->InitiateComms (geometry[MESH_0], config, SOLUTION);
990+ solver[MESH_0][FLOW_SOL]->CompleteComms (geometry[MESH_0], config, SOLUTION);
991+
992+ /* --- For turbulent simulations the flow preprocessing is done by the turbulence solver
993+ * after it loads its variables (they are needed to compute flow primitives). ---*/
994+ if (!turbulent) {
995+ solver[MESH_0][FLOW_SOL]->Preprocessing (geometry[MESH_0], solver[MESH_0], config, MESH_0, NO_RK_ITER, RUNTIME_FLOW_SYS, false );
996+ }
997+
998+ /* --- Interpolate the solution down to the coarse multigrid levels ---*/
999+
1000+ for (iMesh = 1 ; iMesh <= config->GetnMGLevels (); iMesh++) {
1001+ SU2_OMP_FOR_STAT (omp_chunk_size)
1002+ for (iPoint = 0 ; iPoint < geometry[iMesh]->GetnPoint (); iPoint++) {
1003+ Area_Parent = geometry[iMesh]->nodes ->GetVolume (iPoint);
1004+ su2double Solution_Coarse[MAXNVAR] = {0.0 };
1005+ for (iChildren = 0 ; iChildren < geometry[iMesh]->nodes ->GetnChildren_CV (iPoint); iChildren++) {
1006+ Point_Fine = geometry[iMesh]->nodes ->GetChildren_CV (iPoint, iChildren);
1007+ Area_Children = geometry[iMesh-1 ]->nodes ->GetVolume (Point_Fine);
1008+ Solution_Fine = solver[iMesh-1 ][FLOW_SOL]->GetNodes ()->GetSolution (Point_Fine);
1009+ for (iVar = 0 ; iVar < nVar; iVar++) {
1010+ Solution_Coarse[iVar] += Solution_Fine[iVar]*Area_Children/Area_Parent;
1011+ }
1012+ }
1013+ solver[iMesh][FLOW_SOL]->GetNodes ()->SetSolution (iPoint,Solution_Coarse);
1014+ }
1015+
1016+ solver[iMesh][FLOW_SOL]->InitiateComms (geometry[iMesh], config, SOLUTION);
1017+ solver[iMesh][FLOW_SOL]->CompleteComms (geometry[iMesh], config, SOLUTION);
1018+
1019+ if (!turbulent) {
1020+ solver[iMesh][FLOW_SOL]->Preprocessing (geometry[iMesh], solver[iMesh], config, iMesh, NO_RK_ITER, RUNTIME_FLOW_SYS, false );
1021+ }
1022+ }
1023+
1024+ /* --- Update the old geometry (coordinates n and n-1) in dual time-stepping strategy. ---*/
1025+ if (dual_time && config->GetGrid_Movement () && !config->GetDeform_Mesh () &&
1026+ (config->GetKind_GridMovement () != RIGID_MOTION)) {
1027+ Restart_OldGeometry (geometry[MESH_0], config);
1028+ }
1029+
1030+ /* --- Go back to single threaded execution. ---*/
1031+ SU2_OMP_MASTER
1032+ {
1033+ /* --- Delete the class memory that is used to load the restart. ---*/
1034+
1035+ delete [] Restart_Vars; Restart_Vars = nullptr ;
1036+ delete [] Restart_Data; Restart_Data = nullptr ;
1037+
1038+ } // end SU2_OMP_MASTER
1039+ SU2_OMP_BARRIER
1040+
1041+ }
1042+
1043+ template <class V , ENUM_REGIME R>
1044+ void CFVMFlowSolverBase<V, R>::LoadRestart(CGeometry **geometry, CSolver ***solver,
1045+ CConfig *config, int iter, bool update_geo) {
1046+ LoadRestart_impl (geometry, solver, config, iter, update_geo);
1047+ }
1048+
8211049template <class V , ENUM_REGIME R>
8221050void CFVMFlowSolverBase<V, R>::PushSolutionBackInTime(unsigned long TimeIter, bool restart, bool rans,
8231051 CSolver*** solver_container, CGeometry** geometry,
0 commit comments