77!> @brief AMR hierarchy (SP1: one static, inert refined level-1 patch alongside the base solve).
88module m_amr
99
10+ #ifdef MFC_MPI
11+ use mpi !< MPI- IO for the parallel_io AMR restart file
12+ #endif
13+
1014 use m_derived_types ! scalar_field, t_box, int_bounds_info
1115 use m_global_parameters
1216 use m_constants, only: num_fluids_max
@@ -23,7 +27,8 @@ module m_amr
2327 public :: t_level, amr_fine, amr_maxc, amr_dt_fine, s_initialize_amr_module, s_populate_amr_fine, &
2428 & s_interpolate_coarse_to_fine, s_restrict_fine_to_coarse, s_amr_conservation_check, s_finalize_amr_module, &
2529 & s_amr_swap_to_fine, s_amr_restore_coarse, s_amr_fill_fine_ghosts, s_amr_operator_checks, s_advance_amr_fine_stage, &
26- & s_advance_amr_fine_substeps, s_amr_conservation_defect, s_set_amr_fine_geometry, s_amr_regrid
30+ & s_advance_amr_fine_substeps, s_amr_conservation_defect, s_set_amr_fine_geometry, s_amr_regrid, s_write_amr_restart, &
31+ & s_read_amr_restart
2732
2833 !> Fine- level time step for subcycling (= 0.5 * dt after init; 0 when amr is off).
2934 real (wp) :: amr_dt_fine = 0._wp
@@ -1160,6 +1165,206 @@ contains
11601165
11611166 end subroutine s_amr_regrid
11621167
1168+ !> Write the fine- level restart file for save step t_step alongside the level-0 restart (whose format stays untouched): the
1169+ !! CURRENT patch box (it moves under regrid), the writing rank count, and each rank' s intersection-local fine conservative
1170+ !! state. Serial mode: one unformatted file per rank inside its level-0 step directory. Parallel mode: one shared MPI-IO file
1171+ !! with a 7-integer header (np, box lo, box hi) followed by the ranks' fine blocks concatenated in rank order.
1172+ impure subroutine s_write_amr_restart (t_step )
1173+
1174+ integer , intent (in ) :: t_step
1175+ character (LEN= path_len + 3 * name_len) :: file_loc
1176+ integer :: i
1177+
1178+ #ifdef MFC_MPI
1179+ integer :: ifile, ierr, cnt, idx, fi, fj, fk, hdr(7 )
1180+ integer , dimension (MPI_STATUS_SIZE) :: status
1181+ integer (kind= MPI_OFFSET_KIND) :: my_cnt, my_off, disp
1182+ logical :: file_exist
1183+ real (stp), allocatable :: buf(:)
1184+ #endif
1185+
1186+ if (.not. amr) return
1187+ ! host consumer: the fine state is device- current during stepping
1188+ if (amr_rank_owns_patch) then
1189+ do i = 1 , sys_size
1190+ $:GPU_UPDATE(host= ' [amr_fine%q_cons(i)%sf]' )
1191+ end do
1192+ end if
1193+
1194+ if (.not. parallel_io) then
1195+ ! per- rank file in the step directory freshly created by the level-0 serial write
1196+ write (file_loc, ' (A,I0,A,I0,A)' ) trim (case_dir) // ' /p_all/p' , proc_rank, ' /' , t_step, ' /amr_fine.dat'
1197+ open (2 , FILE= trim (file_loc), form= ' unformatted' , STATUS= ' new' )
1198+ write (2 ) num_procs, amr_fine%region%lo, amr_fine%region%hi, amr_fine%m, amr_fine%n, amr_fine%p
1199+ if (amr_rank_owns_patch) then
1200+ do i = 1 , sys_size
1201+ write (2 ) amr_fine%q_cons(i)%sf(0 :amr_fine%m,0 :amr_fine%n,0 :amr_fine%p)
1202+ end do
1203+ end if
1204+ close (2 )
1205+ else
1206+ #ifdef MFC_MPI
1207+ write (file_loc, ' (A,I0,A)' ) ' amr_' , t_step, ' .dat'
1208+ file_loc = trim (case_dir) // ' /restart_data' // trim (mpiiofs) // trim (file_loc)
1209+ inquire (FILE= trim (file_loc), EXIST= file_exist)
1210+ if (file_exist .and. proc_rank == 0 ) then
1211+ call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
1212+ end if
1213+ call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, ior (MPI_MODE_WRONLY, MPI_MODE_CREATE), mpi_info_int, ifile, ierr)
1214+
1215+ ! rank- order concatenation offset: exclusive prefix sum of the per- rank block sizes
1216+ cnt = sys_size* (amr_fine%m + 1 )* (amr_fine%n + 1 )* (amr_fine%p + 1 ) ! 0 on ranks without fine cells
1217+ if (.not. amr_rank_owns_patch) cnt = 0
1218+ my_cnt = int (cnt, MPI_OFFSET_KIND)
1219+ my_off = int (0 , MPI_OFFSET_KIND)
1220+ call MPI_EXSCAN(my_cnt, my_off, 1 , MPI_OFFSET, MPI_SUM, MPI_COMM_WORLD, ierr)
1221+ if (proc_rank == 0 ) then
1222+ my_off = int (0 , MPI_OFFSET_KIND)
1223+ hdr(1 ) = num_procs; hdr(2 :4 ) = amr_fine%region%lo; hdr(5 :7 ) = amr_fine%region%hi
1224+ call MPI_FILE_WRITE_AT(ifile, int (0 , MPI_OFFSET_KIND), hdr, 7 , MPI_INTEGER, status, ierr)
1225+ end if
1226+ allocate (buf(max (cnt, 1 )))
1227+ idx = 0
1228+ do i = 1 , sys_size
1229+ do fk = 0 , amr_fine%p
1230+ do fj = 0 , amr_fine%n
1231+ do fi = 0 , amr_fine%m
1232+ idx = idx + 1
1233+ buf(idx) = amr_fine%q_cons(i)%sf(fi, fj, fk)
1234+ end do
1235+ end do
1236+ end do
1237+ end do
1238+ disp = int (7 * storage_size(0 )/ 8 , MPI_OFFSET_KIND) + my_off* int (storage_size(0._stp )/ 8 , MPI_OFFSET_KIND)
1239+ call MPI_FILE_WRITE_AT_ALL(ifile, disp, buf, cnt* mpi_io_type, mpi_io_p, status, ierr)
1240+ deallocate (buf)
1241+ call MPI_FILE_CLOSE(ifile, ierr)
1242+ #endif
1243+ end if
1244+
1245+ end subroutine s_write_amr_restart
1246+
1247+ !> Restore the fine level from the AMR restart file at t_step_start (n_start under cfl_dt), if one exists: rebuild the saved
1248+ !! (possibly regridded) box via s_set_amr_fine_geometry, then read each rank' s intersection-local fine state (exact stp
1249+ !! round-trip). Requires the rank count that wrote the file (np-flexible restart is a follow-up). restored = false on a fresh
1250+ !! start, or - with a one-line warning - on a legacy restart without the file; the caller then re-prolongs from coarse.
1251+ !! Collective: ALL ranks must call together (the existence decision is allreduced).
1252+ impure subroutine s_read_amr_restart(restored)
1253+
1254+ logical, intent(out) :: restored
1255+ character(LEN=path_len + 3*name_len) :: file_loc
1256+ character(LEN=200) :: msg
1257+ logical :: file_exist
1258+ integer :: i, ts, have_loc, have_glb, hdr(7), rm, rn, rp
1259+
1260+ #ifdef MFC_MPI
1261+ integer :: ifile, ierr, cnt, idx, fi, fj, fk
1262+ integer, dimension(MPI_STATUS_SIZE) :: status
1263+ integer(kind=MPI_OFFSET_KIND) :: my_cnt, my_off, tot_cnt, disp, file_sz
1264+ real(stp), allocatable :: buf(:)
1265+ #endif
1266+
1267+ restored = .false.
1268+ if (.not. amr) return
1269+ if (cfl_dt) then
1270+ ts = n_start
1271+ else
1272+ ts = t_step_start
1273+ end if
1274+ if (ts == 0) return ! fresh start: the fine level is prolonged from the pre_process ICs
1275+
1276+ if (.not. parallel_io) then
1277+ write (file_loc, ' (A,I0,A,I0,A)' ) trim(case_dir) // ' / p_all/ p' , proc_rank, ' / ' , ts, ' / amr_fine.dat'
1278+ else
1279+ write (file_loc, ' (A,I0,A)' ) ' amr_' , ts, ' .dat'
1280+ file_loc = trim(case_dir) // ' / restart_data' // trim(mpiiofs) // trim(file_loc)
1281+ end if
1282+ inquire (FILE=trim(file_loc), EXIST=file_exist)
1283+ have_loc = merge(1, 0, file_exist)
1284+ call s_mpi_allreduce_integer_min(have_loc, have_glb)
1285+ if (have_glb == 0) then
1286+ if (proc_rank == 0) then
1287+ print ' (A)' , &
1288+ & ' [amr] WARNING: no AMR restart file at this step; the fine level is re- initialized by ' &
1289+ & // ' prolongation from coarse (fine- level accuracy is lost across this restart)'
1290+ end if
1291+ return
1292+ end if
1293+
1294+ if (.not. parallel_io) then
1295+ open (2, FILE=trim(file_loc), form=' unformatted' , ACTION=' read ' , STATUS=' old' )
1296+ read (2) hdr, rm, rn, rp
1297+ if (hdr(1) /= num_procs) then
1298+ write (msg, ' (A,I0,A,I0,A)' ) ' amr restart rank- count mismatch: the AMR restart file was written with ' , hdr(1), &
1299+ & ' ranks but this run has ' , num_procs, ' ; restart with the same rank count'
1300+ call s_mpi_abort(trim(msg))
1301+ end if
1302+ call s_set_amr_fine_geometry(hdr(2:4), hdr(5:7))
1303+ if (rm /= amr_fine%m .or. rn /= amr_fine%n .or. rp /= amr_fine%p) then
1304+ call s_mpi_abort(' amr restart decomposition mismatch: this rank' ' s fine extents differ from the file' &
1305+ & // ' (identical decomposition - rank count and load_balance settings - required)' )
1306+ end if
1307+ if (amr_rank_owns_patch) then
1308+ do i = 1, sys_size
1309+ read (2) amr_fine%q_cons(i)%sf(0:amr_fine%m,0:amr_fine%n,0:amr_fine%p)
1310+ end do
1311+ end if
1312+ close (2)
1313+ else
1314+ #ifdef MFC_MPI
1315+ call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, MPI_MODE_RDONLY, mpi_info_int, ifile, ierr)
1316+ call MPI_FILE_READ_AT_ALL(ifile, int(0, MPI_OFFSET_KIND), hdr, 7, MPI_INTEGER, status, ierr)
1317+ if (hdr(1) /= num_procs) then
1318+ write (msg, ' (A,I0,A,I0,A)' ) ' amr restart rank- count mismatch: the AMR restart file was written with ' , hdr(1), &
1319+ & ' ranks but this run has ' , num_procs, ' ; restart with the same rank count'
1320+ call s_mpi_abort(trim(msg))
1321+ end if
1322+ call s_set_amr_fine_geometry(hdr(2:4), hdr(5:7))
1323+ cnt = sys_size*(amr_fine%m + 1)*(amr_fine%n + 1)*(amr_fine%p + 1)
1324+ if (.not. amr_rank_owns_patch) cnt = 0
1325+ my_cnt = int(cnt, MPI_OFFSET_KIND)
1326+ my_off = int(0, MPI_OFFSET_KIND)
1327+ call MPI_EXSCAN(my_cnt, my_off, 1, MPI_OFFSET, MPI_SUM, MPI_COMM_WORLD, ierr)
1328+ if (proc_rank == 0) my_off = int(0, MPI_OFFSET_KIND)
1329+ call MPI_ALLREDUCE(my_cnt, tot_cnt, 1, MPI_OFFSET, MPI_SUM, MPI_COMM_WORLD, ierr)
1330+ call MPI_FILE_GET_SIZE(ifile, file_sz, ierr)
1331+ if (file_sz /= int(7*storage_size(0)/8, MPI_OFFSET_KIND) + tot_cnt*int(storage_size(0._stp)/8, MPI_OFFSET_KIND)) then
1332+ call s_mpi_abort(' amr restart decomposition mismatch: the AMR restart file size differs from this run' ' s' &
1333+ & // ' fine intersections (identical decomposition - rank count and load_balance settings' &
1334+ & // ' - required)' )
1335+ end if
1336+ allocate (buf(max(cnt, 1)))
1337+ disp = int(7*storage_size(0)/8, MPI_OFFSET_KIND) + my_off*int(storage_size(0._stp)/8, MPI_OFFSET_KIND)
1338+ call MPI_FILE_READ_AT_ALL(ifile, disp, buf, cnt*mpi_io_type, mpi_io_p, status, ierr)
1339+ idx = 0
1340+ do i = 1, sys_size
1341+ do fk = 0, amr_fine%p
1342+ do fj = 0, amr_fine%n
1343+ do fi = 0, amr_fine%m
1344+ idx = idx + 1
1345+ amr_fine%q_cons(i)%sf(fi, fj, fk) = buf(idx)
1346+ end do
1347+ end do
1348+ end do
1349+ end do
1350+ deallocate (buf)
1351+ call MPI_FILE_CLOSE(ifile, ierr)
1352+ #endif
1353+ end if
1354+
1355+ ! restored fine state to the device (mirrors s_populate_amr_fine' s push; host reads above)
1356+ if (amr_rank_owns_patch) then
1357+ do i = 1 , sys_size
1358+ $:GPU_UPDATE(device= ' [amr_fine%q_cons(i)%sf]' )
1359+ end do
1360+ end if
1361+ restored = .true.
1362+ if (proc_rank == 0 ) then
1363+ print ' (A,I0,A,I0)' , ' [amr] restart: restored fine level, box x ' , amr_fine%region%lo(1 ), ' :' , amr_fine%region%hi(1 )
1364+ end if
1365+
1366+ end subroutine s_read_amr_restart
1367+
11631368 !> Global Sum (dV* U) for the per- fluid masses (continuity variables) and energy (eqn_idx%E) over the level-0 interior. First call
11641369 !! (finalize_report= F) stores the baselines; the finalize call prints the relative drifts (~roundoff with refluxing).
11651370 impure subroutine s_amr_conservation_defect (q_cons_base , finalize_report )
0 commit comments