MFC
Exascale flow solver
Loading...
Searching...
No Matches
m_data_output.fpp.f90
Go to the documentation of this file.
1# 1 "/home/runner/work/MFC/MFC/src/pre_process/m_data_output.fpp"
2!>
3!! @file
4!! @brief Contains module m_data_output
5
6!> @brief Writes grid and initial condition data to serial or parallel output files
8
11 use m_helper
12 use m_mpi_proxy
13#ifdef MFC_MPI
14 use mpi
15#endif
16
19 use m_helper
24 use m_thermochem, only: species_names
25 use m_helper
27
28 implicit none
29
30 private
33
34 type(scalar_field), allocatable, dimension(:) :: q_cons_temp
35
36 abstract interface
37
38 !> Interface for the conservative data
39 impure subroutine s_write_abstract_data_files(q_cons_vf, q_prim_vf, bc_type, q_T_sf)
40
41 import :: scalar_field, integer_field, sys_size, m, n, p, pres_field, num_dims
42
43 type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf, q_prim_vf
44 type(integer_field), dimension(1:num_dims,-1:1), intent(in) :: bc_type
45 type(scalar_field), intent(inout), optional :: q_t_sf
46
47 end subroutine s_write_abstract_data_files
48 end interface
49
50 !> Time-step folder into which grid and initial condition data will be placed
51 character(LEN=path_len + 2*name_len), private :: t_step_dir
52 character(LEN=path_len + 2*name_len), public :: restart_dir !< Restart data folder
53 procedure(s_write_abstract_data_files), pointer :: s_write_data_files => null()
54
55contains
56
57 !> Writes grid and initial condition data files to the "0" time-step directory in the local processor rank folder
58 impure subroutine s_write_serial_data_files(q_cons_vf, q_prim_vf, bc_type, q_T_sf)
59
60 type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf, q_prim_vf
61 type(integer_field), dimension(1:num_dims,-1:1), intent(in) :: bc_type
62 logical :: file_exist
63 character(LEN=15) :: fmt
64 character(LEN=3) :: status
65 character(len=int(floor(log10(real(sys_size, wp)))) + 1) :: file_num
66 character(LEN=len_trim(t_step_dir) + name_len) :: file_loc
67 integer :: i, j, k, l, r, c
68 integer :: t_step
69 real(wp), dimension(nb) :: nrtmp
70 real(wp) :: nbub
71 real(wp) :: gamma, pi_inf, qv
72 real(wp) :: rho
73 real(wp) :: pres, t
74 real(wp) :: rhoyks(1:num_species)
75 real(wp) :: pres_mag
76 type(scalar_field), intent(inout), optional :: q_t_sf
77
78 pres_mag = 0._wp
79
80 t = dflt_t_guess
81
82 t_step = 0
83
84 if (old_grid) then
85 status = 'old'
86 else
87 status = 'new'
88 end if
89
90 if (bc_io) then
91 if (igr) then
93 else
94 call s_write_serial_boundary_condition_files(q_prim_vf, bc_type, t_step_dir, old_grid, q_t_sf)
95 end if
96 end if
97
98 file_loc = trim(t_step_dir) // '/x_cb.dat'
99 open (1, file=trim(file_loc), form='unformatted', status=status)
100 write (1) x_cb(-1:m)
101 close (1)
102
103 if (n > 0) then
104 file_loc = trim(t_step_dir) // '/y_cb.dat'
105 open (1, file=trim(file_loc), form='unformatted', status=status)
106 write (1) y_cb(-1:n)
107 close (1)
108
109 if (p > 0) then
110 file_loc = trim(t_step_dir) // '/z_cb.dat'
111 open (1, file=trim(file_loc), form='unformatted', status=status)
112 write (1) z_cb(-1:p)
113 close (1)
114 end if
115 end if
116
117 do i = 1, sys_size
118 write (file_num, '(I0)') i
119 file_loc = trim(t_step_dir) // '/q_cons_vf' // trim(file_num) // '.dat'
120 open (1, file=trim(file_loc), form='unformatted', status=status)
121 write (1) q_cons_vf(i)%sf(0:m,0:n,0:p)
122 close (1)
123 end do
124
125 if (bubbles_lagrange) then
126 block
127 real(stp), allocatable :: beta_ones(:,:,:)
128 character(LEN=len_trim(t_step_dir) + name_len) :: beta_file_loc
129 integer :: jj, kk, ll
130 allocate (beta_ones(0:m,0:n,0:p))
131 do ll = 0, p
132 do kk = 0, n
133 do jj = 0, m
134 beta_ones(jj, kk, ll) = 1.0_stp
135 end do
136 end do
137 end do
138 write (beta_file_loc, '(A,I0,A)') trim(t_step_dir) // '/q_cons_vf', sys_size + 1, '.dat'
139 open (1, file=trim(beta_file_loc), form='unformatted', status=status)
140 write (1) beta_ones
141 close (1)
142 deallocate (beta_ones)
143 end block
144 end if
145
146 if (qbmm .and. .not. polytropic) then
147 do i = 1, nb
148 do r = 1, nnode
149 write (file_num, '(I0)') r + (i - 1)*nnode + sys_size
150 file_loc = trim(t_step_dir) // '/pb' // trim(file_num) // '.dat'
151 open (1, file=trim(file_loc), form='unformatted', status=status)
152 write (1) pb%sf(:,:,:,r, i)
153 close (1)
154 end do
155 end do
156
157 do i = 1, nb
158 do r = 1, nnode
159 write (file_num, '(I0)') r + (i - 1)*nnode + sys_size
160 file_loc = trim(t_step_dir) // '/mv' // trim(file_num) // '.dat'
161 open (1, file=trim(file_loc), form='unformatted', status=status)
162 write (1) mv%sf(:,:,:,r, i)
163 close (1)
164 end do
165 end do
166 end if
167
168 if (precision == precision_single) then
169 fmt = "(2F30.3)"
170 else
171 fmt = "(2F40.14)"
172 end if
173
174 write (t_step_dir, '(A,I0,A,I0)') trim(case_dir) // '/D'
175 file_loc = trim(t_step_dir) // '/.'
176
177 inquire (file=trim(file_loc), exist=file_exist)
178
179 if (.not. file_exist) call s_create_directory(trim(t_step_dir))
180
181 if (cfl_dt) t_step = n_start
182
183 if (n == 0 .and. p == 0) then
184 if (model_eqns == model_eqns_5eq) then
185 do i = 1, sys_size
186 write (file_loc, '(A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/prim.', i, '.', proc_rank, '.', t_step, '.dat'
187
188 open (2, file=trim(file_loc))
189 do j = 0, m
190 if (chemistry) then
191 do c = 1, num_species
192 rhoyks(c) = q_cons_vf(eqn_idx%species%beg + c - 1)%sf(j, 0, 0)
193 end do
194 end if
195
196 call s_convert_to_mixture_variables(q_cons_vf, j, 0, 0, rho, gamma, pi_inf, qv)
197
198 if ((i >= eqn_idx%species%beg) .and. (i <= eqn_idx%species%end)) then
199 write (2, fmt) x_cb(j), q_cons_vf(i)%sf(j, 0, 0)/rho
200 else if (((i >= eqn_idx%cont%beg) .and. (i <= eqn_idx%cont%end)) .or. ((i >= eqn_idx%adv%beg) &
201 & .and. (i <= eqn_idx%adv%end)) .or. ((i >= eqn_idx%species%beg) .and. (i <= eqn_idx%species%end) &
202 & )) then
203 write (2, fmt) x_cb(j), q_cons_vf(i)%sf(j, 0, 0)
204 else if (i == eqn_idx%mom%beg) then ! u
205 write (2, fmt) x_cb(j), q_cons_vf(eqn_idx%mom%beg)%sf(j, 0, 0)/rho
206 else if (i == eqn_idx%stress%beg) then ! tau_e
207 write (2, fmt) x_cb(j), q_cons_vf(eqn_idx%stress%beg)%sf(j, 0, 0)/rho
208 else if (i == eqn_idx%E) then ! p
209 if (mhd) then
210 pres_mag = 0.5_wp*(bx0**2 + q_cons_vf(eqn_idx%B%beg)%sf(j, 0, &
211 & 0)**2 + q_cons_vf(eqn_idx%B%beg + 1)%sf(j, 0, 0)**2)
212 end if
213
214 call s_compute_pressure(q_cons_vf(eqn_idx%E)%sf(j, 0, 0), q_cons_vf(eqn_idx%alf)%sf(j, 0, 0), &
215 & 0.5_wp*(q_cons_vf(eqn_idx%mom%beg)%sf(j, 0, 0)**2._wp)/rho, pi_inf, gamma, &
216 & rho, qv, rhoyks, pres, t, pres_mag=pres_mag)
217 write (2, fmt) x_cb(j), pres
218 else if (mhd) then
219 if (i == eqn_idx%mom%beg + 1) then ! v
220 write (2, fmt) x_cb(j), q_cons_vf(eqn_idx%mom%beg + 1)%sf(j, 0, 0)/rho
221 else if (i == eqn_idx%mom%beg + 2) then ! w
222 write (2, fmt) x_cb(j), q_cons_vf(eqn_idx%mom%beg + 2)%sf(j, 0, 0)/rho
223 else if (i == eqn_idx%B%beg) then ! By
224 write (2, fmt) x_cb(j), q_cons_vf(eqn_idx%B%beg)%sf(j, 0, 0)/rho
225 else if (i == eqn_idx%B%beg + 1) then ! Bz
226 write (2, fmt) x_cb(j), q_cons_vf(eqn_idx%B%beg + 1)%sf(j, 0, 0)/rho
227 end if
228 else if ((i >= eqn_idx%bub%beg) .and. (i <= eqn_idx%bub%end) .and. bubbles_euler) then
229 if (qbmm) then
230 nbub = q_cons_vf(eqn_idx%bub%beg)%sf(j, 0, 0)
231 else
232 if (adv_n) then
233 nbub = q_cons_vf(eqn_idx%n)%sf(j, 0, 0)
234 else
235 do k = 1, nb
236 nrtmp(k) = q_cons_vf(qbmm_idx%rs(k))%sf(j, 0, 0)
237 end do
238
239 call s_comp_n_from_cons(real(q_cons_vf(eqn_idx%alf)%sf(j, 0, 0), kind=wp), nrtmp, nbub, weight)
240 end if
241 end if
242 write (2, fmt) x_cb(j), q_cons_vf(i)%sf(j, 0, 0)/nbub
243 else if (i == eqn_idx%n .and. adv_n .and. bubbles_euler) then
244 write (2, fmt) x_cb(j), q_cons_vf(i)%sf(j, 0, 0)
245 else if (i == eqn_idx%damage) then
246 write (2, fmt) x_cb(j), q_cons_vf(i)%sf(j, 0, 0)
247 end if
248 end do
249 close (2)
250 end do
251 end if
252
253 do i = 1, sys_size
254 write (file_loc, '(A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/cons.', i, '.', proc_rank, '.', t_step, '.dat'
255
256 open (2, file=trim(file_loc))
257 do j = 0, m
258 write (2, fmt) x_cb(j), q_cons_vf(i)%sf(j, 0, 0)
259 end do
260 close (2)
261 end do
262
263 if (qbmm .and. .not. polytropic) then
264 do i = 1, nb
265 do r = 1, nnode
266 write (file_loc, '(A,I0,A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/pres.', i, '.', r, '.', proc_rank, &
267 & '.', t_step, '.dat'
268
269 open (2, file=trim(file_loc))
270 do j = 0, m
271 write (2, fmt) x_cb(j), pb%sf(j, 0, 0, r, i)
272 end do
273 close (2)
274 end do
275 end do
276 do i = 1, nb
277 do r = 1, nnode
278 write (file_loc, '(A,I0,A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/mv.', i, '.', r, '.', proc_rank, &
279 & '.', t_step, '.dat'
280
281 open (2, file=trim(file_loc))
282 do j = 0, m
283 write (2, fmt) x_cb(j), mv%sf(j, 0, 0, r, i)
284 end do
285 close (2)
286 end do
287 end do
288 end if
289 end if
290
291 if (precision == precision_single) then
292 fmt = "(3F30.7)"
293 else
294 fmt = "(3F40.14)"
295 end if
296
297 if ((n > 0) .and. (p == 0)) then
298 do i = 1, sys_size
299 write (file_loc, '(A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/cons.', i, '.', proc_rank, '.', t_step, '.dat'
300 open (2, file=trim(file_loc))
301 do j = 0, m
302 do k = 0, n
303 write (2, fmt) x_cb(j), y_cb(k), q_cons_vf(i)%sf(j, k, 0)
304 end do
305 write (2, *)
306 end do
307 close (2)
308 end do
309
310 if (qbmm .and. .not. polytropic) then
311 do i = 1, nb
312 do r = 1, nnode
313 write (file_loc, '(A,I0,A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/pres.', i, '.', r, '.', proc_rank, &
314 & '.', t_step, '.dat'
315
316 open (2, file=trim(file_loc))
317 do j = 0, m
318 do k = 0, n
319 write (2, fmt) x_cb(j), y_cb(k), pb%sf(j, k, 0, r, i)
320 end do
321 end do
322 close (2)
323 end do
324 end do
325 do i = 1, nb
326 do r = 1, nnode
327 write (file_loc, '(A,I0,A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/mv.', i, '.', r, '.', proc_rank, &
328 & '.', t_step, '.dat'
329
330 open (2, file=trim(file_loc))
331 do j = 0, m
332 do k = 0, n
333 write (2, fmt) x_cb(j), y_cb(k), mv%sf(j, k, 0, r, i)
334 end do
335 end do
336 close (2)
337 end do
338 end do
339 end if
340 end if
341
342 if (precision == precision_single) then
343 fmt = "(4F30.7)"
344 else
345 fmt = "(4F40.14)"
346 end if
347
348 if (p > 0) then
349 do i = 1, sys_size
350 write (file_loc, '(A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/cons.', i, '.', proc_rank, '.', t_step, '.dat'
351 open (2, file=trim(file_loc))
352 do j = 0, m
353 do k = 0, n
354 do l = 0, p
355 write (2, fmt) x_cb(j), y_cb(k), z_cb(l), q_cons_vf(i)%sf(j, k, l)
356 end do
357 write (2, *)
358 end do
359 write (2, *)
360 end do
361 close (2)
362 end do
363
364 if (qbmm .and. .not. polytropic) then
365 do i = 1, nb
366 do r = 1, nnode
367 write (file_loc, '(A,I0,A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/pres.', i, '.', r, '.', proc_rank, &
368 & '.', t_step, '.dat'
369
370 open (2, file=trim(file_loc))
371 do j = 0, m
372 do k = 0, n
373 do l = 0, p
374 write (2, fmt) x_cb(j), y_cb(k), z_cb(l), pb%sf(j, k, l, r, i)
375 end do
376 end do
377 end do
378 close (2)
379 end do
380 end do
381 do i = 1, nb
382 do r = 1, nnode
383 write (file_loc, '(A,I0,A,I0,A,I2.2,A,I6.6,A)') trim(t_step_dir) // '/mv.', i, '.', r, '.', proc_rank, &
384 & '.', t_step, '.dat'
385
386 open (2, file=trim(file_loc))
387 do j = 0, m
388 do k = 0, n
389 do l = 0, p
390 write (2, fmt) x_cb(j), y_cb(k), z_cb(l), mv%sf(j, k, l, r, i)
391 end do
392 end do
393 end do
394 close (2)
395 end do
396 end do
397 end if
398 end if
399
400 end subroutine s_write_serial_data_files
401
402 !> Writes grid and initial condition data files in parallel to the "0" time-step directory in the local processor rank folder
403 impure subroutine s_write_parallel_data_files(q_cons_vf, q_prim_vf, bc_type, q_T_sf)
404
405 type(scalar_field), dimension(sys_size), intent(inout) :: q_cons_vf, q_prim_vf
406 type(integer_field), dimension(1:num_dims,-1:1), intent(in) :: bc_type
407 type(scalar_field), optional, intent(inout) :: q_t_sf
408
409#ifdef MFC_MPI
410 integer :: ifile, ierr, data_size
411 integer, dimension(MPI_STATUS_SIZE) :: status
412 integer(KIND=MPI_OFFSET_KIND) :: disp
413 integer(KIND=MPI_OFFSET_KIND) :: m_mok, n_mok, p_mok
414 integer(KIND=MPI_OFFSET_KIND) :: wp_mok, var_mok, str_mok
415 integer(KIND=MPI_OFFSET_KIND) :: nvars_mok
416 integer(KIND=MPI_OFFSET_KIND) :: mok
417 character(LEN=path_len + 2*name_len) :: file_loc
418 logical :: file_exist, dir_check
419 integer :: i, j, k, l
420 real(wp) :: loc_violations, glb_violations
421 integer :: m_ds, n_ds, p_ds
422 integer :: m_glb_ds, n_glb_ds, p_glb_ds
423 integer :: m_glb_save, n_glb_save, p_glb_save !< Size of array being saved
424
425 loc_violations = 0._wp
426
427 if (down_sample) then
428 if ((mod(m + 1, 3) > 0) .or. (mod(n + 1, 3) > 0) .or. (mod(p + 1, 3) > 0)) then
429 loc_violations = 1._wp
430 end if
431 call s_mpi_allreduce_sum(loc_violations, glb_violations)
432 if (proc_rank == 0 .and. nint(glb_violations) > 0) then
433 print *, &
434 & "WARNING: Attempting to downsample data but there are" &
435 & // "processors with local problem sizes that are not divisible by 3."
436 end if
437 call s_populate_variables_buffers(bc_type, q_cons_vf)
438 call s_downsample_data(q_cons_vf, q_cons_temp, m_ds, n_ds, p_ds, m_glb_ds, n_glb_ds, p_glb_ds)
439 end if
440
441 if (file_per_process) then
442 if (proc_rank == 0) then
443 file_loc = trim(case_dir) // '/restart_data/lustre_0'
444 call my_inquire(file_loc, dir_check)
445 if (dir_check .neqv. .true.) then
446 call s_create_directory(trim(file_loc))
447 end if
448 call s_create_directory(trim(file_loc))
449 end if
450 call s_mpi_barrier()
451 call s_delay_file_access(proc_rank)
452
453 if (down_sample) then
454 call s_initialize_mpi_data_ds(m_ds, n_ds, p_ds)
455 else
456 call s_initialize_mpi_data(q_cons_vf, qbmm_pb=pb, qbmm_mv=mv)
457 end if
458
459 if (cfl_dt) then
460 write (file_loc, '(I0,A,i7.7,A)') n_start, '_', proc_rank, '.dat'
461 else
462 write (file_loc, '(I0,A,i7.7,A)') t_step_start, '_', proc_rank, '.dat'
463 end if
464 file_loc = trim(restart_dir) // '/lustre_0' // trim(mpiiofs) // trim(file_loc)
465 inquire (file=trim(file_loc), exist=file_exist)
466 if (file_exist .and. proc_rank == 0) then
467 call mpi_file_delete(file_loc, mpi_info_int, ierr)
468 end if
469 if (file_exist) call mpi_file_delete(file_loc, mpi_info_int, ierr)
470 call mpi_file_open(mpi_comm_self, file_loc, ior(mpi_mode_wronly, mpi_mode_create), mpi_info_int, ifile, ierr)
471 call s_check_mpi_file_open(ierr, file_loc)
472
473 if (down_sample) then
474 data_size = (m_ds + 3)*(n_ds + 3)*(p_ds + 3)
475 m_glb_save = m_glb_ds + 3
476 n_glb_save = n_glb_ds + 3
477 p_glb_save = p_glb_ds + 3
478 else
479 data_size = (m + 1)*(n + 1)*(p + 1)
480 m_glb_save = m_glb + 1
481 n_glb_save = n_glb + 1
482 p_glb_save = p_glb + 1
483 end if
484
485 ! Resize some integers so MPI can write even the biggest files
486 m_mok = int(m_glb_save, mpi_offset_kind)
487 n_mok = int(n_glb_save, mpi_offset_kind)
488 p_mok = int(p_glb_save, mpi_offset_kind)
489 wp_mok = int(storage_size(0._stp)/8, mpi_offset_kind)
490 mok = int(1._wp, mpi_offset_kind)
491 str_mok = int(name_len, mpi_offset_kind)
492 nvars_mok = int(sys_size, mpi_offset_kind)
493
494 if (bubbles_euler) then
495 do i = 1, sys_size
496 var_mok = int(i, mpi_offset_kind)
497
498 call mpi_file_write_all(ifile, mpi_io_data%var(i)%sf, data_size*mpi_io_type, mpi_io_p, status, ierr)
499 end do
500 if (qbmm .and. .not. polytropic) then
501 do i = sys_size + 1, sys_size + 2*nb*nnode
502 var_mok = int(i, mpi_offset_kind)
503
504 call mpi_file_write_all(ifile, mpi_io_data%var(i)%sf, data_size*mpi_io_type, mpi_io_p, status, ierr)
505 end do
506 end if
507 else
508 if (down_sample) then
509 do i = 1, sys_size
510 var_mok = int(i, mpi_offset_kind)
511
512 call mpi_file_write_all(ifile, q_cons_temp(i)%sf, data_size*mpi_io_type, mpi_io_p, status, ierr)
513 end do
514 else
515 do i = 1, sys_size
516 var_mok = int(i, mpi_offset_kind)
517
518 call mpi_file_write_all(ifile, mpi_io_data%var(i)%sf, data_size*mpi_io_type, mpi_io_p, status, ierr)
519 end do
520 end if
521 end if
522
523 if (bubbles_lagrange) then
524 block
525 real(stp), allocatable :: beta_ones(:,:,:)
526 integer :: jj, kk, ll
527 allocate (beta_ones(0:m,0:n,0:p))
528 do ll = 0, p
529 do kk = 0, n
530 do jj = 0, m
531 beta_ones(jj, kk, ll) = 1.0_stp
532 end do
533 end do
534 end do
535 call mpi_file_write_all(ifile, beta_ones, data_size*mpi_io_type, mpi_io_p, status, ierr)
536 deallocate (beta_ones)
537 end block
538 end if
539
540 call mpi_file_close(ifile, ierr)
541 else
542 call s_initialize_mpi_data(q_cons_vf, qbmm_pb=pb, qbmm_mv=mv)
543
544 if (cfl_dt) then
545 write (file_loc, '(I0,A)') n_start, '.dat'
546 else
547 write (file_loc, '(I0,A)') t_step_start, '.dat'
548 end if
549 file_loc = trim(restart_dir) // trim(mpiiofs) // trim(file_loc)
550 inquire (file=trim(file_loc), exist=file_exist)
551 if (file_exist .and. proc_rank == 0) then
552 call mpi_file_delete(file_loc, mpi_info_int, ierr)
553 end if
554 call mpi_file_open(mpi_comm_world, file_loc, ior(mpi_mode_wronly, mpi_mode_create), mpi_info_int, ifile, ierr)
555 call s_check_mpi_file_open(ierr, file_loc)
556
557 data_size = (m + 1)*(n + 1)*(p + 1)
558
559 ! Resize some integers so MPI can write even the biggest files
560 m_mok = int(m_glb + 1, mpi_offset_kind)
561 n_mok = int(n_glb + 1, mpi_offset_kind)
562 p_mok = int(p_glb + 1, mpi_offset_kind)
563 wp_mok = int(storage_size(0._stp)/8, mpi_offset_kind)
564 mok = int(1._wp, mpi_offset_kind)
565 str_mok = int(name_len, mpi_offset_kind)
566 nvars_mok = int(sys_size, mpi_offset_kind)
567
568 if (bubbles_euler) then
569 do i = 1, sys_size
570 var_mok = int(i, mpi_offset_kind)
571
572 disp = m_mok*max(mok, n_mok)*max(mok, p_mok)*wp_mok*(var_mok - 1)
573
574 call mpi_file_set_view(ifile, disp, mpi_io_p, mpi_io_data%view(i), 'native', mpi_info_int, ierr)
575 call mpi_file_write_all(ifile, mpi_io_data%var(i)%sf, data_size*mpi_io_type, mpi_io_p, status, ierr)
576 end do
577 if (qbmm .and. .not. polytropic) then
578 do i = sys_size + 1, sys_size + 2*nb*nnode
579 var_mok = int(i, mpi_offset_kind)
580
581 disp = m_mok*max(mok, n_mok)*max(mok, p_mok)*wp_mok*(var_mok - 1)
582
583 call mpi_file_set_view(ifile, disp, mpi_io_p, mpi_io_data%view(i), 'native', mpi_info_int, ierr)
584 call mpi_file_write_all(ifile, mpi_io_data%var(i)%sf, data_size*mpi_io_type, mpi_io_p, status, ierr)
585 end do
586 end if
587 else
588 do i = 1, sys_size
589 var_mok = int(i, mpi_offset_kind)
590
591 disp = m_mok*max(mok, n_mok)*max(mok, p_mok)*wp_mok*(var_mok - 1)
592
593 call mpi_file_set_view(ifile, disp, mpi_io_p, mpi_io_data%view(i), 'native', mpi_info_int, ierr)
594 call mpi_file_write_all(ifile, mpi_io_data%var(i)%sf, data_size*mpi_io_type, mpi_io_p, status, ierr)
595 end do
596 end if
597
598 if (bubbles_lagrange) then
599 block
600 real(stp), allocatable :: beta_ones(:,:,:)
601 integer :: jj, kk, ll
602 allocate (beta_ones(0:m,0:n,0:p))
603 do ll = 0, p
604 do kk = 0, n
605 do jj = 0, m
606 beta_ones(jj, kk, ll) = 1.0_stp
607 end do
608 end do
609 end do
610 var_mok = int(sys_size + 1, mpi_offset_kind)
611 disp = m_mok*max(mok, n_mok)*max(mok, p_mok)*wp_mok*(var_mok - 1)
612 call mpi_file_set_view(ifile, disp, mpi_io_p, mpi_io_data%view(1), 'native', mpi_info_int, ierr)
613 call mpi_file_write_all(ifile, beta_ones, data_size*mpi_io_type, mpi_io_p, status, ierr)
614 deallocate (beta_ones)
615 end block
616 end if
617
618 call mpi_file_close(ifile, ierr)
619 end if
620#endif
621
622 if (bc_io) then
623 if (igr) then
624 call s_write_parallel_boundary_condition_files(q_cons_vf, bc_type)
625 else
626 call s_write_parallel_boundary_condition_files(q_prim_vf, bc_type, q_t_sf)
627 end if
628 end if
629
630 end subroutine s_write_parallel_data_files
631
632 !> Computation of parameters, allocation procedures, and/or any other tasks needed to properly setup the module
634
635 character(LEN=len_trim(case_dir) + 2*name_len) :: file_loc
636 character(len=15) :: temp
637 character(LEN=1), dimension(3), parameter :: coord = (/'x', 'y', 'z'/)
638 logical :: dir_check
639 integer :: i, iu
640 integer :: m_ds, n_ds, p_ds
641
642 if (parallel_io .neqv. .true.) then
643 write (t_step_dir, '(A,I0,A)') '/p_all/p', proc_rank, '/0'
644 t_step_dir = trim(case_dir) // trim(t_step_dir)
645
646 if (old_grid .neqv. .true.) then
647 file_loc = trim(t_step_dir) // '/'
648
649 call my_inquire(file_loc, dir_check)
650
651 if (dir_check) call s_delete_directory(trim(t_step_dir))
652
653 call s_create_directory(trim(t_step_dir))
654 end if
655
657 else
658 write (restart_dir, '(A)') '/restart_data'
659 restart_dir = trim(case_dir) // trim(restart_dir)
660
661 if ((old_grid .neqv. .true.) .and. (proc_rank == 0)) then
662 file_loc = trim(restart_dir) // '/'
663 call my_inquire(file_loc, dir_check)
664
665 if (dir_check) call s_delete_directory(trim(restart_dir))
666 call s_create_directory(trim(restart_dir))
667 end if
668
669 call s_mpi_barrier()
670
672 end if
673
674 open (newunit=iu, file='indices.dat', status='unknown')
675
676 write (iu, '(A)') "Warning: The creation of file is currently experimental."
677 write (iu, '(A)') "This file may contain errors and not support all features."
678
679 write (iu, '(A3,A20,A20)') "#", "Conservative", "Primitive"
680 write (iu, '(A)') " "
681 do i = eqn_idx%cont%beg, eqn_idx%cont%end
682 write (temp, '(I0)') i - eqn_idx%cont%beg + 1
683 write (iu, '(I3,A20,A20)') i, "\alpha_{" // trim(temp) // "} \rho_{" // trim(temp) // "}", &
684 & "\alpha_{" // trim(temp) // "} \rho"
685 end do
686 do i = eqn_idx%mom%beg, eqn_idx%mom%end
687 write (iu, '(I3,A20,A20)') i, "\rho u_" // coord(i - eqn_idx%mom%beg + 1), "u_" // coord(i - eqn_idx%mom%beg + 1)
688 end do
689 if (eqn_idx%E /= 0) write (iu, '(I3,A20,A20)') eqn_idx%E, "\rho U", "p"
690 do i = eqn_idx%adv%beg, eqn_idx%adv%end
691 write (temp, '(I0)') i - eqn_idx%cont%beg + 1
692 write (iu, '(I3,A20,A20)') i, "\alpha_{" // trim(temp) // "}", "\alpha_{" // trim(temp) // "}"
693 end do
694 if (chemistry) then
695 do i = 1, num_species
696 write (iu, '(I3,A20,A20)') eqn_idx%species%beg + i - 1, "Y_{" // trim(species_names(i)) // "} \rho", &
697 & "Y_{" // trim(species_names(i)) // "}"
698 end do
699 end if
700
701 write (iu, '(A)') ""
702 call write_range(eqn_idx%cont%beg, eqn_idx%cont%end, " Continuity")
703 call write_range(eqn_idx%mom%beg, eqn_idx%mom%end, " Momentum")
704 call write_range(eqn_idx%E, eqn_idx%E, " Energy/Pressure")
705 call write_range(eqn_idx%adv%beg, eqn_idx%adv%end, " Advection")
706 call write_range(eqn_idx%bub%beg, eqn_idx%bub%end, " Bubbles")
707 call write_range(eqn_idx%stress%beg, eqn_idx%stress%end, " Stress")
708 call write_range(eqn_idx%int_en%beg, eqn_idx%int_en%end, " Internal Energies")
709 call write_range(eqn_idx%B%beg, eqn_idx%B%end, " Magnetic Field")
710 call write_range(eqn_idx%c, eqn_idx%c, " Color Function")
711 call write_range(eqn_idx%species%beg, eqn_idx%species%end, " Chemistry")
712
713 close (iu)
714
715 if (down_sample) then
716 m_ds = int((m + 1)/3) - 1
717 n_ds = int((n + 1)/3) - 1
718 p_ds = int((p + 1)/3) - 1
719
720 allocate (q_cons_temp(1:sys_size))
721 do i = 1, sys_size
722 allocate (q_cons_temp(i)%sf(-1:m_ds + 1,-1:n_ds + 1,-1:p_ds + 1))
723 end do
724 end if
725
726 contains
727
728 subroutine write_range(beg, end, label)
729
730 integer, intent(in) :: beg, end
731 character(*), intent(in) :: label
732
733 if (beg /= 0) write (iu, '("[",I0,",",I0,"]",A)') beg, end, label
734
735 end subroutine write_range
736
738
739 !> @brief Writes the initial IB layout (namelist patch_ib entries, then generated particle-cloud beds) that simulation reads
740 !! back at startup (s_read_ib_restart_data, src/simulation/m_start_up.fpp), in the layouts simulation's own IB state writers
741 !! use. Under file_per_process each rank writes only the IBs it owns to restart_data/lustre_0/ib_state_0_<rank>.dat; otherwise
742 !! only rank 0 calls this and writes every IB, in global-id order, to restart_data/ib_state_0.dat.
743 impure subroutine s_write_ib_state_0_file(glb_bounds, particle_cloud_ibs, num_particle_cloud_ibs)
744
745 type(bounds_info), dimension(3), intent(in) :: glb_bounds
746 type(ib_patch_parameters), dimension(:), intent(in) :: particle_cloud_ibs
747 integer, intent(in) :: num_particle_cloud_ibs
748 character(LEN=len_trim(case_dir) + 2*name_len) :: file_loc
749 integer :: i, ios, file_unit
750 logical, dimension(num_ibs) :: owned
751 real(wp), dimension(3) :: centroid
752
753 if (file_per_process) then
754 do i = 1, num_ibs
755 centroid = [patch_ib(i)%x_centroid, patch_ib(i)%y_centroid, patch_ib(i)%z_centroid]
756 owned(i) = f_local_rank_owns_location(centroid, glb_bounds)
757 end do
758
759 if (proc_rank == 0) call s_create_directory(trim(case_dir) // '/restart_data/lustre_0')
760 call s_mpi_barrier()
761 call s_delay_file_access(proc_rank)
762 write (file_loc, '(A,i7.7,A)') '/restart_data/lustre_0/ib_state_0_', proc_rank, '.dat'
763 else
764 owned = .true.
765 call s_create_directory(trim(case_dir) // '/restart_data')
766 file_loc = '/restart_data/ib_state_0.dat'
767 end if
768 file_loc = trim(case_dir) // trim(file_loc)
769
770 open (newunit=file_unit, file=trim(file_loc), form='unformatted', access='stream', status='replace', iostat=ios)
771 if (ios /= 0) call s_mpi_abort('Cannot open IB state output file: ' // trim(file_loc))
772
773 if (file_per_process) write (file_unit) count(owned) + num_particle_cloud_ibs
774 do i = 1, num_ibs
775 if (owned(i)) call s_write_ib_state_record(patch_ib(i), i)
776 end do
777 do i = 1, num_particle_cloud_ibs
778 call s_write_ib_state_record(particle_cloud_ibs(i), particle_cloud_ibs(i)%gbl_patch_id)
779 end do
780
781 close (file_unit)
782
783 contains
784
785 !> Writes one 20-field IB state record, prefixed by its global id under file_per_process.
786 subroutine s_write_ib_state_record(ib_patch, gbl_id)
787
788 type(ib_patch_parameters), intent(in) :: ib_patch
789 integer, intent(in) :: gbl_id
790 real(wp), dimension(20) :: ib_buf
791
792 ib_buf = 0._wp
793 ib_buf(8:10) = ib_patch%vel
794 ib_buf(11:13) = ib_patch%angular_vel
795 ib_buf(14:16) = ib_patch%angles
796 ib_buf(17) = ib_patch%x_centroid
797 ib_buf(18) = ib_patch%y_centroid
798 ib_buf(19) = ib_patch%z_centroid
799 ib_buf(20) = ib_patch%radius
800
801 if (file_per_process) write (file_unit) gbl_id
802 write (file_unit) ib_buf
803
804 end subroutine s_write_ib_state_record
805
806 end subroutine s_write_ib_state_0_file
807
808 !> Resets s_write_data_files pointer
810
811 integer :: i
812
813 s_write_data_files => null()
814
815 if (down_sample) then
816 do i = 1, sys_size
817 deallocate (q_cons_temp(i)%sf)
818 end do
819 deallocate (q_cons_temp)
820 end if
821
822 end subroutine s_finalize_data_output_module
823
824end module m_data_output
Interface for the conservative data.
subroutine s_write_ib_state_record(ib_patch, gbl_id)
Writes one 20-field IB state record, prefixed by its global id under file_per_process.
subroutine write_range(beg, end, label)
type(scalar_field), dimension(sys_size), intent(inout) q_cons_vf
integer, intent(in) k
integer, intent(in) j
integer, intent(in) l
Noncharacteristic and processor boundary condition application for ghost cells and buffer regions.
Applies spatially varying boundary condition patches along domain edges and faces.
Boundary condition restart I/O, capillary/IGR buffer population, and grid-variable buffers.
subroutine s_write_serial_boundary_condition_files(q_prim_vf, bc_type, step_dirpath, old_grid_in, q_t_sf)
Write boundary condition type and buffer data to serial (unformatted) restart files.
Platform-specific file and directory operations: create, delete, inquire, getcwd, and basename.
impure subroutine s_create_directory(dir_name)
Create a directory and all its parents if it does not exist.
Compile-time constant parameters: default values, tolerances, and physical constants.
integer, parameter model_eqns_5eq
real(wp), parameter dflt_t_guess
Default guess for temperature (when a previous value is not available).
integer, parameter nnode
Number of QBMM nodes.
integer, parameter precision_single
Writes grid and initial condition data to serial or parallel output files.
type(scalar_field), dimension(:), allocatable q_cons_temp
procedure(s_write_abstract_data_files), pointer, public s_write_data_files
impure subroutine, public s_write_ib_state_0_file(glb_bounds, particle_cloud_ibs, num_particle_cloud_ibs)
Writes the initial IB layout (namelist patch_ib entries, then generated particle-cloud beds) that sim...
impure subroutine, public s_write_serial_data_files(q_cons_vf, q_prim_vf, bc_type, q_t_sf)
Writes grid and initial condition data files to the "0" time-step directory in the local processor ra...
character(len=path_len+2 *name_len), private t_step_dir
Time-step folder into which grid and initial condition data will be placed.
impure subroutine, public s_initialize_data_output_module
Computation of parameters, allocation procedures, and/or any other tasks needed to properly setup the...
impure subroutine, public s_finalize_data_output_module
Resets s_write_data_files pointer.
impure subroutine, public s_write_parallel_data_files(q_cons_vf, q_prim_vf, bc_type, q_t_sf)
Writes grid and initial condition data files in parallel to the "0" time-step directory in the local ...
character(len=path_len+2 *name_len), public restart_dir
Restart data folder.
Rank-staggered file access delays to prevent I/O contention on parallel file systems.
Shared derived types for field data, patch geometry, bubble dynamics, and MPI I/O structures.
Defines global parameters for the computational domain, simulation algorithm, and initial conditions.
type(qbmm_idx_info) qbmm_idx
QBMM moment index mappings.
integer proc_rank
Rank of the local processor Number of cells in the x-, y- and z-coordinate directions.
logical bc_io
whether or not to save BC data
real(wp), dimension(:), allocatable y_cb
real(wp), dimension(:), allocatable weight
real(wp), dimension(:), allocatable z_cb
real(wp), dimension(:), allocatable x_cb
Locations of cell-boundaries (cb) in x-, y- and z-directions, respectively.
Utility routines for bubble model setup, coordinate transforms, array sampling, and special functions...
subroutine, public s_comp_n_from_cons(vftmp, nrtmp, ntmp, weights)
Compute the bubble number density from the conservative void fraction and weighted bubble radii.
Broadcasts user inputs and decomposes the domain across MPI ranks for pre-processing.
Conservative-to-primitive variable conversion, mixture property evaluation, and pressure computation.
subroutine, public s_compute_pressure(energy, alf, dyn_p, pi_inf, gamma, rho, qv, rhoyks, pres, t, e_e_in, pres_mag)
Compute the pressure from the appropriate equation of state.
subroutine, public s_convert_to_mixture_variables(q_vf, i, j, k, rho, gamma, pi_inf, qv, re_k, g_k, g)
Dispatch to the s_convert_mixture_to_mixture_variables and s_convert_species_to_mixture_variables sub...
Derived type annexing an integer scalar field (SF).
Derived type for bubble variables pb and mv at quadrature nodes (qbmm).
Derived type annexing a scalar field (SF).