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/post_process/m_data_output.fpp"
2!>
3!! @file
4!! @brief Contains module m_data_output
5
6!> @brief Writes post-processed grid and flow-variable data to Silo-HDF5 or binary database files
8
12 use m_mpi_proxy
14 use m_helper
17
18 implicit none
19
26
27 ! Include Silo-HDF5 interface library
28 include 'silo_f9x.inc'
29
30 !> Output workspace: flow variable buffers, VisIt extents/offsets, directory paths, file handles, and variable count.
32
33 ! Generic error flag for Silo-HDF5 and Binary I/O operations
34 integer, private :: err
35
36contains
37
38 !> Allocate storage arrays, configure output directories, and count flow variables for formatted database output.
40
41 character(LEN=len_trim(case_dir) + 2*name_len) :: file_loc
42 logical :: dir_check
43 integer :: i
44
45 allocate (out%q_sf(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end))
46 if (grid_geometry == 3) then
47 allocate (out%cyl_q_sf(-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end,-offset_x%beg:m + offset_x%end))
48 end if
49
50 if (precision == precision_single) then
51 allocate (out%q_sf_s(-offset_x%beg:m + offset_x%end,-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end))
52 if (grid_geometry == 3) then
53 allocate (out%cyl_q_sf_s(-offset_y%beg:n + offset_y%end,-offset_z%beg:p + offset_z%end, &
54 & -offset_x%beg:m + offset_x%end))
55 end if
56 end if
57
58 if (n == 0) then
59 allocate (out%q_root_sf(0:m_root,0:0,0:0))
60 if (precision == precision_single) then
61 allocate (out%q_root_sf_s(0:m_root,0:0,0:0))
62 end if
63 end if
64
65 ! Allocating the spatial and data extents and also the variables for the offsets and the one bookkeeping the number of
66 ! cell-boundaries in each active coordinate direction. Note that all these variables are only needed by the Silo-HDF5 format
67 ! for multidimensional data.
68 if (format == format_silo) then
69 allocate (out%data_extents(1:2,0:num_procs - 1))
70
71 if (p > 0) then
72 allocate (out%spatial_extents(1:6,0:num_procs - 1))
73 allocate (out%lo_offset(1:3))
74 allocate (out%hi_offset(1:3))
75 allocate (out%dims(1:3))
76 else if (n > 0) then
77 allocate (out%spatial_extents(1:4,0:num_procs - 1))
78 allocate (out%lo_offset(1:2))
79 allocate (out%hi_offset(1:2))
80 allocate (out%dims(1:2))
81 else
82 allocate (out%spatial_extents(1:2,0:num_procs - 1))
83 allocate (out%lo_offset(1:1))
84 allocate (out%hi_offset(1:1))
85 allocate (out%dims(1:1))
86 end if
87 end if
88
89 ! The size of the ghost zone layer in each of the active coordinate directions was set in the module m_mpi_proxy.f90. The
90 ! results are now transferred to the local variables of this module when they are required by the Silo-HDF5 format, for
91 ! multidimensional data sets. With the same, latter, requirements, the variables bookkeeping the number of cell-boundaries
92 ! in each active coordinate direction are also set here.
93 if (format == format_silo) then
94 if (p > 0) then
95 if (grid_geometry == 3) then
96 out%lo_offset(:) = (/offset_y%beg, offset_z%beg, offset_x%beg/)
97 out%hi_offset(:) = (/offset_y%end, offset_z%end, offset_x%end/)
98 else
99 out%lo_offset(:) = (/offset_x%beg, offset_y%beg, offset_z%beg/)
100 out%hi_offset(:) = (/offset_x%end, offset_y%end, offset_z%end/)
101 end if
102
103 if (grid_geometry == 3) then
104 out%dims(:) = (/n + offset_y%beg + offset_y%end + 2, p + offset_z%beg + offset_z%end + 2, &
105 & m + offset_x%beg + offset_x%end + 2/)
106 else
107 out%dims(:) = (/m + offset_x%beg + offset_x%end + 2, n + offset_y%beg + offset_y%end + 2, &
108 & p + offset_z%beg + offset_z%end + 2/)
109 end if
110 else if (n > 0) then
111 out%lo_offset(:) = (/offset_x%beg, offset_y%beg/)
112 out%hi_offset(:) = (/offset_x%end, offset_y%end/)
113
114 out%dims(:) = (/m + offset_x%beg + offset_x%end + 2, n + offset_y%beg + offset_y%end + 2/)
115 else
116 out%lo_offset(:) = (/offset_x%beg/)
117 out%hi_offset(:) = (/offset_x%end/)
118 out%dims(:) = (/m + offset_x%beg + offset_x%end + 2/)
119 end if
120 end if
121
122 if (format == format_silo) then
123 out%dbdir = trim(case_dir) // '/silo_hdf5'
124
125 write (out%proc_rank_dir, '(A,I0)') '/p', proc_rank
126
127 out%proc_rank_dir = trim(out%dbdir) // trim(out%proc_rank_dir)
128
129 file_loc = trim(out%proc_rank_dir) // '/.'
130
131 call my_inquire(file_loc, dir_check)
132 if (dir_check .neqv. .true.) then
133 call s_create_directory(trim(out%proc_rank_dir))
134 end if
135
136 if (proc_rank == 0) then
137 out%rootdir = trim(out%dbdir) // '/root'
138
139 file_loc = trim(out%rootdir) // '/.'
140
141 call my_inquire(file_loc, dir_check)
142 if (dir_check .neqv. .true.) then
143 call s_create_directory(trim(out%rootdir))
144 end if
145 end if
146 else
147 out%dbdir = trim(case_dir) // '/binary'
148
149 write (out%proc_rank_dir, '(A,I0)') '/p', proc_rank
150
151 out%proc_rank_dir = trim(out%dbdir) // trim(out%proc_rank_dir)
152
153 file_loc = trim(out%proc_rank_dir) // '/.'
154
155 call my_inquire(file_loc, dir_check)
156
157 if (dir_check .neqv. .true.) then
158 call s_create_directory(trim(out%proc_rank_dir))
159 end if
160
161 if (n == 0 .and. proc_rank == 0) then
162 out%rootdir = trim(out%dbdir) // '/root'
163
164 file_loc = trim(out%rootdir) // '/.'
165
166 call my_inquire(file_loc, dir_check)
167
168 if (dir_check .neqv. .true.) then
169 call s_create_directory(trim(out%rootdir))
170 end if
171 end if
172 end if
173
174 if (bubbles_lagrange) then ! Lagrangian solver
175 if (lag_txt_wrt) then
176 out%dbdir = trim(case_dir) // '/lag_bubbles_post_process'
177 file_loc = trim(out%dbdir) // '/.'
178 call my_inquire(file_loc, dir_check)
179
180 if (dir_check .neqv. .true.) then
181 call s_create_directory(trim(out%dbdir))
182 end if
183 end if
184 end if
185
186 ! Contrary to the Silo-HDF5 database format, handles of the Binary database master/root and slave/local process files are
187 ! perfectly static throughout post-process. Hence, they are set here so that they do not have to be repetitively computed in
188 ! later procedures.
189 if (format == format_binary) then
190 if (n == 0 .and. proc_rank == 0) out%dbroot = 2
191 out%dbfile = 1
192 end if
193
194 if (format == format_binary) then
195 out%dbvars = 0
196
197 if ((model_eqns == model_eqns_5eq) .or. (model_eqns == model_eqns_6eq)) then
198 do i = 1, num_fluids
199 if (alpha_rho_wrt(i) .or. (cons_vars_wrt .or. prim_vars_wrt)) then
200 out%dbvars = out%dbvars + 1
201 end if
202 end do
203 end if
204
205 if ((rho_wrt .or. (model_eqns == model_eqns_gamma_law .and. (cons_vars_wrt .or. prim_vars_wrt))) &
206 & .and. (.not. relativity)) then
207 out%dbvars = out%dbvars + 1
208 end if
209
210 if (relativity .and. (rho_wrt .or. prim_vars_wrt)) out%dbvars = out%dbvars + 1
211 if (relativity .and. (rho_wrt .or. cons_vars_wrt)) out%dbvars = out%dbvars + 1
212
213 do i = 1, eqn_idx%E - eqn_idx%mom%beg
214 if (mom_wrt(i) .or. cons_vars_wrt) out%dbvars = out%dbvars + 1
215 end do
216
217 do i = 1, eqn_idx%E - eqn_idx%mom%beg
218 if (vel_wrt(i) .or. prim_vars_wrt) out%dbvars = out%dbvars + 1
219 end do
220
221 do i = 1, eqn_idx%E - eqn_idx%mom%beg
222 if (flux_wrt(i)) out%dbvars = out%dbvars + 1
223 end do
224
225 if (e_wrt .or. cons_vars_wrt) out%dbvars = out%dbvars + 1
226 if (pres_wrt .or. prim_vars_wrt) out%dbvars = out%dbvars + 1
227 if (hypoelasticity) out%dbvars = out%dbvars + (num_dims*(num_dims + 1))/2
228 if (cont_damage) out%dbvars = out%dbvars + 1
229 if (hyper_cleaning) out%dbvars = out%dbvars + 1
230
231 if (mhd) then
232 if (n == 0) then
233 out%dbvars = out%dbvars + 2
234 else
235 out%dbvars = out%dbvars + 3
236 end if
237 end if
238
239 if ((model_eqns == model_eqns_5eq) .or. (model_eqns == model_eqns_6eq)) then
240 do i = 1, num_fluids - 1
241 if (alpha_wrt(i) .or. (cons_vars_wrt .or. prim_vars_wrt)) then
242 out%dbvars = out%dbvars + 1
243 end if
244 end do
245
246 if (alpha_wrt(num_fluids) .or. (cons_vars_wrt .or. prim_vars_wrt)) then
247 out%dbvars = out%dbvars + 1
248 end if
249 end if
250
251 if (gamma_wrt .or. (model_eqns == model_eqns_gamma_law .and. (cons_vars_wrt .or. prim_vars_wrt))) then
252 out%dbvars = out%dbvars + 1
253 end if
254
255 if (heat_ratio_wrt) out%dbvars = out%dbvars + 1
256
257 if (pi_inf_wrt .or. (model_eqns == model_eqns_gamma_law .and. (cons_vars_wrt .or. prim_vars_wrt))) then
258 out%dbvars = out%dbvars + 1
259 end if
260
261 if (pres_inf_wrt) out%dbvars = out%dbvars + 1
262 if (c_wrt) out%dbvars = out%dbvars + 1
263
264 if (p > 0) then
265 do i = 1, num_vels
266 if (omega_wrt(i)) out%dbvars = out%dbvars + 1
267 end do
268 else if (n > 0) then
269 do i = 1, num_vels
270 if (omega_wrt(i)) out%dbvars = out%dbvars + 1
271 end do
272 end if
273
274 if (schlieren_wrt) out%dbvars = out%dbvars + 1
275 end if
276
278
279 !> Compute the cell-index bounds for the user-specified partial output domain in each coordinate direction.
280 impure subroutine s_define_output_region
281
282 integer :: i
283 integer :: lower_bound, upper_bound
284
285# 285 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
286 if (m == 0) return ! Early return for y or z if simulation is 1D or 2D
287
288 lower_bound = -offset_x%beg
289 upper_bound = m + offset_x%end
290
291 do i = lower_bound, upper_bound
292 if (x_cc(i) > x_output%beg) then
293 x_output_idx%beg = i + offset_x%beg
294 exit
295 end if
296 end do
297
298 do i = upper_bound, lower_bound, -1
299 if (x_cc(i) < x_output%end) then
300 x_output_idx%end = i + offset_x%beg
301 exit
302 end if
303 end do
304
305 ! If no grid points are within the output region
306 if ((x_cc(lower_bound) > x_output%end) .or. (x_cc(upper_bound) < x_output%beg)) then
307 x_output_idx%beg = 0
308 x_output_idx%end = 0
309 end if
310# 285 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
311 if (n == 0) return ! Early return for y or z if simulation is 1D or 2D
312
313 lower_bound = -offset_y%beg
314 upper_bound = n + offset_y%end
315
316 do i = lower_bound, upper_bound
317 if (y_cc(i) > y_output%beg) then
318 y_output_idx%beg = i + offset_y%beg
319 exit
320 end if
321 end do
322
323 do i = upper_bound, lower_bound, -1
324 if (y_cc(i) < y_output%end) then
325 y_output_idx%end = i + offset_y%beg
326 exit
327 end if
328 end do
329
330 ! If no grid points are within the output region
331 if ((y_cc(lower_bound) > y_output%end) .or. (y_cc(upper_bound) < y_output%beg)) then
332 y_output_idx%beg = 0
333 y_output_idx%end = 0
334 end if
335# 285 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
336 if (p == 0) return ! Early return for y or z if simulation is 1D or 2D
337
338 lower_bound = -offset_z%beg
339 upper_bound = p + offset_z%end
340
341 do i = lower_bound, upper_bound
342 if (z_cc(i) > z_output%beg) then
343 z_output_idx%beg = i + offset_z%beg
344 exit
345 end if
346 end do
347
348 do i = upper_bound, lower_bound, -1
349 if (z_cc(i) < z_output%end) then
350 z_output_idx%end = i + offset_z%beg
351 exit
352 end if
353 end do
354
355 ! If no grid points are within the output region
356 if ((z_cc(lower_bound) > z_output%end) .or. (z_cc(upper_bound) < z_output%beg)) then
357 z_output_idx%beg = 0
358 z_output_idx%end = 0
359 end if
360# 310 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
361
362 end subroutine s_define_output_region
363
364 !> Open (or create) the Silo-HDF5 or Binary formatted database slave and master files for a given time step.
365 impure subroutine s_open_formatted_database_file(t_step)
366
367 integer, intent(in) :: t_step
368 character(LEN=len_trim(case_dir) + 3*name_len) :: file_loc
369 integer :: ierr
370
371 if (format == format_silo) then
372 write (file_loc, '(A,I0,A)') '/', t_step, '.silo'
373 file_loc = trim(out%proc_rank_dir) // trim(file_loc)
374
375 ierr = dbcreate(trim(file_loc), len_trim(file_loc), db_clobber, db_local, 'MFC v3.0', 8, db_hdf5, out%dbfile)
376
377 if (out%dbfile == -1) then
378 call s_mpi_abort('Unable to create Silo-HDF5 database ' // 'slave file ' // trim(file_loc) // '. ' // 'Exiting.')
379 end if
380
381 if (proc_rank == 0) then
382 write (file_loc, '(A,I0,A)') '/collection_', t_step, '.silo'
383 file_loc = trim(out%rootdir) // trim(file_loc)
384
385 ierr = dbcreate(trim(file_loc), len_trim(file_loc), db_clobber, db_local, 'MFC v3.0', 8, db_hdf5, out%dbroot)
386
387 if (out%dbroot == -1) then
388 call s_mpi_abort('Unable to create Silo-HDF5 database ' // 'master file ' // trim(file_loc) // '. ' &
389 & // 'Exiting.')
390 end if
391 end if
392 else
393 write (file_loc, '(A,I0,A)') '/', t_step, '.dat'
394 file_loc = trim(out%proc_rank_dir) // trim(file_loc)
395
396 open (out%dbfile, iostat=err, file=trim(file_loc), form='unformatted', status='replace')
397
398 if (err /= 0) then
399 call s_mpi_abort('Unable to create Binary database slave ' // 'file ' // trim(file_loc) // '. Exiting.')
400 end if
401
402 if (output_partial_domain) then
403 write (out%dbfile) x_output_idx%end - x_output_idx%beg, y_output_idx%end - y_output_idx%beg, &
404 & z_output_idx%end - z_output_idx%beg, out%dbvars
405 else
406 write (out%dbfile) m, n, p, out%dbvars
407 end if
408
409 if (n == 0 .and. proc_rank == 0) then
410 write (file_loc, '(A,I0,A)') '/', t_step, '.dat'
411 file_loc = trim(out%rootdir) // trim(file_loc)
412
413 open (out%dbroot, iostat=err, file=trim(file_loc), form='unformatted', status='replace')
414
415 if (err /= 0) then
416 call s_mpi_abort('Unable to create Binary database ' // 'master file ' // trim(file_loc) // '. Exiting.')
417 end if
418
419 if (output_partial_domain) then
420 write (out%dbroot) x_output_idx%end - x_output_idx%beg, 0, 0, out%dbvars
421 else
422 write (out%dbroot) m_root, 0, 0, out%dbvars
423 end if
424 end if
425 end if
426
427 end subroutine s_open_formatted_database_file
428
429 !> Open the interface data file for appending extracted interface coordinates.
430 impure subroutine s_open_intf_data_file()
431
432 character(LEN=path_len + 3*name_len) :: file_path
433
434 write (file_path, '(A)') '/intf_data.dat'
435 file_path = trim(case_dir) // trim(file_path)
436
437 open (211, file=trim(file_path), form='formatted', position='append', status='unknown')
438
439 end subroutine s_open_intf_data_file
440
441 !> Open the energy data file for appending volume-integrated energy budget quantities.
442 impure subroutine s_open_energy_data_file()
443
444 character(LEN=path_len + 3*name_len) :: file_path
445
446 write (file_path, '(A)') '/eng_data.dat'
447 file_path = trim(case_dir) // trim(file_path)
448
449 open (251, file=trim(file_path), form='formatted', position='append', status='unknown')
450
451 end subroutine s_open_energy_data_file
452
453 !> Write the computational grid (cell-boundary coordinates) to the formatted database slave and master files.
455
456 integer, intent(in) :: t_step
457
458 ! NAG compiler requires these to be statically sized
459 character(LEN=4*name_len), dimension(num_procs) :: meshnames
460 integer, dimension(num_procs) :: meshtypes
461 integer :: i
462 integer :: ierr
463
464 if (format == format_silo) then
465 ! For multidimensional data sets, the spatial extents of all of the grid(s) handled by the local processor(s) are
466 ! recorded so that they may be written, by root processor, to the formatted database master file.
467 if (num_procs > 1) then
468 call s_mpi_gather_spatial_extents(out%spatial_extents)
469 else if (p > 0) then
470 if (grid_geometry == 3) then
471 out%spatial_extents(:,0) = (/minval(y_cb), minval(z_cb), minval(x_cb), maxval(y_cb), maxval(z_cb), &
472 & maxval(x_cb)/)
473 else
474 out%spatial_extents(:,0) = (/minval(x_cb), minval(y_cb), minval(z_cb), maxval(x_cb), maxval(y_cb), &
475 & maxval(z_cb)/)
476 end if
477 else if (n > 0) then
478 out%spatial_extents(:,0) = (/minval(x_cb), minval(y_cb), maxval(x_cb), maxval(y_cb)/)
479 else
480 out%spatial_extents(:,0) = (/minval(x_cb), maxval(x_cb)/)
481 end if
482
483 ! Next, the root processor proceeds to record all of the spatial extents in the formatted database master file. In
484 ! addition, it also records a sub-domain connectivity map so that the entire grid may be reassembled by looking at the
485 ! master file.
486 if (proc_rank == 0) then
487 do i = 1, num_procs
488 write (meshnames(i), '(A,I0,A,I0,A)') '../p', i - 1, '/', t_step, '.silo:rectilinear_grid'
489 end do
490
491 meshtypes = db_quad_rect
492
493 err = dbset2dstrlen(len(meshnames(1)))
494 err = dbmkoptlist(2, out%optlist)
495 err = dbaddiopt(out%optlist, dbopt_extents_size, size(out%spatial_extents, 1))
496 err = dbadddopt(out%optlist, dbopt_extents, out%spatial_extents)
497 err = dbputmmesh(out%dbroot, 'rectilinear_grid', 16, num_procs, meshnames, len_trim(meshnames), meshtypes, &
498 & out%optlist, ierr)
499 err = dbfreeoptlist(out%optlist)
500 end if
501
502 ! Finally, the local quadrilateral mesh, either 2D or 3D, along with its offsets that indicate the presence and size of
503 ! ghost zone layer(s), are put in the formatted database slave file.
504
505 if (p > 0) then
506 err = dbmkoptlist(2, out%optlist)
507 err = dbaddiaopt(out%optlist, dbopt_lo_offset, size(out%lo_offset), out%lo_offset)
508 err = dbaddiaopt(out%optlist, dbopt_hi_offset, size(out%hi_offset), out%hi_offset)
509 if (grid_geometry == 3) then
510 err = dbputqm(out%dbfile, 'rectilinear_grid', 16, 'x', 1, 'y', 1, 'z', 1, y_cb, z_cb, x_cb, out%dims, 3, &
511 & db_double, db_collinear, out%optlist, ierr)
512 else
513 err = dbputqm(out%dbfile, 'rectilinear_grid', 16, 'x', 1, 'y', 1, 'z', 1, x_cb, y_cb, z_cb, out%dims, 3, &
514 & db_double, db_collinear, out%optlist, ierr)
515 end if
516 err = dbfreeoptlist(out%optlist)
517 else if (n > 0) then
518 err = dbmkoptlist(2, out%optlist)
519 err = dbaddiaopt(out%optlist, dbopt_lo_offset, size(out%lo_offset), out%lo_offset)
520 err = dbaddiaopt(out%optlist, dbopt_hi_offset, size(out%hi_offset), out%hi_offset)
521 err = dbputqm(out%dbfile, 'rectilinear_grid', 16, 'x', 1, 'y', 1, 'z', 1, x_cb, y_cb, db_f77null, out%dims, 2, &
522 & db_double, db_collinear, out%optlist, ierr)
523 err = dbfreeoptlist(out%optlist)
524 else
525 err = dbmkoptlist(2, out%optlist)
526 err = dbaddiaopt(out%optlist, dbopt_lo_offset, size(out%lo_offset), out%lo_offset)
527 err = dbaddiaopt(out%optlist, dbopt_hi_offset, size(out%hi_offset), out%hi_offset)
528 err = dbputqm(out%dbfile, 'rectilinear_grid', 16, 'x', 1, 'y', 1, 'z', 1, x_cb, db_f77null, db_f77null, out%dims, &
529 & 1, db_double, db_collinear, out%optlist, ierr)
530 err = dbfreeoptlist(out%optlist)
531 end if
532 else if (format == format_binary) then
533 ! Multidimensional local grid data is written to the formatted database slave file. Recall that no master file to
534 ! maintained in multidimensions.
535 if (p > 0) then
536 if (precision == precision_single) then
537 write (out%dbfile) real(x_cb, sp), real(y_cb, sp), real(z_cb, sp)
538 else
539 if (output_partial_domain) then
540 write (out%dbfile) x_cb(x_output_idx%beg - 1:x_output_idx%end), &
541 & y_cb(y_output_idx%beg - 1:y_output_idx%end), z_cb(z_output_idx%beg - 1:z_output_idx%end)
542 else
543 write (out%dbfile) x_cb, y_cb, z_cb
544 end if
545 end if
546 else if (n > 0) then
547 if (precision == precision_single) then
548 write (out%dbfile) real(x_cb, sp), real(y_cb, sp)
549 else
550 if (output_partial_domain) then
551 write (out%dbfile) x_cb(x_output_idx%beg - 1:x_output_idx%end), y_cb(y_output_idx%beg - 1:y_output_idx%end)
552 else
553 write (out%dbfile) x_cb, y_cb
554 end if
555 end if
556
557 ! One-dimensional local grid data is written to the formatted database slave file. In addition, the local grid data
558 ! is put together by the root process and written to the master file.
559 else
560 if (precision == precision_single) then
561 write (out%dbfile) real(x_cb, sp)
562 else
563 if (output_partial_domain) then
564 write (out%dbfile) x_cb(x_output_idx%beg - 1:x_output_idx%end)
565 else
566 write (out%dbfile) x_cb
567 end if
568 end if
569
570 if (num_procs > 1) then
572 else
573 x_root_cb(:) = x_cb(:)
574 end if
575
576 if (proc_rank == 0) then
577 if (precision == precision_single) then
578 write (out%dbroot) real(x_root_cb, wp)
579 else
580 if (output_partial_domain) then
581 write (out%dbroot) x_root_cb(x_output_idx%beg - 1:x_output_idx%end)
582 else
583 write (out%dbroot) x_root_cb
584 end if
585 end if
586 end if
587 end if
588 end if
589
591
592 !> Write a single flow variable field to the formatted database slave and master files for a given time step.
593 impure subroutine s_write_variable_to_formatted_database_file(varname, t_step)
594
595 character(LEN=*), intent(in) :: varname
596 integer, intent(in) :: t_step
597
598 ! NAG compiler requires these to be statically sized
599 character(LEN=4*name_len), dimension(num_procs) :: varnames
600 integer, dimension(num_procs) :: vartypes
601 integer :: i, j, k
602 integer :: ierr
603
604 if (format == format_silo) then
605 ! Determining the extents of the flow variable on each local process and gathering all this information on root process
606 if (num_procs > 1) then
607 call s_mpi_gather_data_extents(out%q_sf, out%data_extents)
608 else
609 out%data_extents(:,0) = (/minval(out%q_sf), maxval(out%q_sf)/)
610 end if
611
612 if (proc_rank == 0) then
613 do i = 1, num_procs
614 write (varnames(i), '(A,I0,A,I0,A)') '../p', i - 1, '/', t_step, '.silo:' // trim(varname)
615 end do
616
617 vartypes = db_quadvar
618
619 err = dbset2dstrlen(len(varnames(1)))
620 err = dbmkoptlist(2, out%optlist)
621 err = dbaddiopt(out%optlist, dbopt_extents_size, 2)
622 err = dbadddopt(out%optlist, dbopt_extents, out%data_extents)
623 err = dbputmvar(out%dbroot, trim(varname), len_trim(varname), num_procs, varnames, len_trim(varnames), vartypes, &
624 & out%optlist, ierr)
625 err = dbfreeoptlist(out%optlist)
626 end if
627
628 if (wp == dp) then
629 if (precision == precision_single) then
630 do i = -offset_x%beg, m + offset_x%end
631 do j = -offset_y%beg, n + offset_y%end
632 do k = -offset_z%beg, p + offset_z%end
633 out%q_sf_s(i, j, k) = real(out%q_sf(i, j, k), sp)
634 end do
635 end do
636 end do
637 if (grid_geometry == 3) then
638 do i = -offset_x%beg, m + offset_x%end
639 do j = -offset_y%beg, n + offset_y%end
640 do k = -offset_z%beg, p + offset_z%end
641 out%cyl_q_sf_s(j, k, i) = out%q_sf_s(i, j, k)
642 end do
643 end do
644 end do
645 end if
646 else
647 if (grid_geometry == 3) then
648 do i = -offset_x%beg, m + offset_x%end
649 do j = -offset_y%beg, n + offset_y%end
650 do k = -offset_z%beg, p + offset_z%end
651 out%cyl_q_sf(j, k, i) = out%q_sf(i, j, k)
652 end do
653 end do
654 end do
655 end if
656 end if
657 else if (wp == sp) then
658 do i = -offset_x%beg, m + offset_x%end
659 do j = -offset_y%beg, n + offset_y%end
660 do k = -offset_z%beg, p + offset_z%end
661 out%q_sf_s(i, j, k) = out%q_sf(i, j, k)
662 end do
663 end do
664 end do
665 if (grid_geometry == 3) then
666 do i = -offset_x%beg, m + offset_x%end
667 do j = -offset_y%beg, n + offset_y%end
668 do k = -offset_z%beg, p + offset_z%end
669 out%cyl_q_sf_s(j, k, i) = out%q_sf_s(i, j, k)
670 end do
671 end do
672 end do
673 end if
674 end if
675
676# 626 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
677 if (precision == 1) then
678 if (p > 0) then
679 if (grid_geometry == 3) then
680 err = dbputqv1(out%dbfile, trim(varname), len_trim(varname), 'rectilinear_grid', 16, &
681 & out%cyl_q_sf_s, out%dims - 1, 3, db_f77null, 0, db_float, db_zonecent, &
682 & db_f77null, ierr)
683 else
684 err = dbputqv1(out%dbfile, trim(varname), len_trim(varname), 'rectilinear_grid', 16, out%q_sf_s, &
685 & out%dims - 1, 3, db_f77null, 0, db_float, db_zonecent, db_f77null, ierr)
686 end if
687 else if (n > 0) then
688 err = dbputqv1(out%dbfile, trim(varname), len_trim(varname), 'rectilinear_grid', 16, out%q_sf_s, &
689 & out%dims - 1, 2, db_f77null, 0, db_float, db_zonecent, db_f77null, ierr)
690 else
691 err = dbputqv1(out%dbfile, trim(varname), len_trim(varname), 'rectilinear_grid', 16, out%q_sf_s, &
692 & out%dims - 1, 1, db_f77null, 0, db_float, db_zonecent, db_f77null, ierr)
693 end if
694 end if
695# 626 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
696 if (precision == 2) then
697 if (p > 0) then
698 if (grid_geometry == 3) then
699 err = dbputqv1(out%dbfile, trim(varname), len_trim(varname), 'rectilinear_grid', 16, &
700 & out%cyl_q_sf, out%dims - 1, 3, db_f77null, 0, db_double, db_zonecent, &
701 & db_f77null, ierr)
702 else
703 err = dbputqv1(out%dbfile, trim(varname), len_trim(varname), 'rectilinear_grid', 16, out%q_sf, &
704 & out%dims - 1, 3, db_f77null, 0, db_double, db_zonecent, db_f77null, ierr)
705 end if
706 else if (n > 0) then
707 err = dbputqv1(out%dbfile, trim(varname), len_trim(varname), 'rectilinear_grid', 16, out%q_sf, &
708 & out%dims - 1, 2, db_f77null, 0, db_double, db_zonecent, db_f77null, ierr)
709 else
710 err = dbputqv1(out%dbfile, trim(varname), len_trim(varname), 'rectilinear_grid', 16, out%q_sf, &
711 & out%dims - 1, 1, db_f77null, 0, db_double, db_zonecent, db_f77null, ierr)
712 end if
713 end if
714# 645 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
715 else
716 ! Writing the name of the flow variable and its data, associated with the local processor, to the formatted database
717 ! slave file
718 if (precision == precision_single) then
719 write (out%dbfile) varname, real(out%q_sf, wp)
720 else
721 write (out%dbfile) varname, out%q_sf
722 end if
723
724 ! In 1D, the root process also takes care of gathering the flow variable data from all of the local processor(s) and
725 ! writes it to the formatted database master file.
726 if (n == 0) then
727 if (num_procs > 1) then
728 call s_mpi_defragment_1d_flow_variable(out%q_sf, out%q_root_sf)
729 else
730 out%q_root_sf(:,:,:) = out%q_sf(:,:,:)
731 end if
732
733 if (proc_rank == 0) then
734 if (precision == precision_single) then
735 write (out%dbroot) varname, real(out%q_root_sf, wp)
736 else
737 write (out%dbroot) varname, out%q_root_sf
738 end if
739 end if
740 end if
741 end if
742
744
745 !> Write the post-processed results in the folder 'lag_bubbles_data'
746 impure subroutine s_write_lag_bubbles_results_to_text(t_step)
747
748 integer, intent(in) :: t_step
749 character(len=len_trim(case_dir) + 3*name_len) :: file_loc
750 integer :: id
751
752#ifdef MFC_MPI
753 real(wp), dimension(20) :: inputvals
754 real(wp) :: time_real
755 integer, dimension(MPI_STATUS_SIZE) :: status
756 integer(KIND=MPI_OFFSET_KIND) :: disp
757 integer :: view
758 logical :: file_exist
759 integer, dimension(2) :: gsizes, lsizes, start_idx_part
760 integer :: ifile
761 integer :: ierr
762 real(wp) :: file_time, file_dt
763 integer :: file_num_procs, file_tot_part
764 integer :: i
765 integer, dimension(:), allocatable :: proc_bubble_counts
766 real(wp), dimension(1:1,1:lag_io_vars) :: lag_io_null
767
768 lag_io_null = 0._wp
769
770 ! Construct file path
771 write (file_loc, '(A,I0,A)') 'lag_bubbles_', t_step, '.dat'
772 file_loc = trim(case_dir) // '/restart_data' // trim(mpiiofs) // trim(file_loc)
773
774 ! Check if file exists
775 inquire (file=trim(file_loc), exist=file_exist)
776 if (.not. file_exist) then
777 call s_mpi_abort('Restart file ' // trim(file_loc) // ' does not exist!')
778 end if
779
780 if (.not. parallel_io) return
781
782 if (proc_rank == 0) then
783 call mpi_file_open(mpi_comm_self, file_loc, mpi_mode_rdonly, mpi_info_int, ifile, ierr)
784
785 call mpi_file_read(ifile, file_tot_part, 1, mpi_integer, status, ierr)
786 call mpi_file_read(ifile, file_time, 1, mpi_p, status, ierr)
787 call mpi_file_read(ifile, file_dt, 1, mpi_p, status, ierr)
788 call mpi_file_read(ifile, file_num_procs, 1, mpi_integer, status, ierr)
789
790 call mpi_file_close(ifile, ierr)
791 end if
792
793 call mpi_bcast(file_tot_part, 1, mpi_integer, 0, mpi_comm_world, ierr)
794 call mpi_bcast(file_time, 1, mpi_p, 0, mpi_comm_world, ierr)
795 call mpi_bcast(file_dt, 1, mpi_p, 0, mpi_comm_world, ierr)
796 call mpi_bcast(file_num_procs, 1, mpi_integer, 0, mpi_comm_world, ierr)
797 time_real = file_time
798
799 allocate (proc_bubble_counts(file_num_procs))
800
801 if (proc_rank == 0) then
802 call mpi_file_open(mpi_comm_self, file_loc, mpi_mode_rdonly, mpi_info_int, ifile, ierr)
803
804 ! Skip to processor counts position
805 disp = int(sizeof(file_tot_part) + 2*sizeof(file_time) + sizeof(file_num_procs), mpi_offset_kind)
806 call mpi_file_seek(ifile, disp, mpi_seek_set, ierr)
807 call mpi_file_read(ifile, proc_bubble_counts, file_num_procs, mpi_integer, status, ierr)
808
809 call mpi_file_close(ifile, ierr)
810 end if
811
812 call mpi_bcast(proc_bubble_counts, file_num_procs, mpi_integer, 0, mpi_comm_world, ierr)
813
814 if (file_tot_part > 0) then
815 gsizes(1) = file_tot_part
816 gsizes(2) = lag_io_vars
817 lsizes(1) = file_tot_part
818 lsizes(2) = lag_io_vars
819 start_idx_part(1) = 0
820 start_idx_part(2) = 0
821
822 call mpi_type_create_subarray(2, gsizes, lsizes, start_idx_part, mpi_order_fortran, mpi_p, view, ierr)
823 call mpi_type_commit(view, ierr)
824
825 call mpi_file_open(mpi_comm_world, file_loc, mpi_mode_rdonly, mpi_info_int, ifile, ierr)
826
827 disp = int(sizeof(file_tot_part) + 2*sizeof(file_time) + sizeof(file_num_procs) &
828 & + file_num_procs*sizeof(proc_bubble_counts(1)), mpi_offset_kind)
829 call mpi_file_set_view(ifile, disp, mpi_p, view, 'native', mpi_info_null, ierr)
830
831 allocate (mpi_io_data_lg_bubbles(file_tot_part,1:lag_io_vars))
832
833 call mpi_file_read_all(ifile, mpi_io_data_lg_bubbles, lag_io_vars*file_tot_part, mpi_p, status, ierr)
834
835 write (file_loc, '(A,I0,A)') 'lag_bubbles_post_process_', t_step, '.dat'
836 file_loc = trim(case_dir) // '/lag_bubbles_post_process/' // trim(file_loc)
837
838 if (proc_rank == 0) then
839 open (unit=29, file=file_loc, form='formatted', position='rewind')
840
841 if (lag_header) then
842 write (29, '(A)', advance='no')
843 if (lag_id_wrt) write (29, '(A8)', advance='no') 'id, '
844 if (lag_pos_wrt) write (29, '(3(A17))', advance='no') 'px, ', 'py, ', 'pz, '
845 if (lag_pos_prev_wrt) write (29, '(3(A17))', advance='no') 'pvx, ', 'pvy, ', 'pvz, '
846 if (lag_vel_wrt) write (29, '(3(A17))', advance='no') 'vx, ', 'vy, ', 'vz, '
847 if (lag_rad_wrt) write (29, '(A17)', advance='no') 'radius, '
848 if (lag_rvel_wrt) write (29, '(A17)', advance='no') 'rvel, '
849 if (lag_r0_wrt) write (29, '(A17)', advance='no') 'r0, '
850 if (lag_rmax_wrt) write (29, '(A17)', advance='no') 'rmax, '
851 if (lag_rmin_wrt) write (29, '(A17)', advance='no') 'rmin, '
852 if (lag_dphidt_wrt) write (29, '(A17)', advance='no') 'dphidt, '
853 if (lag_pres_wrt) write (29, '(A17)', advance='no') 'pressure, '
854 if (lag_mv_wrt) write (29, '(A17)', advance='no') 'mv, '
855 if (lag_mg_wrt) write (29, '(A17)', advance='no') 'mg, '
856 if (lag_betat_wrt) write (29, '(A17)', advance='no') 'betaT, '
857 if (lag_betac_wrt) write (29, '(A17)', advance='no') 'betaC, '
858 write (29, '(A15)') 'time'
859 end if
860
861 do i = 1, file_tot_part
862 id = int(mpi_io_data_lg_bubbles(i, 1))
863 inputvals(1:20) = mpi_io_data_lg_bubbles(i,2:21)
864 if (id > 0) then
865 write (29, '(100(A))', advance='no') ''
866 if (lag_id_wrt) write (29, '(I6, A)', advance='no') id, ', '
867 if (lag_pos_wrt) write (29, '(3(E15.7, A))', advance='no') inputvals(1), ', ', inputvals(2), ', ', &
868 & inputvals(3), ', '
869 if (lag_pos_prev_wrt) write (29, '(3(E15.7, A))', advance='no') inputvals(4), ', ', inputvals(5), ', ', &
870 & inputvals(6), ', '
871 if (lag_vel_wrt) write (29, '(3(E15.7, A))', advance='no') inputvals(7), ', ', inputvals(8), ', ', &
872 & inputvals(9), ', '
873 if (lag_rad_wrt) write (29, '(E15.7, A)', advance='no') inputvals(10), ', '
874 if (lag_rvel_wrt) write (29, '(E15.7, A)', advance='no') inputvals(11), ', '
875 if (lag_r0_wrt) write (29, '(E15.7, A)', advance='no') inputvals(12), ', '
876 if (lag_rmax_wrt) write (29, '(E15.7, A)', advance='no') inputvals(13), ', '
877 if (lag_rmin_wrt) write (29, '(E15.7, A)', advance='no') inputvals(14), ', '
878 if (lag_dphidt_wrt) write (29, '(E15.7, A)', advance='no') inputvals(15), ', '
879 if (lag_pres_wrt) write (29, '(E15.7, A)', advance='no') inputvals(16), ', '
880 if (lag_mv_wrt) write (29, '(E15.7, A)', advance='no') inputvals(17), ', '
881 if (lag_mg_wrt) write (29, '(E15.7, A)', advance='no') inputvals(18), ', '
882 if (lag_betat_wrt) write (29, '(E15.7, A)', advance='no') inputvals(19), ', '
883 if (lag_betac_wrt) write (29, '(E15.7, A)', advance='no') inputvals(20), ', '
884 write (29, '(E15.7)') time_real
885 end if
886 end do
887 close (29)
888 end if
889
890 deallocate (mpi_io_data_lg_bubbles)
891
892 call s_mpi_barrier()
893
894 call mpi_file_close(ifile, ierr)
895 else
896 call mpi_type_contiguous(0, mpi_p, view, ierr)
897 call mpi_type_commit(view, ierr)
898
899 call mpi_file_open(mpi_comm_world, file_loc, mpi_mode_rdonly, mpi_info_int, ifile, ierr)
900
901 disp = int(sizeof(file_tot_part) + 2*sizeof(file_time) + sizeof(file_num_procs) &
902 & + file_num_procs*sizeof(proc_bubble_counts(1)), mpi_offset_kind)
903 call mpi_file_set_view(ifile, disp, mpi_p, view, 'native', mpi_info_null, ierr)
904
905 call mpi_file_read_all(ifile, lag_io_null, 0, mpi_p, status, ierr)
906
907 call mpi_file_close(ifile, ierr)
908 call mpi_type_free(view, ierr)
909 end if
910#endif
911
913
914 !> Read Lagrangian bubble restart data and write bubble positions and scalar fields to the Silo database.
916
917 integer, intent(in) :: t_step
918 character(len=len_trim(case_dir) + 3*name_len) :: file_loc
919 integer :: id
920
921#ifdef MFC_MPI
922 real(wp) :: time_real
923 integer, dimension(MPI_STATUS_SIZE) :: status
924 integer(KIND=MPI_OFFSET_KIND) :: disp
925 integer :: view
926 logical :: file_exist
927 integer, dimension(2) :: gsizes, lsizes, start_idx_part
928 integer :: ifile, ierr, nbub
929 real(wp) :: file_time, file_dt
930 integer :: file_num_procs, file_tot_part
931 integer, dimension(:), allocatable :: proc_bubble_counts
932 real(wp), dimension(1:1,1:lag_io_vars) :: dummy
933 character(LEN=4*name_len), dimension(num_procs) :: meshnames
934 integer, dimension(num_procs) :: meshtypes
935 real(wp) :: dummy_data
936 integer :: i
937 real(wp), dimension(:), allocatable :: bub_id
938 real(wp), dimension(:), allocatable :: px, py, pz, ppx, ppy, ppz, vx, vy, vz
939 real(wp), dimension(:), allocatable :: radius, rvel, rnot, rmax, rmin, dphidt
940 real(wp), dimension(:), allocatable :: pressure, mv, mg, betat, betac
941
942 dummy = 0._wp
943 dummy_data = 0._wp
944
945 ! Construct file path
946 write (file_loc, '(A,I0,A)') 'lag_bubbles_', t_step, '.dat'
947 file_loc = trim(case_dir) // '/restart_data' // trim(mpiiofs) // trim(file_loc)
948
949 ! Check if file exists
950 inquire (file=trim(file_loc), exist=file_exist)
951 if (.not. file_exist) then
952 call s_mpi_abort('Restart file ' // trim(file_loc) // ' does not exist!')
953 end if
954
955 if (.not. parallel_io) return
956
957 if (proc_rank == 0) then
958 call mpi_file_open(mpi_comm_self, file_loc, mpi_mode_rdonly, mpi_info_int, ifile, ierr)
959
960 call mpi_file_read(ifile, file_tot_part, 1, mpi_integer, status, ierr)
961 call mpi_file_read(ifile, file_time, 1, mpi_p, status, ierr)
962 call mpi_file_read(ifile, file_dt, 1, mpi_p, status, ierr)
963 call mpi_file_read(ifile, file_num_procs, 1, mpi_integer, status, ierr)
964
965 call mpi_file_close(ifile, ierr)
966 end if
967
968 call mpi_bcast(file_tot_part, 1, mpi_integer, 0, mpi_comm_world, ierr)
969 call mpi_bcast(file_time, 1, mpi_p, 0, mpi_comm_world, ierr)
970 call mpi_bcast(file_dt, 1, mpi_p, 0, mpi_comm_world, ierr)
971 call mpi_bcast(file_num_procs, 1, mpi_integer, 0, mpi_comm_world, ierr)
972 time_real = file_time
973
974 allocate (proc_bubble_counts(file_num_procs))
975
976 if (proc_rank == 0) then
977 call mpi_file_open(mpi_comm_self, file_loc, mpi_mode_rdonly, mpi_info_int, ifile, ierr)
978
979 ! Skip to processor counts position
980 disp = int(sizeof(file_tot_part) + 2*sizeof(file_time) + sizeof(file_num_procs), mpi_offset_kind)
981 call mpi_file_seek(ifile, disp, mpi_seek_set, ierr)
982 call mpi_file_read(ifile, proc_bubble_counts, file_num_procs, mpi_integer, status, ierr)
983
984 call mpi_file_close(ifile, ierr)
985 end if
986
987 call mpi_bcast(proc_bubble_counts, file_num_procs, mpi_integer, 0, mpi_comm_world, ierr)
988
989 ! Set time variables from file
990
991 nbub = proc_bubble_counts(proc_rank + 1)
992
993 start_idx_part(1) = 0
994 do i = 1, proc_rank
995 start_idx_part(1) = start_idx_part(1) + proc_bubble_counts(i)
996 end do
997
998 start_idx_part(2) = 0
999 lsizes(1) = nbub
1000 lsizes(2) = lag_io_vars
1001
1002 gsizes(1) = file_tot_part
1003 gsizes(2) = lag_io_vars
1004
1005 if (nbub > 0) then
1006# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1007 allocate (bub_id(nbub))
1008# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1009 allocate (px(nbub))
1010# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1011 allocate (py(nbub))
1012# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1013 allocate (pz(nbub))
1014# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1015 allocate (ppx(nbub))
1016# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1017 allocate (ppy(nbub))
1018# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1019 allocate (ppz(nbub))
1020# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1021 allocate (vx(nbub))
1022# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1023 allocate (vy(nbub))
1024# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1025 allocate (vz(nbub))
1026# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1027 allocate (radius(nbub))
1028# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1029 allocate (rvel(nbub))
1030# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1031 allocate (rnot(nbub))
1032# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1033 allocate (rmax(nbub))
1034# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1035 allocate (rmin(nbub))
1036# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1037 allocate (dphidt(nbub))
1038# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1039 allocate (pressure(nbub))
1040# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1041 allocate (mv(nbub))
1042# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1043 allocate (mg(nbub))
1044# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1045 allocate (betat(nbub))
1046# 939 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1047 allocate (betac(nbub))
1048# 941 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1049 allocate (mpi_io_data_lg_bubbles(nbub,1:lag_io_vars))
1050
1051 call mpi_type_create_subarray(2, gsizes, lsizes, start_idx_part, mpi_order_fortran, mpi_p, view, ierr)
1052 call mpi_type_commit(view, ierr)
1053
1054 call mpi_file_open(mpi_comm_world, file_loc, mpi_mode_rdonly, mpi_info_int, ifile, ierr)
1055
1056 ! Skip extended header
1057 disp = int(sizeof(file_tot_part) + 2*sizeof(file_time) + sizeof(file_num_procs) &
1058 & + file_num_procs*sizeof(proc_bubble_counts(1)), mpi_offset_kind)
1059 call mpi_file_set_view(ifile, disp, mpi_p, view, 'native', mpi_info_int, ierr)
1060
1061 call mpi_file_read_all(ifile, mpi_io_data_lg_bubbles, lag_io_vars*nbub, mpi_p, status, ierr)
1062
1063 call mpi_file_close(ifile, ierr)
1064 call mpi_type_free(view, ierr)
1065
1066 ! Extract data from MPI_IO_DATA_lg_bubbles array Adjust these indices based on your actual data layout
1067# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1068 bub_id(:) = mpi_io_data_lg_bubbles(:,1)
1069# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1070 px(:) = mpi_io_data_lg_bubbles(:,2)
1071# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1072 py(:) = mpi_io_data_lg_bubbles(:,3)
1073# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1074 pz(:) = mpi_io_data_lg_bubbles(:,4)
1075# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1076 ppx(:) = mpi_io_data_lg_bubbles(:,5)
1077# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1078 ppy(:) = mpi_io_data_lg_bubbles(:,6)
1079# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1080 ppz(:) = mpi_io_data_lg_bubbles(:,7)
1081# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1082 vx(:) = mpi_io_data_lg_bubbles(:,8)
1083# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1084 vy(:) = mpi_io_data_lg_bubbles(:,9)
1085# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1086 vz(:) = mpi_io_data_lg_bubbles(:,10)
1087# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1088 radius(:) = mpi_io_data_lg_bubbles(:,11)
1089# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1090 rvel(:) = mpi_io_data_lg_bubbles(:,12)
1091# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1092 rnot(:) = mpi_io_data_lg_bubbles(:,13)
1093# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1094 rmax(:) = mpi_io_data_lg_bubbles(:,14)
1095# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1096 rmin(:) = mpi_io_data_lg_bubbles(:,15)
1097# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1098 dphidt(:) = mpi_io_data_lg_bubbles(:,16)
1099# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1100 pressure(:) = mpi_io_data_lg_bubbles(:,17)
1101# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1102 mv(:) = mpi_io_data_lg_bubbles(:,18)
1103# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1104 mg(:) = mpi_io_data_lg_bubbles(:,19)
1105# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1106 betat(:) = mpi_io_data_lg_bubbles(:,20)
1107# 963 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1108 betac(:) = mpi_io_data_lg_bubbles(:,21)
1109# 965 "/home/runner/work/MFC/MFC/src/post_process/m_data_output.fpp"
1110
1111 ! Next, the root processor proceeds to record all of the spatial extents in the formatted database master file. In
1112 ! addition, it also records a sub-domain connectivity map so that the entire grid may be reassembled by looking at the
1113 ! master file.
1114 if (proc_rank == 0) then
1115 do i = 1, num_procs
1116 write (meshnames(i), '(A,I0,A,I0,A)') '../p', i - 1, '/', t_step, '.silo:lag_bubbles'
1117 meshtypes(i) = db_pointmesh
1118 end do
1119 err = dbset2dstrlen(len(meshnames(1)))
1120 err = dbputmmesh(out%dbroot, 'lag_bubbles', 16, num_procs, meshnames, len_trim(meshnames), meshtypes, db_f77null, &
1121 & ierr)
1122 end if
1123
1124 err = dbputpm(out%dbfile, 'lag_bubbles', 11, 3, px, py, pz, nbub, db_double, db_f77null, ierr)
1125
1126 if (lag_id_wrt) call s_write_lag_variable_to_formatted_database_file('part_id', t_step, bub_id, nbub)
1127 if (lag_vel_wrt) then
1128 call s_write_lag_variable_to_formatted_database_file('part_vel1', t_step, vx, nbub)
1129 call s_write_lag_variable_to_formatted_database_file('part_vel2', t_step, vy, nbub)
1130 if (p > 0) call s_write_lag_variable_to_formatted_database_file('part_vel3', t_step, vz, nbub)
1131 end if
1132 if (lag_rad_wrt) call s_write_lag_variable_to_formatted_database_file('part_radius', t_step, radius, nbub)
1133 if (lag_rvel_wrt) call s_write_lag_variable_to_formatted_database_file('part_rdot', t_step, rvel, nbub)
1134 if (lag_r0_wrt) call s_write_lag_variable_to_formatted_database_file('part_r0', t_step, rnot, nbub)
1135 if (lag_rmax_wrt) call s_write_lag_variable_to_formatted_database_file('part_rmax', t_step, rmax, nbub)
1136 if (lag_rmin_wrt) call s_write_lag_variable_to_formatted_database_file('part_rmin', t_step, rmin, nbub)
1137 if (lag_dphidt_wrt) call s_write_lag_variable_to_formatted_database_file('part_dphidt', t_step, dphidt, nbub)
1138 if (lag_pres_wrt) call s_write_lag_variable_to_formatted_database_file('part_pressure', t_step, pressure, nbub)
1139 if (lag_mv_wrt) call s_write_lag_variable_to_formatted_database_file('part_mv', t_step, mv, nbub)
1140 if (lag_mg_wrt) call s_write_lag_variable_to_formatted_database_file('part_mg', t_step, mg, nbub)
1141 if (lag_betat_wrt) call s_write_lag_variable_to_formatted_database_file('part_betaT', t_step, betat, nbub)
1142 if (lag_betac_wrt) call s_write_lag_variable_to_formatted_database_file('part_betaC', t_step, betac, nbub)
1143
1144 deallocate (bub_id, px, py, pz, ppx, ppy, ppz, vx, vy, vz, radius, rvel, rnot, rmax, rmin, dphidt, pressure, mv, mg, &
1145 & betat, betac)
1146 deallocate (mpi_io_data_lg_bubbles)
1147 else
1148 call mpi_type_contiguous(0, mpi_p, view, ierr)
1149 call mpi_type_commit(view, ierr)
1150
1151 call mpi_file_open(mpi_comm_world, file_loc, mpi_mode_rdonly, mpi_info_int, ifile, ierr)
1152
1153 ! Skip extended header
1154 disp = int(sizeof(file_tot_part) + 2*sizeof(file_time) + sizeof(file_num_procs) &
1155 & + file_num_procs*sizeof(proc_bubble_counts(1)), mpi_offset_kind)
1156 call mpi_file_set_view(ifile, disp, mpi_p, view, 'native', mpi_info_int, ierr)
1157
1158 call mpi_file_read_all(ifile, dummy, 0, mpi_p, status, ierr)
1159
1160 call mpi_file_close(ifile, ierr)
1161 call mpi_type_free(view, ierr)
1162
1163 if (proc_rank == 0) then
1164 do i = 1, num_procs
1165 write (meshnames(i), '(A,I0,A,I0,A)') '../p', i - 1, '/', t_step, '.silo:lag_bubbles'
1166 meshtypes(i) = db_pointmesh
1167 end do
1168 err = dbset2dstrlen(len(meshnames(1)))
1169 err = dbputmmesh(out%dbroot, 'lag_bubbles', 16, num_procs, meshnames, len_trim(meshnames), meshtypes, db_f77null, &
1170 & ierr)
1171 end if
1172
1173 err = dbsetemptyok(1)
1174 err = dbputpm(out%dbfile, 'lag_bubbles', 11, 3, dummy_data, dummy_data, dummy_data, 0, db_double, db_f77null, ierr)
1175
1176 if (lag_id_wrt) call s_write_lag_variable_to_formatted_database_file('part_id', t_step)
1177 if (lag_vel_wrt) then
1178 call s_write_lag_variable_to_formatted_database_file('part_vel1', t_step)
1179 call s_write_lag_variable_to_formatted_database_file('part_vel2', t_step)
1180 if (p > 0) call s_write_lag_variable_to_formatted_database_file('part_vel3', t_step)
1181 end if
1182 if (lag_rad_wrt) call s_write_lag_variable_to_formatted_database_file('part_radius', t_step)
1183 if (lag_rvel_wrt) call s_write_lag_variable_to_formatted_database_file('part_rdot', t_step)
1184 if (lag_r0_wrt) call s_write_lag_variable_to_formatted_database_file('part_r0', t_step)
1185 if (lag_rmax_wrt) call s_write_lag_variable_to_formatted_database_file('part_rmax', t_step)
1186 if (lag_rmin_wrt) call s_write_lag_variable_to_formatted_database_file('part_rmin', t_step)
1187 if (lag_dphidt_wrt) call s_write_lag_variable_to_formatted_database_file('part_dphidt', t_step)
1188 if (lag_pres_wrt) call s_write_lag_variable_to_formatted_database_file('part_pressure', t_step)
1189 if (lag_mv_wrt) call s_write_lag_variable_to_formatted_database_file('part_mv', t_step)
1190 if (lag_mg_wrt) call s_write_lag_variable_to_formatted_database_file('part_mg', t_step)
1191 if (lag_betat_wrt) call s_write_lag_variable_to_formatted_database_file('part_betaT', t_step)
1192 if (lag_betac_wrt) call s_write_lag_variable_to_formatted_database_file('part_betaC', t_step)
1193 end if
1194#endif
1195
1197
1198 !> Write a single Lagrangian bubble point-variable to the Silo database slave and master files.
1199 subroutine s_write_lag_variable_to_formatted_database_file(varname, t_step, data, nBubs)
1200
1201 character(len=*), intent(in) :: varname
1202 integer, intent(in) :: t_step
1203 real(wp), dimension(1:), intent(in), optional :: data
1204 integer, intent(in), optional :: nBubs
1205 character(len=64), dimension(num_procs) :: var_names
1206 integer, dimension(num_procs) :: var_types
1207 real(wp) :: dummy_data
1208 integer :: ierr
1209 integer :: i
1210
1211 dummy_data = 0._wp
1212
1213 if (present(nbubs) .and. present(data)) then
1214 if (proc_rank == 0) then
1215 do i = 1, num_procs
1216 write (var_names(i), '(A,I0,A,I0,A)') '../p', i - 1, '/', t_step, '.silo:' // trim(varname)
1217 var_types(i) = db_pointvar
1218 end do
1219 err = dbset2dstrlen(len(var_names(1)))
1220 err = dbputmvar(out%dbroot, trim(varname), len_trim(varname), num_procs, var_names, len_trim(var_names), &
1221 & var_types, db_f77null, ierr)
1222 end if
1223
1224 err = dbputpv1(out%dbfile, trim(varname), len_trim(varname), 'lag_bubbles', 11, data, nbubs, db_double, db_f77null, &
1225 & ierr)
1226 else
1227 if (proc_rank == 0) then
1228 do i = 1, num_procs
1229 write (var_names(i), '(A,I0,A,I0,A)') '../p', i - 1, '/', t_step, '.silo:' // trim(varname)
1230 var_types(i) = db_pointvar
1231 end do
1232 err = dbset2dstrlen(len(var_names(1)))
1233 err = dbsetemptyok(1)
1234 err = dbputmvar(out%dbroot, trim(varname), len_trim(varname), num_procs, var_names, len_trim(var_names), &
1235 & var_types, db_f77null, ierr)
1236 end if
1237
1238 err = dbsetemptyok(1)
1239 err = dbputpv1(out%dbfile, trim(varname), len_trim(varname), 'lag_bubbles', 11, dummy_data, 0, db_double, db_f77null, &
1240 & ierr)
1241 end if
1242
1244
1245 !> Convert the binary immersed-boundary state file to per-body formatted text files
1246 impure subroutine s_write_ib_state_files()
1247
1248 character(len=len_trim(case_dir) + 4*name_len) :: in_file, out_file, file_loc
1249 integer :: iu_in, ios, i, rec_id
1250 integer, allocatable, dimension(:) :: iu_out
1251 real(wp) :: rec_time
1252 real(wp), dimension(3) :: rec_force, rec_torque
1253 real(wp), dimension(3) :: rec_vel, rec_angular_vel
1254 real(wp), dimension(3) :: rec_angles, rec_centroid
1255
1256 file_loc = trim(case_dir) // '/D'
1257
1258 in_file = trim(file_loc) // '/ib_state.dat'
1259 open (newunit=iu_in, file=trim(in_file), form='unformatted', access='stream', status='old', action='read', iostat=ios)
1260 if (ios /= 0) then
1261 call s_mpi_abort('Cannot open IB state input file: ' // trim(in_file))
1262 end if
1263
1264 allocate (iu_out(num_ibs))
1265 do i = 1, num_ibs
1266 write (out_file, '(A,I0,A)') trim(file_loc) // '/ib_', i, '.txt'
1267 open (newunit=iu_out(i), file=trim(out_file), form='formatted', status='replace', action='write', iostat=ios)
1268 if (ios /= 0) then
1269 call s_mpi_abort('Cannot open IB state output file: ' // trim(out_file))
1270 end if
1271 write (iu_out(i), &
1272 & '(A)') 'mytime fx fy fz Tau_x Tau_y Tau_z vx vy vz omega_x omega_y omega_z angle_x angle_y angle_z x_c y_c z_c'
1273 end do
1274
1275 do
1276 read (iu_in, iostat=ios) rec_time, rec_id, rec_force, rec_torque, rec_vel, rec_angular_vel, rec_angles, &
1277 & rec_centroid(1), rec_centroid(2), rec_centroid(3)
1278 if (ios /= 0) exit
1279
1280 if (rec_id >= 1 .and. rec_id <= num_ibs) then
1281 write (iu_out(rec_id), '(19(ES24.16E3,1X))') rec_time, rec_force(1), rec_force(2), rec_force(3), rec_torque(1), &
1282 & rec_torque(2), rec_torque(3), rec_vel(1), rec_vel(2), rec_vel(3), rec_angular_vel(1), &
1283 & rec_angular_vel(2), rec_angular_vel(3), rec_angles(1), rec_angles(2), rec_angles(3), rec_centroid(1), &
1284 & rec_centroid(2), rec_centroid(3)
1285 end if
1286 end do
1287
1288 close (iu_in)
1289 do i = 1, num_ibs
1290 close (iu_out(i))
1291 end do
1292 deallocate (iu_out)
1293
1294 end subroutine s_write_ib_state_files
1295
1296 !> Extract the volume-fraction interface contour from primitive fields and write the coordinates to the interface data file.
1297 impure subroutine s_write_intf_data_file(q_prim_vf)
1298
1299 type(scalar_field), dimension(sys_size), intent(in) :: q_prim_vf
1300 integer :: i, j, k, l, cent
1301 integer :: counter, root !< number of data points extracted to fit shape to SH perturbations
1302 real(wp), allocatable :: x_td(:), y_td(:), x_d1(:), y_d1(:), y_d(:), x_d(:)
1303 real(wp) :: axp, axm, ayp, aym, tgp, euc_d, thres, maxalph_loc, maxalph_glb
1304
1305 allocate (x_d1(m*n))
1306 allocate (y_d1(m*n))
1307 counter = 0
1308 maxalph_loc = 0._wp
1309 do k = 0, p
1310 do j = 0, n
1311 do i = 0, m
1312 if (q_prim_vf(eqn_idx%E + 2)%sf(i, j, k) > maxalph_loc) then
1313 maxalph_loc = q_prim_vf(eqn_idx%E + 2)%sf(i, j, k)
1314 end if
1315 end do
1316 end do
1317 end do
1318
1319 call s_mpi_allreduce_max(maxalph_loc, maxalph_glb)
1320 if (p > 0) then
1321 do l = 0, p
1322 if (z_cc(l) < dz(l) .and. z_cc(l) > 0) then
1323 cent = l
1324 end if
1325 end do
1326 else
1327 cent = 0
1328 end if
1329
1330 thres = 0.9_wp*maxalph_glb
1331 do k = 0, n
1332 do j = 0, m
1333 axp = q_prim_vf(eqn_idx%E + 2)%sf(j + 1, k, cent)
1334 axm = q_prim_vf(eqn_idx%E + 2)%sf(j, k, cent)
1335 ayp = q_prim_vf(eqn_idx%E + 2)%sf(j, k + 1, cent)
1336 aym = q_prim_vf(eqn_idx%E + 2)%sf(j, k, cent)
1337 if ((axp > thres .and. axm < thres) .or. (axp < thres .and. axm > thres) .or. (ayp > thres .and. aym < thres) &
1338 & .or. (ayp < thres .and. aym > thres)) then
1339 if (counter == 0) then
1340 counter = counter + 1
1341 x_d1(counter) = x_cc(j)
1342 y_d1(counter) = y_cc(k)
1343 else
1344 tgp = sqrt(dx(j)**2 + dy(k)**2)
1345 do i = 1, counter
1346 euc_d = sqrt((x_cc(j) - x_d1(i))**2 + (y_cc(k) - y_d1(i))**2)
1347 if (euc_d < tgp) then
1348 exit
1349 else if (i == counter) then
1350 counter = counter + 1
1351 x_d1(counter) = x_cc(j)
1352 y_d1(counter) = y_cc(k)
1353 end if
1354 end do
1355 end if
1356 end if
1357 end do
1358 end do
1359
1360 allocate (x_d(counter), y_d(counter))
1361
1362 do i = 1, counter
1363 y_d(i) = y_d1(i)
1364 x_d(i) = x_d1(i)
1365 end do
1366 root = 0
1367
1368 call s_mpi_gather_data(x_d, counter, x_td, root)
1369 call s_mpi_gather_data(y_d, counter, y_td, root)
1370 if (proc_rank == 0) then
1371 do i = 1, size(x_td)
1372 if (i == size(x_td)) then
1373 write (211, '(F12.9,1X,F12.9,1X,I4)') x_td(i), y_td(i), size(x_td)
1374 else
1375 write (211, '(F12.9,1X,F12.9,1X,F3.1)') x_td(i), y_td(i), 0._wp
1376 end if
1377 end do
1378 end if
1379
1380 end subroutine s_write_intf_data_file
1381
1382 !> Compute volume-integrated kinetic, potential, and internal energies and write the energy budget to the energy data file.
1383 impure subroutine s_write_energy_data_file(q_prim_vf, q_cons_vf)
1384
1385 type(scalar_field), dimension(sys_size), intent(in) :: q_prim_vf, q_cons_vf
1386 real(wp) :: elk, egk, elp, egint, vb, vl, pres_av, et
1387 real(wp) :: rho, pres, dv, tmp, gamma, pi_inf, maxma, maxma_glb, maxvel, c, ma, h, qv
1388 real(wp), dimension(num_vels) :: vel
1389 real(wp), dimension(num_fluids) :: adv
1390 integer :: i, j, k, l, s !< looping indices
1391
1392 egk = 0._wp
1393 elp = 0._wp
1394 egint = 0._wp
1395 vb = 0._wp
1396 maxvel = 0._wp
1397 maxma = 0._wp
1398 vl = 0._wp
1399 elk = 0._wp
1400 et = 0._wp
1401 vb = 0._wp
1402 dv = 0._wp
1403 pres_av = 0._wp
1404 pres = 0._wp
1405 c = 0._wp
1406
1407 do k = 0, p
1408 do j = 0, n
1409 do i = 0, m
1410 pres = 0._wp
1411 dv = dx(i)*dy(j)*dz(k)
1412 rho = 0._wp
1413 gamma = 0._wp
1414 pi_inf = 0._wp
1415 qv = 0._wp
1416 pres = q_prim_vf(eqn_idx%E)%sf(i, j, k)
1417 egint = egint + q_prim_vf(eqn_idx%E + 2)%sf(i, j, k)*(gammas(2)*pres)*dv
1418 do s = 1, num_vels
1419 vel(s) = q_prim_vf(num_fluids + s)%sf(i, j, k)
1420 egk = egk + 0.5_wp*q_prim_vf(eqn_idx%E + 2)%sf(i, j, k)*q_prim_vf(2)%sf(i, j, k)*vel(s)*vel(s)*dv
1421 elk = elk + 0.5_wp*q_prim_vf(eqn_idx%E + 1)%sf(i, j, k)*q_prim_vf(1)%sf(i, j, k)*vel(s)*vel(s)*dv
1422 if (abs(vel(s)) > maxvel) then
1423 maxvel = abs(vel(s))
1424 end if
1425 end do
1426 do l = 1, eqn_idx%adv%end - eqn_idx%E
1427 adv(l) = q_prim_vf(eqn_idx%E + l)%sf(i, j, k)
1428 gamma = gamma + adv(l)*gammas(l)
1429 pi_inf = pi_inf + adv(l)*pi_infs(l)
1430 rho = rho + adv(l)*q_prim_vf(l)%sf(i, j, k)
1431 qv = qv + adv(l)*q_prim_vf(l)%sf(i, j, k)*qvs(l)
1432 end do
1433
1434 h = ((gamma + 1._wp)*pres + pi_inf + qv)/rho
1435
1436 call s_compute_speed_of_sound(pres, rho, gamma, pi_inf, h, adv, 0._wp, 0._wp, c, qv)
1437
1438 ma = maxvel/c
1439 if (ma > maxma .and. (adv(1) > (1.0_wp - 1.0e-10_wp))) then
1440 maxma = ma
1441 end if
1442 vl = vl + adv(1)*dv
1443 vb = vb + adv(2)*dv
1444 pres_av = pres_av + adv(1)*pres*dv
1445 et = et + q_cons_vf(eqn_idx%E)%sf(i, j, k)*dv
1446 end do
1447 end do
1448 end do
1449
1450 tmp = pres_av
1451 call s_mpi_allreduce_sum(tmp, pres_av)
1452 tmp = vl
1453 call s_mpi_allreduce_sum(tmp, vl)
1454
1455 call s_mpi_allreduce_max(maxma, maxma_glb)
1456 tmp = elk
1457 call s_mpi_allreduce_sum(tmp, elk)
1458 tmp = egint
1459 call s_mpi_allreduce_sum(tmp, egint)
1460 tmp = egk
1461 call s_mpi_allreduce_sum(tmp, egk)
1462 tmp = vb
1463 call s_mpi_allreduce_sum(tmp, vb)
1464 tmp = et
1465 call s_mpi_allreduce_sum(tmp, et)
1466
1467 elp = pres_av/vl*vb
1468 if (proc_rank == 0) then
1469 write (251, '(10X, 8F24.8)') elp, egint, elk, egk, et, vb, vl, maxma_glb
1470 end if
1471
1472 end subroutine s_write_energy_data_file
1473
1474 !> Read IB state and write a Silo point mesh with per-body scalar fields.
1476
1477 integer, intent(in) :: t_step
1478 character(len=len_trim(case_dir) + 3*name_len) :: file_loc
1479
1480#ifdef MFC_MPI
1481 integer, parameter :: nfields_per_ib = 20
1482 real(wp) :: ib_buf(nfields_per_ib)
1483 real(wp), dimension(:,:), allocatable :: ib_data
1484 logical :: file_exist
1485 character(LEN=4*name_len), dimension(num_procs) :: meshnames
1486 integer, dimension(num_procs) :: meshtypes
1487 integer :: i, ios, file_unit
1488 integer :: ierr, nbodies
1489 integer :: r, nlocal, gbl_id
1490 character(len=10) :: t_step_string
1491 real(wp), dimension(:), allocatable :: px, py, pz
1492 real(wp), dimension(:), allocatable :: force_x, force_y, force_z
1493 real(wp), dimension(:), allocatable :: torque_x, torque_y, torque_z
1494 real(wp), dimension(:), allocatable :: vel_x, vel_y, vel_z
1495 real(wp), dimension(:), allocatable :: omega_x, omega_y, omega_z
1496 real(wp), dimension(:), allocatable :: angle_x, angle_y, angle_z
1497 real(wp), dimension(:), allocatable :: ib_diameter
1498
1499 if (proc_rank == 0) then
1500 nbodies = num_ibs
1501
1502 if (nbodies > 0) then
1503 allocate (ib_data(nbodies, nfields_per_ib))
1504 allocate (px(nbodies), py(nbodies), pz(nbodies))
1505 allocate (force_x(nbodies), force_y(nbodies), force_z(nbodies))
1506 allocate (torque_x(nbodies), torque_y(nbodies), torque_z(nbodies))
1507 allocate (vel_x(nbodies), vel_y(nbodies), vel_z(nbodies))
1508 allocate (omega_x(nbodies), omega_y(nbodies), omega_z(nbodies))
1509 allocate (angle_x(nbodies), angle_y(nbodies), angle_z(nbodies))
1510 allocate (ib_diameter(nbodies))
1511
1512 if (file_per_process) then
1513 call s_int_to_str(t_step, t_step_string)
1514 ib_data = 0._wp
1515 do r = 0, num_procs - 1
1516 write (file_loc, '(A,I0,A,i7.7,A)') 'ib_state_', t_step, '_', r, '.dat'
1517 file_loc = trim(case_dir) // '/restart_data/lustre_' // trim(t_step_string) // '/' // trim(file_loc)
1518
1519 inquire (file=trim(file_loc), exist=file_exist)
1520 if (.not. file_exist) call s_mpi_abort('Restart file ' // trim(file_loc) // ' does not exist!')
1521
1522 open (newunit=file_unit, file=trim(file_loc), form='unformatted', access='stream', status='old', iostat=ios)
1523 if (ios /= 0) call s_mpi_abort('Cannot open IB state file: ' // trim(file_loc))
1524
1525 read (file_unit, iostat=ios) nlocal
1526 if (ios /= 0) call s_mpi_abort('Error reading IB state file header: ' // trim(file_loc))
1527
1528 do i = 1, nlocal
1529 read (file_unit, iostat=ios) gbl_id
1530 if (ios /= 0) call s_mpi_abort('Error reading IB patch ID: ' // trim(file_loc))
1531 read (file_unit, iostat=ios) ib_buf
1532 if (ios /= 0) call s_mpi_abort('Error reading IB state data: ' // trim(file_loc))
1533 ib_data(gbl_id,:) = ib_buf(:)
1534 end do
1535
1536 close (file_unit)
1537 end do
1538 else
1539 ! Build path to per-timestep IB state file
1540 write (file_loc, '(A,I0,A)') '/restart_data/ib_state_', t_step, '.dat'
1541 file_loc = trim(case_dir) // trim(file_loc)
1542
1543 inquire (file=trim(file_loc), exist=file_exist)
1544 if (.not. file_exist) call s_mpi_abort('Restart file ' // trim(file_loc) // ' does not exist!')
1545
1546 open (newunit=file_unit, file=trim(file_loc), form='unformatted', access='stream', status='old', iostat=ios)
1547 if (ios /= 0) call s_mpi_abort('Cannot open IB state file: ' // trim(file_loc))
1548
1549 do i = 1, nbodies
1550 read (file_unit, iostat=ios) ib_buf
1551 if (ios /= 0) call s_mpi_abort('Error reading IB state file')
1552 ib_data(i,:) = ib_buf(:)
1553 end do
1554
1555 close (file_unit)
1556 end if
1557
1558 do i = 1, nbodies
1559 force_x(i) = ib_data(i, 2); force_y(i) = ib_data(i, 3); force_z(i) = ib_data(i, 4)
1560 torque_x(i) = ib_data(i, 5); torque_y(i) = ib_data(i, 6); torque_z(i) = ib_data(i, 7)
1561 vel_x(i) = ib_data(i, 8); vel_y(i) = ib_data(i, 9); vel_z(i) = ib_data(i, 10)
1562 omega_x(i) = ib_data(i, 11); omega_y(i) = ib_data(i, 12); omega_z(i) = ib_data(i, 13)
1563 angle_x(i) = ib_data(i, 14); angle_y(i) = ib_data(i, 15); angle_z(i) = ib_data(i, 16)
1564 px(i) = ib_data(i, 17); py(i) = ib_data(i, 18); pz(i) = ib_data(i, 19)
1565 ib_diameter(i) = ib_data(i, 20)*2.0_wp
1566 end do
1567
1568 write (meshnames(1), '(A,I0,A)') '../p0/', t_step, '.silo:ib_bodies'
1569 meshtypes(1) = db_pointmesh
1570 err = dbset2dstrlen(len(meshnames(1)))
1571 err = dbputmmesh(out%dbroot, 'ib_bodies', 16, 1, meshnames, len_trim(meshnames), meshtypes, db_f77null, ierr)
1572
1573 err = dbputpm(out%dbfile, 'ib_bodies', 9, 3, px, py, pz, nbodies, db_double, db_f77null, ierr)
1574
1575 call s_write_ib_variable('ib_force_x', t_step, force_x, nbodies)
1576 call s_write_ib_variable('ib_force_y', t_step, force_y, nbodies)
1577 call s_write_ib_variable('ib_force_z', t_step, force_z, nbodies)
1578 call s_write_ib_variable('ib_torque_x', t_step, torque_x, nbodies)
1579 call s_write_ib_variable('ib_torque_y', t_step, torque_y, nbodies)
1580 call s_write_ib_variable('ib_torque_z', t_step, torque_z, nbodies)
1581 call s_write_ib_variable('ib_vel_x', t_step, vel_x, nbodies)
1582 call s_write_ib_variable('ib_vel_y', t_step, vel_y, nbodies)
1583 call s_write_ib_variable('ib_vel_z', t_step, vel_z, nbodies)
1584 call s_write_ib_variable('ib_omega_x', t_step, omega_x, nbodies)
1585 call s_write_ib_variable('ib_omega_y', t_step, omega_y, nbodies)
1586 call s_write_ib_variable('ib_omega_z', t_step, omega_z, nbodies)
1587 call s_write_ib_variable('ib_angle_x', t_step, angle_x, nbodies)
1588 call s_write_ib_variable('ib_angle_y', t_step, angle_y, nbodies)
1589 call s_write_ib_variable('ib_angle_z', t_step, angle_z, nbodies)
1590 call s_write_ib_variable('ib_diameter', t_step, ib_diameter, nbodies)
1591
1592 deallocate (ib_data, px, py, pz, force_x, force_y, force_z)
1593 deallocate (torque_x, torque_y, torque_z, vel_x, vel_y, vel_z)
1594 deallocate (omega_x, omega_y, omega_z, angle_x, angle_y, angle_z)
1595 deallocate (ib_diameter)
1596 end if
1597 end if
1598#endif
1599
1601
1602 !> Write a single IB point-variable to the Silo database slave and master files.
1603 subroutine s_write_ib_variable(varname, t_step, data, nBodies)
1604
1605 character(len=*), intent(in) :: varname
1606 integer, intent(in) :: t_step
1607 real(wp), dimension(:), intent(in) :: data
1608 integer, intent(in) :: nBodies
1609 character(len=4*name_len) :: var_name_entry
1610 integer :: var_type_entry, ierr
1611
1612 write (var_name_entry, '(A,I0,A)') '../p0/', t_step, '.silo:' // trim(varname)
1613 var_type_entry = db_pointvar
1614 err = dbset2dstrlen(len(var_name_entry))
1615 err = dbputmvar(out%dbroot, trim(varname), len_trim(varname), 1, var_name_entry, len_trim(var_name_entry), &
1616 & var_type_entry, db_f77null, ierr)
1617
1618 err = dbputpv1(out%dbfile, trim(varname), len_trim(varname), 'ib_bodies', 9, data, nbodies, db_double, db_f77null, ierr)
1619
1620 end subroutine s_write_ib_variable
1621
1622 !> Close the formatted database slave file and, for the root process, the master file.
1624
1625 integer :: ierr
1626
1627 if (format == format_silo) then
1628 ierr = dbclose(out%dbfile)
1629 if (proc_rank == 0) ierr = dbclose(out%dbroot)
1630 else
1631 close (out%dbfile)
1632 if (n == 0 .and. proc_rank == 0) close (out%dbroot)
1633 end if
1634
1635 end subroutine s_close_formatted_database_file
1636
1637 !> Close the interface data file.
1638 impure subroutine s_close_intf_data_file()
1639
1640 close (211)
1641
1642 end subroutine s_close_intf_data_file
1643
1644 !> Close the energy data file.
1645 impure subroutine s_close_energy_data_file()
1646
1647 close (251)
1648
1649 end subroutine s_close_energy_data_file
1650
1651 !> Deallocate module arrays and release all data-output resources.
1653
1654 deallocate (out%q_sf)
1655 if (n == 0) deallocate (out%q_root_sf)
1656 if (grid_geometry == 3) then
1657 deallocate (out%cyl_q_sf)
1658 end if
1659
1660 ! Deallocating spatial and data extents and also the variables for the offsets and the one bookkeeping the number of
1661 ! cell-boundaries in each active coordinate direction. Note that all these variables were only needed by Silo-HDF5 format
1662 ! for multidimensional data.
1663 if (format == format_silo) then
1664 deallocate (out%spatial_extents)
1665 deallocate (out%data_extents)
1666 deallocate (out%lo_offset)
1667 deallocate (out%hi_offset)
1668 deallocate (out%dims)
1669 end if
1670
1671 end subroutine s_finalize_data_output_module
1672
1673end module m_data_output
type(scalar_field), dimension(sys_size), intent(inout) q_cons_vf
integer, intent(in) k
integer, intent(in) j
integer, intent(in) l
Platform-specific file and directory operations: create, delete, inquire, getcwd, and basename.
impure subroutine my_inquire(fileloc, dircheck)
Inquire on the existence of a directory or file.
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 lag_io_vars
Number of variables per particle for MPI_IO.
integer, parameter model_eqns_5eq
integer, parameter format_silo
integer, parameter format_binary
integer, parameter precision_single
integer, parameter model_eqns_6eq
integer, parameter model_eqns_gamma_law
Writes post-processed grid and flow-variable data to Silo-HDF5 or binary database files.
impure subroutine, public s_write_grid_to_formatted_database_file(t_step)
Write the computational grid (cell-boundary coordinates) to the formatted database slave and master f...
impure subroutine, public s_write_variable_to_formatted_database_file(varname, t_step)
Write a single flow variable field to the formatted database slave and master files for a given time ...
impure subroutine, public s_open_energy_data_file()
Open the energy data file for appending volume-integrated energy budget quantities.
impure subroutine, public s_open_intf_data_file()
Open the interface data file for appending extracted interface coordinates.
impure subroutine, public s_write_ib_state_files()
Convert the binary immersed-boundary state file to per-body formatted text files.
impure subroutine, public s_write_energy_data_file(q_prim_vf, q_cons_vf)
Compute volume-integrated kinetic, potential, and internal energies and write the energy budget to th...
impure subroutine, public s_write_lag_bubbles_to_formatted_database_file(t_step)
Read Lagrangian bubble restart data and write bubble positions and scalar fields to the Silo database...
impure subroutine, public s_write_intf_data_file(q_prim_vf)
Extract the volume-fraction interface contour from primitive fields and write the coordinates to the ...
subroutine s_write_ib_variable(varname, t_step, data, nbodies)
Write a single IB point-variable to the Silo database slave and master files.
impure subroutine, public s_initialize_data_output_module()
Allocate storage arrays, configure output directories, and count flow variables for formatted databas...
impure subroutine, public s_close_energy_data_file()
Close the energy data file.
impure subroutine, public s_close_formatted_database_file()
Close the formatted database slave file and, for the root process, the master file.
impure subroutine, public s_open_formatted_database_file(t_step)
Open (or create) the Silo-HDF5 or Binary formatted database slave and master files for a given time s...
impure subroutine, public s_close_intf_data_file()
Close the interface data file.
impure subroutine, public s_write_lag_bubbles_results_to_text(t_step)
Write the post-processed results in the folder 'lag_bubbles_data'.
impure subroutine, public s_finalize_data_output_module()
Deallocate module arrays and release all data-output resources.
integer, private err
impure subroutine, public s_define_output_region
Compute the cell-index bounds for the user-specified partial output domain in each coordinate directi...
impure subroutine, public s_write_ib_bodies_to_formatted_database_file(t_step)
Read IB state and write a Silo point mesh with per-body scalar fields.
type(output_context), public out
Output workspace: flow variable buffers, VisIt extents/offsets, directory paths, file handles,...
subroutine s_write_lag_variable_to_formatted_database_file(varname, t_step, data, nbubs)
Write a single Lagrangian bubble point-variable to the Silo database slave and master files.
Shared derived types for field data, patch geometry, bubble dynamics, and MPI I/O structures.
Computes derived flow quantities (sound speed, vorticity, Schlieren, etc.) from conservative and prim...
Global parameters for the post-process: domain geometry, equation of state, and output database setti...
type(int_bounds_info) offset_y
real(wp), dimension(:,:), allocatable, public mpi_io_data_lg_bubbles
real(wp), dimension(:), allocatable y_cc
integer proc_rank
Rank of the local processor.
real(wp), dimension(:), allocatable adv
Advection variables.
type(int_bounds_info) z_output_idx
Indices of domain to output for post-processing.
real(wp), dimension(:), allocatable y_cb
real(wp), dimension(:), allocatable dz
real(wp), dimension(:), allocatable x_root_cb
real(wp), dimension(:), allocatable z_cb
type(bounds_info) z_output
Portion of domain to output for post-processing.
type(int_bounds_info) x_output_idx
real(wp), dimension(:), allocatable x_cc
real(wp), dimension(:), allocatable x_cb
real(wp), dimension(:), allocatable dy
type(int_bounds_info) offset_x
real(wp), dimension(:), allocatable z_cc
integer num_procs
Number of processors.
type(int_bounds_info) y_output_idx
type(int_bounds_info) offset_z
real(wp), dimension(:), allocatable dx
Cell-width distributions in the x-, y- and z-coordinate directions.
Utility routines for bubble model setup, coordinate transforms, array sampling, and special functions...
elemental subroutine, public s_int_to_str(i, res)
Convert an integer to its trimmed string representation.
MPI gather and scatter operations for distributing post-process grid and flow-variable data.
impure subroutine s_mpi_defragment_1d_grid_variable
Collect the sub-domain cell-boundary or cell-center location data from all processors and put back to...
impure subroutine s_mpi_defragment_1d_flow_variable(q_sf, q_root_sf)
Gather the sub-domain flow variable data from all processors and reassemble it for the entire computa...
impure subroutine s_mpi_gather_spatial_extents(spatial_extents)
Gather spatial extents from all ranks for Silo database metadata.
impure subroutine s_mpi_gather_data_extents(q_sf, data_extents)
Gather the Silo database metadata for the flow variable's extents to boost performance of the multidi...
Conservative-to-primitive variable conversion, mixture property evaluation, and pressure computation.
real(wp), dimension(:), allocatable, public gammas
subroutine s_compute_speed_of_sound(pres, rho, gamma, pi_inf, h, adv, vel_sum, c_c, c, qv)
Compute the speed of sound from thermodynamic state variables, supporting multiple equation-of-state ...
real(wp), dimension(:), allocatable, public qvs
real(wp), dimension(:), allocatable, public pi_infs
Output workspace for post_process: flow variable buffers, VisIt extents/offsets, directory paths,...
Derived type annexing a scalar field (SF).