From 6a9ed308f84a3d917b92fd13e53c698a7d2a4e8f Mon Sep 17 00:00:00 2001
From: Ben Wilfong <48168887+wilfonba@users.noreply.github.com>
Date: Wed, 13 Dec 2023 13:11:27 -0500
Subject: [PATCH 1/7] Performance manual page and better namelist errors
---
docs/documentation/expectedPerformance.md | 74 ++++
docs/res/strongScaling/S01.95 | 1 +
docs/res/strongScaling/cpuStrongScaling.svg | 450 ++++++++++++++++++++
docs/res/strongScaling/strongScaling16.svg | 429 +++++++++++++++++++
docs/res/strongScaling/strongScaling64.svg | 429 +++++++++++++++++++
docs/res/weakScaling/cpuScaling.svg | 364 ++++++++++++++++
docs/res/weakScaling/frontier.svg | 1 +
docs/res/weakScaling/summit.svg | 1 +
src/common/m_delay_file_access.f90 | 37 ++
src/post_process/m_data_input.f90 | 140 ++++--
src/post_process/m_global_parameters.fpp | 2 +
src/post_process/m_mpi_proxy.fpp | 2 +-
src/post_process/m_start_up.f90 | 11 +-
src/pre_process/m_data_output.fpp | 185 +++++---
src/pre_process/m_global_parameters.fpp | 2 +
src/pre_process/m_mpi_proxy.fpp | 2 +-
src/pre_process/m_start_up.fpp | 8 +-
src/simulation/m_data_output.fpp | 179 +++++---
src/simulation/m_global_parameters.fpp | 2 +
src/simulation/m_mpi_proxy.fpp | 2 +-
src/simulation/m_start_up.fpp | 173 +++++---
toolchain/mfc/run/case_dicts.py | 2 +-
22 files changed, 2281 insertions(+), 215 deletions(-)
create mode 100644 docs/documentation/expectedPerformance.md
create mode 100644 docs/res/strongScaling/S01.95
create mode 100644 docs/res/strongScaling/cpuStrongScaling.svg
create mode 100644 docs/res/strongScaling/strongScaling16.svg
create mode 100644 docs/res/strongScaling/strongScaling64.svg
create mode 100644 docs/res/weakScaling/cpuScaling.svg
create mode 100644 src/common/m_delay_file_access.f90
diff --git a/docs/documentation/expectedPerformance.md b/docs/documentation/expectedPerformance.md
new file mode 100644
index 000000000..c2455d3a0
--- /dev/null
+++ b/docs/documentation/expectedPerformance.md
@@ -0,0 +1,74 @@
+# Performance Results
+
+MFC has been extensively benchmarked on both CPUs and GPUs. A summary of these results follow.
+
+## Expected time-steps/hour
+
+The following table outlines expected performance in terms of number of time-steps per hour
+(rounded to the nearest hundred) for various problem sizes and hardware for a inviscid, 6-equation,
+3D simulation. CPU results utilize an entire die.
+
+| Hardware | # Ranks | 1M Cells | 4M Cells | 8M Cells | Compiler | Computer |
+| ---: | :----: | :----: | :---: | :---: | :----: | :--- |
+| Nvidia V100 | 1 | 88.5k | 18.7k | N/A | NVHPC 22.11 | PACE Phoenix |
+| Nvidia A100 | 1 | 114.4k | 34.6k | 16.5k | NVHPC 23.5 | Wingtip |
+| AMD MI250x | 1 | 77.5k | 22.3k | 11.2k | CCE 16.0.1 | OLCF Frontier |
+| Intel Xeon Gold 6226 | 12 | 2.5k | 0.7k | 0.4k | GNU 10.3.0 | Pace Phoenix |
+| Apple Silicon M2 | 6 | 2.8k | 0.6k | 0.2k | GNU 13.2.0 | N/A |
+
+If `'model_eqns' : 3` is replaced by `'model_eqns' : 2`, an inviscid 5-equation model is used.
+The following table outlines expected performance in terms of number of time-steps per hour
+(rounded to the nearest hundred) for various problem sizes and hardware for a inviscid, 5-equation,
+3D simulation. CPU results utilize an entire die.
+
+| Hardware | # Ranks | 1M Cells | 4M Cells | 8M Cells | Compiler | Computer |
+| ---: | :----: | :----: | :---: | :---: | :----: | :--- |
+| Nvidia V100 | 1 | 113.4k | 26.2k | N/A | NVHPC 22.11 | PACE Phoenix |
+| Nvidia A100 | 1 | 153.5k | 48.0k | 22.5k | NVHPC 23.5 | Wingtip |
+| AMD MI250x | 1 | 104.2k | 31.0k | 14.8k | CCE 16.0.1 | OLCF Frontier |
+| Intel Xeon Gold 6226 | 12 | 5.4k | 1.6k | 0.8k | GNU 10.3.0 | Pace Phoenix |
+| Apple Silicon M2 | 6 | 3.7k | 11.0k | 0.3k | GNU 13.2.0 | N/A |
+
+## Weak scaling
+
+Strong scaling results are obtained by increasing the problem size with the number of processes
+so that work per process remains constant.
+
+### AMD MI250X GPU
+MFC weask scales to 65,536 AMD MI250X GPUs on OLCF Frontier with 96% efficiency.
+
+
+
+### Nvidia V100 GPU
+MFC weak scales to 13,824 V100 Nvidia V100 GPUs on OLCF Summit with 97% efficiency.
+
+
+
+### IMB Power9 CPU
+MFC Weak scales to 13,824 Power9 CPU cores on OLCF Summit with 1% of ideal scaling.
+
+
+
+## Strong scaling
+
+Strong scaling results are obtained by keeping the problem size constant and increasing
+the number of process so that work per process decreases.
+
+### Nvidia V100 GPU
+
+For these tests, the base case utilizes 8 GPUs with one MPI process per GPU. The performance
+is analyzed at two different problem sizes of 16 and 64M grid points, with the base case using
+2 and 8M grid points per process.
+
+#### 16M Grid Points
+
+
+#### 64M Grid Points
+
+
+### IBM Power 9 CPU
+
+CPU strong scaling tests are done with problem sizes of 16, 32, and 64M grid points, with the
+base case using 2, 4, and 8M cells per process.
+
+
\ No newline at end of file
diff --git a/docs/res/strongScaling/S01.95 b/docs/res/strongScaling/S01.95
new file mode 100644
index 000000000..ebd60169b
--- /dev/null
+++ b/docs/res/strongScaling/S01.95
@@ -0,0 +1 @@
+
Towards exascale multiphase compressible flow simulation via scalable interface capturing-based solvers and GPU acceleration - Anand Radhakrishnan Towards exascale multiphase compressible flow simulation via scalable interface capturing-based solvers and GPU acceleration Date: November 21, 2022
diff --git a/docs/res/strongScaling/cpuStrongScaling.svg b/docs/res/strongScaling/cpuStrongScaling.svg
new file mode 100644
index 000000000..1597b20e0
--- /dev/null
+++ b/docs/res/strongScaling/cpuStrongScaling.svg
@@ -0,0 +1,450 @@
+
+image/svg+xml 10
+1
+10
+2
+10
+0
+10
+1
+10
+2
+Smaller Problem perCPUcore
+8M
+4M
+2M
+NumberofCPUcores
+Walltime[s]
+Ideal
+MFC
+
\ No newline at end of file
diff --git a/docs/res/strongScaling/strongScaling16.svg b/docs/res/strongScaling/strongScaling16.svg
new file mode 100644
index 000000000..e391e8a0a
--- /dev/null
+++ b/docs/res/strongScaling/strongScaling16.svg
@@ -0,0 +1,429 @@
+
+image/svg+xml 10
+1
+10
+2
+10
+−
+3
+10
+−
+2
+10
+−
+1
+10
+0
+CUMPI
+MPI
+NumberofGPUs
+Walltime[s]
+Ideal
+MFC
+
\ No newline at end of file
diff --git a/docs/res/strongScaling/strongScaling64.svg b/docs/res/strongScaling/strongScaling64.svg
new file mode 100644
index 000000000..91032bf18
--- /dev/null
+++ b/docs/res/strongScaling/strongScaling64.svg
@@ -0,0 +1,429 @@
+
+image/svg+xml 10
+1
+10
+2
+10
+−
+3
+10
+−
+2
+10
+−
+1
+10
+0
+CUMPI
+MPI
+NumberofGPUs
+Walltime[s]
+Ideal
+MFC
+
\ No newline at end of file
diff --git a/docs/res/weakScaling/cpuScaling.svg b/docs/res/weakScaling/cpuScaling.svg
new file mode 100644
index 000000000..0108f89a2
--- /dev/null
+++ b/docs/res/weakScaling/cpuScaling.svg
@@ -0,0 +1,364 @@
+
+image/svg+xml 10
+2
+10
+3
+10
+4
+0
+0
+.
+5
+1
+1
+.
+5
+NumberofGPUs
+NormalizedWallTime
+Ideal
+MFC
+
\ No newline at end of file
diff --git a/docs/res/weakScaling/frontier.svg b/docs/res/weakScaling/frontier.svg
index b47bd21fa..5882a346e 100644
--- a/docs/res/weakScaling/frontier.svg
+++ b/docs/res/weakScaling/frontier.svg
@@ -1,5 +1,6 @@
@}
logical :: parallel_io !< Format of the data files
+ logical :: file_per_process !< output format
integer, allocatable, dimension(:) :: proc_coords !<
!! Processor coordinates in MPI_CART_COMM
@@ -294,6 +295,7 @@ contains
flux_lim = dflt_int
flux_wrt = .false.
parallel_io = .false.
+ file_per_process = .true.
E_wrt = .false.
pres_wrt = .false.
alpha_wrt = .false.
diff --git a/src/post_process/m_mpi_proxy.fpp b/src/post_process/m_mpi_proxy.fpp
index 1d67d9168..ef09f1bf3 100644
--- a/src/post_process/m_mpi_proxy.fpp
+++ b/src/post_process/m_mpi_proxy.fpp
@@ -168,7 +168,7 @@ contains
& 'E_wrt', 'pres_wrt', 'gamma_wrt', &
& 'heat_ratio_wrt', 'pi_inf_wrt', 'pres_inf_wrt', 'cons_vars_wrt', &
& 'prim_vars_wrt', 'c_wrt', 'qm_wrt','schlieren_wrt', 'bubbles', &
- & 'polytropic', 'polydisperse' ]
+ & 'polytropic', 'polydisperse', 'file_per_process' ]
call MPI_BCAST(${VAR}$, 1, MPI_LOGICAL, 0, MPI_COMM_WORLD, ierr)
#:endfor
diff --git a/src/post_process/m_start_up.f90 b/src/post_process/m_start_up.f90
index 3741cc3e4..1f259c85f 100644
--- a/src/post_process/m_start_up.f90
+++ b/src/post_process/m_start_up.f90
@@ -53,6 +53,8 @@ subroutine s_read_input_file() ! ---------------------------------------
integer :: iostatus
!! Integer to check iostat of file read
+ character(len=1000) :: line
+
! Namelist for all of the parameters to be inputed by the user
namelist /user_inputs/ case_dir, m, n, p, t_step_start, &
t_step_stop, t_step_save, model_eqns, &
@@ -69,7 +71,7 @@ subroutine s_read_input_file() ! ---------------------------------------
flux_lim, flux_wrt, cyl_coord, &
parallel_io, rhoref, pref, bubbles, qbmm, sigR, &
R0ref, nb, polytropic, thermal, Ca, Web, Re_inv, &
- polydisperse, poly_sigma
+ polydisperse, poly_sigma, file_per_process
! Inquiring the status of the post_process.inp file
file_loc = 'post_process.inp'
@@ -83,8 +85,11 @@ subroutine s_read_input_file() ! ---------------------------------------
read (1, NML=user_inputs, iostat=iostatus)
if (iostatus /= 0) then
- call s_mpi_abort('Invalid line in post_process.inp. It is '// &
- 'likely due to a datatype mismatch. Exiting ...')
+ backspace(1)
+ read(1,fmt='(A)') line
+ print*, 'Invalid line in namelist: '//trim(line)
+ call s_mpi_abort('Invalid line in pre_process.inp. It is '// &
+ 'likely due to a datatype mismatch. Exiting ...')
end if
close (1)
diff --git a/src/pre_process/m_data_output.fpp b/src/pre_process/m_data_output.fpp
index 9c57d9d76..c10fc76e5 100644
--- a/src/pre_process/m_data_output.fpp
+++ b/src/pre_process/m_data_output.fpp
@@ -29,6 +29,8 @@ module m_data_output
use m_variables_conversion
use m_helper
+
+ use m_delay_file_access
! ==========================================================================
implicit none
@@ -396,80 +398,147 @@ contains
integer(KIND=MPI_OFFSET_KIND) :: MOK
character(LEN=path_len + 2*name_len) :: file_loc
- logical :: file_exist
+ logical :: file_exist, dir_check
! Generic loop iterator
integer :: i
- ! Initialize MPI data I/O
- call s_initialize_mpi_data(q_cons_vf)
-
- ! Open the file to write all flow variables
- write (file_loc, '(I0,A)') t_step_start, '.dat'
- file_loc = trim(restart_dir)//trim(mpiiofs)//trim(file_loc)
- inquire (FILE=trim(file_loc), EXIST=file_exist)
- if (file_exist .and. proc_rank == 0) then
- call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
- end if
- call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, ior(MPI_MODE_WRONLY, MPI_MODE_CREATE), &
- mpi_info_int, ifile, ierr)
-
- ! Size of local arrays
- data_size = (m + 1)*(n + 1)*(p + 1)
-
- ! Resize some integers so MPI can write even the biggest files
- m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
- n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
- p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
- WP_MOK = int(8d0, MPI_OFFSET_KIND)
- MOK = int(1d0, MPI_OFFSET_KIND)
- str_MOK = int(name_len, MPI_OFFSET_KIND)
- NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
-
- ! Write the data for each variable
- if (bubbles) then
- do i = 1, sys_size! adv_idx%end
- var_MOK = int(i, MPI_OFFSET_KIND)
-
- ! Initial displacement to skip at beginning of file
- disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
-
- call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
- call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
- MPI_DOUBLE_PRECISION, status, ierr)
- end do
- !Additional variables pb and mv for non-polytropic qbmm
- if(qbmm .and. .not. polytropic) then
- do i = sys_size + 1, sys_size + 2*nb*nnode
+ if (file_per_process) then
+ if (proc_rank == 0) then
+ file_loc = trim(case_dir)//'/restart_data/lustre_0'
+ call my_inquire(file_loc, dir_check)
+ if (dir_check .neqv. .true.) then
+ call s_create_directory(trim(file_loc))
+ end if
+ call s_create_directory(trim(file_loc))
+ end if
+ call s_mpi_barrier()
+ call DelayFileAccess (proc_rank)
+ ! Initialize MPI data I/O
+ call s_initialize_mpi_data(q_cons_vf)
+
+ ! Open the file to write all flow variables
+ write (file_loc, '(I0,A,i7.7,A)') t_step_start, '_', proc_rank, '.dat'
+ file_loc = trim(restart_dir)//'/lustre_0'//trim(mpiiofs)//trim(file_loc)
+ inquire (FILE=trim(file_loc), EXIST=file_exist)
+ if (file_exist .and. proc_rank == 0) then
+ call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
+ end if
+ if (file_exist) call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
+ call MPI_FILE_OPEN(MPI_COMM_SELF, file_loc, ior(MPI_MODE_WRONLY, MPI_MODE_CREATE), &
+ mpi_info_int, ifile, ierr)
+
+ ! Size of local arrays
+ data_size = (m + 1)*(n + 1)*(p + 1)
+
+ ! Resize some integers so MPI can write even the biggest files
+ m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
+ n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
+ p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
+ WP_MOK = int(8d0, MPI_OFFSET_KIND)
+ MOK = int(1d0, MPI_OFFSET_KIND)
+ str_MOK = int(name_len, MPI_OFFSET_KIND)
+ NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
+
+ ! Write the data for each variable
+ if (bubbles) then
+ do i = 1, sys_size! adv_idx%end
var_MOK = int(i, MPI_OFFSET_KIND)
- ! Initial displacement to skip at beginning of file
- disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ !Additional variables pb and mv for non-polytropic qbmm
+ if(qbmm .and. .not. polytropic) then
+ do i = sys_size + 1, sys_size + 2*nb*nnode
+ var_MOK = int(i, MPI_OFFSET_KIND)
+
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+ else
+ do i = 1, sys_size !TODO: check if this is right
+ ! do i = 1, adv_idx%end
+ var_MOK = int(i, MPI_OFFSET_KIND)
- call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
MPI_DOUBLE_PRECISION, status, ierr)
end do
end if
+
+ call MPI_FILE_CLOSE(ifile, ierr)
+
else
- do i = 1, sys_size !TODO: check if this is right
-! do i = 1, adv_idx%end
- var_MOK = int(i, MPI_OFFSET_KIND)
+ ! Initialize MPI data I/O
+ call s_initialize_mpi_data(q_cons_vf)
+
+ ! Open the file to write all flow variables
+ write (file_loc, '(I0,A)') t_step_start, '.dat'
+ file_loc = trim(restart_dir)//trim(mpiiofs)//trim(file_loc)
+ inquire (FILE=trim(file_loc), EXIST=file_exist)
+ if (file_exist .and. proc_rank == 0) then
+ call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
+ end if
+ call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, ior(MPI_MODE_WRONLY, MPI_MODE_CREATE), &
+ mpi_info_int, ifile, ierr)
+
+ ! Size of local arrays
+ data_size = (m + 1)*(n + 1)*(p + 1)
+
+ ! Resize some integers so MPI can write even the biggest files
+ m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
+ n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
+ p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
+ WP_MOK = int(8d0, MPI_OFFSET_KIND)
+ MOK = int(1d0, MPI_OFFSET_KIND)
+ str_MOK = int(name_len, MPI_OFFSET_KIND)
+ NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
+
+ ! Write the data for each variable
+ if (bubbles) then
+ do i = 1, sys_size! adv_idx%end
+ var_MOK = int(i, MPI_OFFSET_KIND)
- ! Initial displacement to skip at beginning of file
- disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+ ! Initial displacement to skip at beginning of file
+ disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
- call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
- call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
- MPI_DOUBLE_PRECISION, status, ierr)
- end do
- end if
+ call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
+ 'native', mpi_info_int, ierr)
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ !Additional variables pb and mv for non-polytropic qbmm
+ if(qbmm .and. .not. polytropic) then
+ do i = sys_size + 1, sys_size + 2*nb*nnode
+ var_MOK = int(i, MPI_OFFSET_KIND)
+
+ ! Initial displacement to skip at beginning of file
+ disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+
+ call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
+ 'native', mpi_info_int, ierr)
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+ else
+ do i = 1, sys_size !TODO: check if this is right
+ ! do i = 1, adv_idx%end
+ var_MOK = int(i, MPI_OFFSET_KIND)
+
+ ! Initial displacement to skip at beginning of file
+ disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
- call MPI_FILE_CLOSE(ifile, ierr)
+ call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
+ 'native', mpi_info_int, ierr)
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+ call MPI_FILE_CLOSE(ifile, ierr)
+ endif
#endif
end subroutine s_write_parallel_data_files ! ---------------------------
diff --git a/src/pre_process/m_global_parameters.fpp b/src/pre_process/m_global_parameters.fpp
index 3958b4ffd..a022fe61c 100644
--- a/src/pre_process/m_global_parameters.fpp
+++ b/src/pre_process/m_global_parameters.fpp
@@ -95,6 +95,7 @@ module m_global_parameters
!! Boundary conditions in the x-, y- and z-coordinate directions
logical :: parallel_io !< Format of the data files
+ logical :: file_per_process !< type of data output
integer :: precision !< Precision of output files
logical :: vel_profile !< Set hypertangent streamwise velocity profile
@@ -249,6 +250,7 @@ contains
bc_z%beg = dflt_int; bc_z%end = dflt_int
parallel_io = .false.
+ file_per_process = .true.
precision = 2
vel_profile = .false.
instability_wave = .false.
diff --git a/src/pre_process/m_mpi_proxy.fpp b/src/pre_process/m_mpi_proxy.fpp
index 7e43a5242..2e8d431d1 100644
--- a/src/pre_process/m_mpi_proxy.fpp
+++ b/src/pre_process/m_mpi_proxy.fpp
@@ -55,7 +55,7 @@ contains
#:for VAR in [ 'old_grid','old_ic','stretch_x','stretch_y','stretch_z',&
& 'cyl_coord','adv_alphan','mpp_lim','hypoelasticity', &
& 'parallel_io', 'perturb_flow', 'vel_profile', 'instability_wave', 'perturb_sph', &
- 'bubbles', 'polytropic', 'polydisperse', 'qbmm' ]
+ 'bubbles', 'polytropic', 'polydisperse', 'qbmm', 'file_per_process' ]
call MPI_BCAST(${VAR}$, 1, MPI_LOGICAL, 0, MPI_COMM_WORLD, ierr)
#:endfor
call MPI_BCAST(fluid_rho(1), num_fluids_max, MPI_LOGICAL, 0, MPI_COMM_WORLD, ierr)
diff --git a/src/pre_process/m_start_up.fpp b/src/pre_process/m_start_up.fpp
index 2633ec626..abc7f0f54 100644
--- a/src/pre_process/m_start_up.fpp
+++ b/src/pre_process/m_start_up.fpp
@@ -105,6 +105,8 @@ contains
integer :: iostatus
!! Integer to check iostat of file read
+ character(len=1000) :: line
+
! Namelist for all of the parameters to be inputed by the user
namelist /user_inputs/ case_dir, old_grid, old_ic, &
t_step_old, t_step_start, m, n, p, x_domain, y_domain, z_domain, &
@@ -121,7 +123,8 @@ contains
rhoref, pref, bubbles, R0ref, nb, &
polytropic, thermal, Ca, Web, Re_inv, &
polydisperse, poly_sigma, qbmm, &
- sigR, sigV, dist_type, rhoRV, R0_type
+ sigR, sigV, dist_type, rhoRV, R0_type, &
+ file_per_process
! Inquiring the status of the pre_process.inp file
file_loc = 'pre_process.inp'
@@ -134,6 +137,9 @@ contains
STATUS='old', ACTION='read')
read (1, NML=user_inputs, iostat=iostatus)
if (iostatus /= 0) then
+ backspace(1)
+ read(1,fmt='(A)') line
+ print*, 'Invalid line in namelist: '//trim(line)
call s_mpi_abort('Invalid line in pre_process.inp. It is '// &
'likely due to a datatype mismatch. Exiting ...')
end if
diff --git a/src/simulation/m_data_output.fpp b/src/simulation/m_data_output.fpp
index 6229daacf..11be64a1f 100644
--- a/src/simulation/m_data_output.fpp
+++ b/src/simulation/m_data_output.fpp
@@ -26,6 +26,8 @@ module m_data_output
use m_compile_specific
use m_helper
+
+ use m_delay_file_access
! ==========================================================================
implicit none
@@ -813,78 +815,149 @@ contains
integer(KIND=MPI_OFFSET_KIND) :: MOK
character(LEN=path_len + 2*name_len) :: file_loc
- logical :: file_exist
+ logical :: file_exist, dir_check
+ character(len = 10) :: t_step_string
integer :: i !< Generic loop iterator
- ! Initialize MPI data I/O
+ if (file_per_process) then
- call s_initialize_mpi_data(q_cons_vf)
+ call s_int_to_str(t_step, t_step_string)
- ! Open the file to write all flow variables
- write (file_loc, '(I0,A)') t_step, '.dat'
- file_loc = trim(case_dir)//'/restart_data'//trim(mpiiofs)//trim(file_loc)
- inquire (FILE=trim(file_loc), EXIST=file_exist)
- if (file_exist .and. proc_rank == 0) then
- call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
- end if
- call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, ior(MPI_MODE_WRONLY, MPI_MODE_CREATE), &
- mpi_info_int, ifile, ierr)
-
- ! Size of local arrays
- data_size = (m + 1)*(n + 1)*(p + 1)
-
- ! Resize some integers so MPI can write even the biggest files
- m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
- n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
- p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
- WP_MOK = int(8d0, MPI_OFFSET_KIND)
- MOK = int(1d0, MPI_OFFSET_KIND)
- str_MOK = int(name_len, MPI_OFFSET_KIND)
- NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
-
- if (bubbles) then
- ! Write the data for each variable
- do i = 1, sys_size
- var_MOK = int(i, MPI_OFFSET_KIND)
+ if (proc_rank == 0) then
+ file_loc = trim(case_dir)//'/restart_data/lustre_'//trim(t_step_string)
+ call my_inquire(file_loc, dir_check)
+ if (dir_check .neqv. .true.) then
+ call s_create_directory(trim(file_loc))
+ end if
+ call s_create_directory(trim(file_loc))
+ end if
+ call s_mpi_barrier()
+ call DelayFileAccess (proc_rank)
- ! Initial displacement to skip at beginning of file
- disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+ ! Initialize MPI data I/O
- call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
- call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
- MPI_DOUBLE_PRECISION, status, ierr)
- end do
- !Write pb and mv for non-polytropic qbmm
- if(qbmm .and. .not. polytropic) then
- do i = sys_size + 1, sys_size + 2*nb*nnode
+ call s_initialize_mpi_data(q_cons_vf)
+
+ ! Open the file to write all flow variables
+ write (file_loc, '(I0,A,i7.7,A)') t_step, '_', proc_rank, '.dat'
+ file_loc = trim(case_dir)//'/restart_data/lustre_'//trim(t_step_string)//trim(mpiiofs)//trim(file_loc)
+ inquire (FILE=trim(file_loc), EXIST=file_exist)
+ if (file_exist .and. proc_rank == 0) then
+ call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
+ end if
+ call MPI_FILE_OPEN(MPI_COMM_SELF, file_loc, ior(MPI_MODE_WRONLY, MPI_MODE_CREATE), &
+ mpi_info_int, ifile, ierr)
+
+ ! Size of local arrays
+ data_size = (m + 1)*(n + 1)*(p + 1)
+
+ ! Resize some integers so MPI can write even the biggest files
+ m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
+ n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
+ p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
+ WP_MOK = int(8d0, MPI_OFFSET_KIND)
+ MOK = int(1d0, MPI_OFFSET_KIND)
+ str_MOK = int(name_len, MPI_OFFSET_KIND)
+ NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
+
+ if (bubbles) then
+ ! Write the data for each variable
+ do i = 1, sys_size
+ var_MOK = int(i, MPI_OFFSET_KIND)
+
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ !Write pb and mv for non-polytropic qbmm
+ if(qbmm .and. .not. polytropic) then
+ do i = sys_size + 1, sys_size + 2*nb*nnode
+ var_MOK = int(i, MPI_OFFSET_KIND)
+
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+ else
+ do i = 1, sys_size !TODO: check if correct (sys_size
+ var_MOK = int(i, MPI_OFFSET_KIND)
+
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+
+ call MPI_FILE_CLOSE(ifile, ierr)
+ else
+ ! Initialize MPI data I/O
+
+ call s_initialize_mpi_data(q_cons_vf)
+
+ ! Open the file to write all flow variables
+ write (file_loc, '(I0,A)') t_step, '.dat'
+ file_loc = trim(case_dir)//'/restart_data'//trim(mpiiofs)//trim(file_loc)
+ inquire (FILE=trim(file_loc), EXIST=file_exist)
+ if (file_exist .and. proc_rank == 0) then
+ call MPI_FILE_DELETE(file_loc, mpi_info_int, ierr)
+ end if
+ call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, ior(MPI_MODE_WRONLY, MPI_MODE_CREATE), &
+ mpi_info_int, ifile, ierr)
+
+ ! Size of local arrays
+ data_size = (m + 1)*(n + 1)*(p + 1)
+
+ ! Resize some integers so MPI can write even the biggest files
+ m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
+ n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
+ p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
+ WP_MOK = int(8d0, MPI_OFFSET_KIND)
+ MOK = int(1d0, MPI_OFFSET_KIND)
+ str_MOK = int(name_len, MPI_OFFSET_KIND)
+ NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
+
+ if (bubbles) then
+ ! Write the data for each variable
+ do i = 1, sys_size
var_MOK = int(i, MPI_OFFSET_KIND)
! Initial displacement to skip at beginning of file
disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
+ 'native', mpi_info_int, ierr)
call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
MPI_DOUBLE_PRECISION, status, ierr)
end do
- end if
- else
- do i = 1, sys_size !TODO: check if correct (sys_size
- var_MOK = int(i, MPI_OFFSET_KIND)
+ !Write pb and mv for non-polytropic qbmm
+ if(qbmm .and. .not. polytropic) then
+ do i = sys_size + 1, sys_size + 2*nb*nnode
+ var_MOK = int(i, MPI_OFFSET_KIND)
+
+ ! Initial displacement to skip at beginning of file
+ disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+
+ call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
+ 'native', mpi_info_int, ierr)
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+ else
+ do i = 1, sys_size !TODO: check if correct (sys_size
+ var_MOK = int(i, MPI_OFFSET_KIND)
- ! Initial displacement to skip at beginning of file
- disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+ ! Initial displacement to skip at beginning of file
+ disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
- call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
- call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
- MPI_DOUBLE_PRECISION, status, ierr)
- end do
- end if
+ call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
+ 'native', mpi_info_int, ierr)
+ call MPI_FILE_WRITE_ALL(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
- call MPI_FILE_CLOSE(ifile, ierr)
+ call MPI_FILE_CLOSE(ifile, ierr)
+ end if
#endif
diff --git a/src/simulation/m_global_parameters.fpp b/src/simulation/m_global_parameters.fpp
index a49b78bd2..590782e51 100644
--- a/src/simulation/m_global_parameters.fpp
+++ b/src/simulation/m_global_parameters.fpp
@@ -134,6 +134,7 @@ module m_global_parameters
!> @}
logical :: parallel_io !< Format of the data files
+ logical :: file_per_process !< shared file or not when using parallel io
integer :: precision !< Precision of output files
integer, allocatable, dimension(:) :: proc_coords !<
@@ -373,6 +374,7 @@ contains
null_weights = .false.
mixture_err = .false.
parallel_io = .false.
+ file_per_process = .true.
precision = 2
hypoelasticity = .false.
weno_flat = .true.
diff --git a/src/simulation/m_mpi_proxy.fpp b/src/simulation/m_mpi_proxy.fpp
index bfb163cb3..73ece6f0a 100644
--- a/src/simulation/m_mpi_proxy.fpp
+++ b/src/simulation/m_mpi_proxy.fpp
@@ -136,7 +136,7 @@ contains
& 'weno_Re_flux', 'alt_soundspeed', 'null_weights', 'mixture_err', &
& 'parallel_io', 'hypoelasticity', 'bubbles', 'polytropic', &
& 'polydisperse', 'qbmm', 'monopole', 'probe_wrt', 'integral_wrt', &
- & 'prim_vars_wrt', 'weno_avg']
+ & 'prim_vars_wrt', 'weno_avg', 'file_per_process']
call MPI_BCAST(${VAR}$, 1, MPI_LOGICAL, 0, MPI_COMM_WORLD, ierr)
#:endfor
diff --git a/src/simulation/m_start_up.fpp b/src/simulation/m_start_up.fpp
index ca1f29208..9d362ac1a 100644
--- a/src/simulation/m_start_up.fpp
+++ b/src/simulation/m_start_up.fpp
@@ -117,6 +117,8 @@ contains
integer :: iostatus
!! Integer to check iostat of file read
+ character(len=1000) :: line
+
! Namelist of the global parameters which may be specified by user
namelist /user_inputs/ case_dir, run_time_info, m, n, p, dt, &
t_step_start, t_step_stop, t_step_save, &
@@ -141,7 +143,7 @@ contains
polytropic, thermal, &
integral, integral_wrt, num_integrals, &
polydisperse, poly_sigma, qbmm, &
- R0_type
+ R0_type, file_per_process
! Checking that an input file has been provided by the user. If it
! has, then the input file is read in, otherwise, simulation exits.
@@ -155,8 +157,11 @@ contains
read (1, NML=user_inputs, iostat=iostatus)
if (iostatus /= 0) then
- call s_mpi_abort('Invalid line in simulation.inp. It is '// &
- 'likely due to a datatype mismatch. Exiting ...')
+ backspace(1)
+ read(1,fmt='(A)') line
+ print*, 'Invalid line in namelist: '//trim(line)
+ call s_mpi_abort('Invalid line in pre_process.inp. It is '// &
+ 'likely due to a datatype mismatch. Exiting ...')
end if
close (1)
@@ -392,6 +397,8 @@ contains
character(LEN=path_len + 2*name_len) :: file_loc
logical :: file_exist
+ character(len = 10) :: t_step_start_string
+
integer :: i
allocate (x_cb_glb(-1:m_glb))
@@ -463,76 +470,136 @@ contains
end if
end if
- ! Open the file to read conservative variables
- write (file_loc, '(I0,A)') t_step_start, '.dat'
- file_loc = trim(case_dir)//'/restart_data'//trim(mpiiofs)//trim(file_loc)
- inquire (FILE=trim(file_loc), EXIST=file_exist)
+ if (file_per_process) then
+ call s_int_to_str(t_step_start, t_step_start_string)
+ ! Open the file to read conservative variables
+ write (file_loc, '(I0,A1,I7.7,A)') t_step_start, '_', proc_rank, '.dat'
+ file_loc = trim(case_dir)//'/restart_data/lustre_'//trim(t_step_start_string)//trim(mpiiofs)//trim(file_loc)
+ inquire (FILE=trim(file_loc), EXIST=file_exist)
- if (file_exist) then
- call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, MPI_MODE_RDONLY, mpi_info_int, ifile, ierr)
+ if (file_exist) then
+ call MPI_FILE_OPEN(MPI_COMM_SELF, file_loc, MPI_MODE_RDONLY, mpi_info_int, ifile, ierr)
- ! Initialize MPI data I/O
+ ! Initialize MPI data I/O
+ call s_initialize_mpi_data(q_cons_vf)
- call s_initialize_mpi_data(q_cons_vf)
+ ! Size of local arrays
+ data_size = (m + 1)*(n + 1)*(p + 1)
- ! Size of local arrays
- data_size = (m + 1)*(n + 1)*(p + 1)
+ ! Resize some integers so MPI can read even the biggest file
+ m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
+ n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
+ p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
+ WP_MOK = int(8d0, MPI_OFFSET_KIND)
+ MOK = int(1d0, MPI_OFFSET_KIND)
+ str_MOK = int(name_len, MPI_OFFSET_KIND)
+ NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
- ! Resize some integers so MPI can read even the biggest file
- m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
- n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
- p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
- WP_MOK = int(8d0, MPI_OFFSET_KIND)
- MOK = int(1d0, MPI_OFFSET_KIND)
- str_MOK = int(name_len, MPI_OFFSET_KIND)
- NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
+ ! Read the data for each variable
+ if (bubbles .or. hypoelasticity) then
- ! Read the data for each variable
- if (bubbles .or. hypoelasticity) then
+ do i = 1, sys_size!adv_idx%end
+ var_MOK = int(i, MPI_OFFSET_KIND)
- do i = 1, sys_size!adv_idx%end
- var_MOK = int(i, MPI_OFFSET_KIND)
- ! Initial displacement to skip at beginning of file
- disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+ call MPI_FILE_READ(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ !Read pb and mv for non-polytropic qbmm
+ if(qbmm .and. .not. polytropic) then
+ do i = sys_size + 1, sys_size + 2*nb*nnode
+ var_MOK = int(i, MPI_OFFSET_KIND)
- call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
- call MPI_FILE_READ(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
- MPI_DOUBLE_PRECISION, status, ierr)
- end do
- !Read pb and mv for non-polytropic qbmm
- if(qbmm .and. .not. polytropic) then
- do i = sys_size + 1, sys_size + 2*nb*nnode
+ call MPI_FILE_READ(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+ else
+ do i = 1, adv_idx%end
+ var_MOK = int(i, MPI_OFFSET_KIND)
+
+ call MPI_FILE_READ(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+
+ call s_mpi_barrier()
+
+ call MPI_FILE_CLOSE(ifile, ierr)
+ else
+ call s_mpi_abort('File '//trim(file_loc)//' is missing. Exiting...')
+ end if
+ else
+ ! Open the file to read conservative variables
+ write (file_loc, '(I0,A)') t_step_start, '.dat'
+ file_loc = trim(case_dir)//'/restart_data'//trim(mpiiofs)//trim(file_loc)
+ inquire (FILE=trim(file_loc), EXIST=file_exist)
+
+ if (file_exist) then
+ call MPI_FILE_OPEN(MPI_COMM_WORLD, file_loc, MPI_MODE_RDONLY, mpi_info_int, ifile, ierr)
+
+ ! Initialize MPI data I/O
+
+ call s_initialize_mpi_data(q_cons_vf)
+
+ ! Size of local arrays
+ data_size = (m + 1)*(n + 1)*(p + 1)
+
+ ! Resize some integers so MPI can read even the biggest file
+ m_MOK = int(m_glb + 1, MPI_OFFSET_KIND)
+ n_MOK = int(n_glb + 1, MPI_OFFSET_KIND)
+ p_MOK = int(p_glb + 1, MPI_OFFSET_KIND)
+ WP_MOK = int(8d0, MPI_OFFSET_KIND)
+ MOK = int(1d0, MPI_OFFSET_KIND)
+ str_MOK = int(name_len, MPI_OFFSET_KIND)
+ NVARS_MOK = int(sys_size, MPI_OFFSET_KIND)
+
+ ! Read the data for each variable
+ if (bubbles .or. hypoelasticity) then
+
+ do i = 1, sys_size!adv_idx%end
var_MOK = int(i, MPI_OFFSET_KIND)
! Initial displacement to skip at beginning of file
disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
+ 'native', mpi_info_int, ierr)
call MPI_FILE_READ(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
- MPI_DOUBLE_PRECISION, status, ierr)
+ MPI_DOUBLE_PRECISION, status, ierr)
end do
- end if
- else
- do i = 1, adv_idx%end
- var_MOK = int(i, MPI_OFFSET_KIND)
+ !Read pb and mv for non-polytropic qbmm
+ if(qbmm .and. .not. polytropic) then
+ do i = sys_size + 1, sys_size + 2*nb*nnode
+ var_MOK = int(i, MPI_OFFSET_KIND)
+ ! Initial displacement to skip at beginning of file
+ disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+
+ call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
+ 'native', mpi_info_int, ierr)
+ call MPI_FILE_READ(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
+ else
+ do i = 1, adv_idx%end
+ var_MOK = int(i, MPI_OFFSET_KIND)
- ! Initial displacement to skip at beginning of file
- disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
+ ! Initial displacement to skip at beginning of file
+ disp = m_MOK*max(MOK, n_MOK)*max(MOK, p_MOK)*WP_MOK*(var_MOK - 1)
- call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
- 'native', mpi_info_int, ierr)
- call MPI_FILE_READ(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
- MPI_DOUBLE_PRECISION, status, ierr)
- end do
- end if
+ call MPI_FILE_SET_VIEW(ifile, disp, MPI_DOUBLE_PRECISION, MPI_IO_DATA%view(i), &
+ 'native', mpi_info_int, ierr)
+ call MPI_FILE_READ(ifile, MPI_IO_DATA%var(i)%sf, data_size, &
+ MPI_DOUBLE_PRECISION, status, ierr)
+ end do
+ end if
- call s_mpi_barrier()
+ call s_mpi_barrier()
- call MPI_FILE_CLOSE(ifile, ierr)
- else
- call s_mpi_abort('File '//trim(file_loc)//' is missing. Exiting...')
+ call MPI_FILE_CLOSE(ifile, ierr)
+ else
+ call s_mpi_abort('File '//trim(file_loc)//' is missing. Exiting...')
+ end if
end if
deallocate (x_cb_glb, y_cb_glb, z_cb_glb)
diff --git a/toolchain/mfc/run/case_dicts.py b/toolchain/mfc/run/case_dicts.py
index 1a753d1b9..4299c67a8 100644
--- a/toolchain/mfc/run/case_dicts.py
+++ b/toolchain/mfc/run/case_dicts.py
@@ -7,7 +7,7 @@
"Web", "poly_sigma", "case_dir", "thermal", "polytropic",
"m", "mpp_lim", "R0ref", "adv_alphan", "num_fluids", "model_eqns",
"nb", "weno_order", "rhoref", "bubbles", "Re_inv", "n", "precision",
- "Ca", "polydisperse"
+ "Ca", "polydisperse", "file_per_process"
]
From b0002b3942dacfc92d2b60cf50f46e152e46be1b Mon Sep 17 00:00:00 2001
From: Ben Wilfong <48168887+wilfonba@users.noreply.github.com>
Date: Wed, 13 Dec 2023 13:19:33 -0500
Subject: [PATCH 2/7] Additional documentation
---
docs/documentation/case.md | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/docs/documentation/case.md b/docs/documentation/case.md
index fd97d3b43..d5c03c7fb 100644
--- a/docs/documentation/case.md
+++ b/docs/documentation/case.md
@@ -344,6 +344,7 @@ Note that `time_stepper` $=$ 3 specifies the total variation diminishing (TVD),
| `format` | Integer | Output format. [1]: Silo-HDF5; [2] Binary |
| `precision` | Integer | [1] Single; [2] Double |
| `parallel_io` | Logical | Parallel I/O |
+| `file_per_process` | Logical | Whether or not to write one IO file per process |
| `cons_vars_wrt` | Logical | Write conservative variables |
| `prim_vars_wrt` | Logical | Write primitive variables |
| `alpha_rho_wrt(i)` | Logical | Add the partial density of the fluid $i$ to the database \|
@@ -377,7 +378,10 @@ The table lists formatted database output parameters. The parameters define vari
With parallel I/O, MFC inputs and outputs a single file throughout pre-process, simulation, and post-process, regardless of the number of processors used.
Parallel I/O enables the use of different number of processors in each of the processes (i.e. simulation data generated using 1000 processors can be post-processed using a single processor).
-- `cons_vars_wrt` and `prim_vars_wrt} activate output of conservative and primitive state variables into the database, respectively.
+- `file_per_process` deactivates shared file MPI-IO and activates file per process MPI-IO. The default behaviour is to use a shared file.
+ File per process is usefull when running on 10's of thousands of ranks.
+
+- `cons_vars_wrt` and `prim_vars_wrt` activate output of conservative and primitive state variables into the database, respectively.
- `[variable's name]_wrt` activates output of the each specified variable into the database.
From 9dba3bfdb19b2c4f00cc97200b3e953863f533b5 Mon Sep 17 00:00:00 2001
From: Ben Wilfong <48168887+wilfonba@users.noreply.github.com>
Date: Wed, 13 Dec 2023 13:41:15 -0500
Subject: [PATCH 3/7] add example case
---
examples/2D_riemann_test/README.md | 11 +++++++++++
examples/2D_riemann_test/alpha_rho1_final.png | Bin 0 -> 140823 bytes
.../2D_riemann_test/alpha_rho1_initial.png | Bin 0 -> 7163 bytes
3 files changed, 11 insertions(+)
create mode 100644 examples/2D_riemann_test/README.md
create mode 100644 examples/2D_riemann_test/alpha_rho1_final.png
create mode 100644 examples/2D_riemann_test/alpha_rho1_initial.png
diff --git a/examples/2D_riemann_test/README.md b/examples/2D_riemann_test/README.md
new file mode 100644
index 000000000..4e644c988
--- /dev/null
+++ b/examples/2D_riemann_test/README.md
@@ -0,0 +1,11 @@
+# 2D Riemann Test (2D)
+
+Reference: Chamarthi, A., & Hoffmann, N., & Nishikawa, H., & Frankel S. (2023). Implicit gradients based conservative numerical scheme for compressible flows. arXiv:2110.05461
+
+## Density Initial Condition
+
+![Density](alpha_rho1_initial.png)
+
+## Density Final Condition
+
+![Density Norms](alpha_rho1_final.png)
diff --git a/examples/2D_riemann_test/alpha_rho1_final.png b/examples/2D_riemann_test/alpha_rho1_final.png
new file mode 100644
index 0000000000000000000000000000000000000000..c2b0d71e78fc586f9e93da6a5c5e8046bf26f59a
GIT binary patch
literal 140823
zcmeEt_cz>c)a@WabP=NW5=8Hv5Tb`*lpuN?C3*|_B1RXTQKI+W+YmL%5WS2NozbFq
z?o8hM{u6iIS<5f82G5-5oW1usXMe)qYbfF4P~rdp0DR?l3fcg`lPKhmBsMzooxq3q
zXaIm7psXOL<889PG+ep&E17#MP$6!ry}W^+vuwyiLWJBY!-n@ykxNhPTGq-ijR?L7
z-kcM;Xi%(iqt>SQ_S9&Hz^v6M`*-4==pXrUue5(gzEZi7aV(cgz|l%nP>#A1`!BbY
zo)PuRwc_2TBqBz=#{K7%nf|?LNaQ&I{`Vpa$rSvb&pkC`i~jePt=#|r7%Fi8Zv~{*
z4WD*4@KNR=+qAQ4ma2(;snFeOb7%-S3LKT#&Yb;w)G|#ZRX;Kmc)lC>H16KHv*PjW
zR_5{O5d**nsJ_{BUK$uc{(%nPM;FLMN`a(U!aUF84XNz4iQM@;A=NqbW~mHVv$gB|
znb;s;6s^27sr2Spvp}2>z_?}5n>x)y0Z70NI3SpiU;;#T}0_WZKF8|YsL@c|ybzcH(y
z0>DX2ovSmyYrimFKg{G|9@7Nh)4)S7KwRra>q=ri1Bqb{h~=QNzodZFo|P`|)$%|I
zK0PnoD#ieZury0L@TEWHkK1#Z`;&+{HjMADS5^!kTqpw_Xeh6_C#Cp&tWUdNw7}fj
zIQH$6q-3nd#;%7|A8xe$AMSRY9}t~)M-OnfGN1QMP}ifS*`vM3&6WEww+e9auxYBy
zH<^c{$Lm1fN3X|+(@vkIrL%jwN7E+Py(7qpLx5$vRNB4|)lnIGb*K&<5$-uJC)y|e
z`Q=K$h{__ovLlt6?*sU@*a$t&F>oLNLhWQMLk+0wCLYwCZIi$uI5K(Mb~0Pqav{Y6
zQHIH}>3Pp>6{9WDLHp|UZ>y?o9l?ID3y!TehjE-M@E;BWPfeSaFaFLcJ2WgeyQzbB
zqEz^8+|Wv6wL8AysY?O8w>xBLBd2@Z#i?nzbRk
z>27=X=gNAUAf>vCqq2g6!oU#S0Xw{BPwd6TJ0vbqj+Gq8qy2@PG|O+k(D0&2wq(@v
zWSa^ZHELE}au%1Ysn(d*$nu}N$ZqS?8v6|lgG{%Fk)qY>)EA+x>RArt9qsP^9PybN
zaoY4bR}cFZE>L!MXRk55Sjx0i5FcJ*sG_UuwUB%zi|e|wBH$i5B;q+?$fxX}tGAy|
z9KBip5Pu9Q-PGwn=x$~sYxs|G^!G)RlFb{%3c|;_n%cs=yfP9wN-O!S7^A+=Ygl;>Gb}hTnkOwBsg`48+yJ!(KI(r!cdsqdYP()>~>Nk>Oq13YvSp_;g4EOdB2MT?459
z-1gOy4?97;U)LUiMpy$sr6L8~4M>k`hmy~mLLJ*&9=%FFJ1w$1%Ihl&a3*}DAHY~<
z5OLw^WP*(!H~N>iDZI6!)wo!9Y!*7w4
zoXcFfu^Uq%+Bz4ZOgZk2Q^Jh#V>E4X2KW8~-8PJg!K16-)+Aj|%OE}LT^BRSC%-g)
z*(d#gAimpPM@_`f{okw~ZEpWC{1)c{Z~S*5%erXz2-18E@Boqg&cqwKQFMXbuzUlG
z{IsmtHMk>)2^6_K)bes{gy5r+Z(?VqQ5bpE3Qgfi
zmD2jUh)nk4HS3BA2F&l=q~oS%NYlffpJV|{EEScdvsacK8d9MVog2YF_%v;bg#=3b
zRj()xEddeBpm91PC`Hdua^?mbl7e&%MMD8gtg39~V^>>Qax}(!jLZ1!O_`#7zB^*k>Il1(yXY>Q`uv
z34-$`3@|!2d&cL57<_48od`d!kz(&(M5#CuI`j^G`TTt;TKAr)E4)O>93i;)q7ZXe
z`VB&Q?f`nepB8OFFv=?Pi%P)QZ;kysD6`Ve&$lP58_;1=vsI`1*anh1j^A2&DKyBf
z^m8NIiqY`32K5_-I&AiI0Je}Fj#NgG*2UvYjJ3X$mnEWrIps0hzhA!&&2xE(W)Z2!h
zX}m39hmi>eADWVb5Wd|wwjC#e`|ulEP#QT_r{C`AWb0!Li=zH|0kbumeD&Fs!^p~I
zzF0$lUZ#vslFq?~7Z0&9dIIXorsKZLMLm&DOz`RLC={1ZxTlC3P{KG?_w}!2a)G+M
zA=v_ElqM)5?^tjyGp3q&+&m=ad&8QlO=R3lZwIToi-!(riSc&wr%^)Yy}GnPH~r1c
zU1Ee?`jh=b*FKZgpBo~~Pgm!L;Uc$)Mz}9Ly
z9>NF;Q@`Z3jSs18>2RqARhfY_b=sqmYT!!omIMD_q-o%42Gt{DuIeXbZKUXG0vOHt
z^Gv48z_LHM?bmgpWUD(rr_XMUFlfa$K3@Kidwnc>xT7KYfE3iZ4sBIh5{!nl+tJ{3
zHAkoEvYLKrgI7~kULZ$?_|RPnb#ROSZiD2npS>zO-Pa>!rTSusg7B}t_yV%NOo+Yt
zQ+Z`bfOMwZ?v{IqN9%rtm5aD!97uU}w9t}Gx%o@il&?B8(5{2A)~=@v*N!Y{sn>cX
z+4~6e<%fP5nV`(BlE~BDm3Qp4*H78fKQ1^k5s$x@evv?7!M~mvHnTb%PVzJ_FElSg
z2=E;15tc3}Hrk6Saiu#anpV1IyWz%BtnL{1rPSrsI
zKRf8cn3m`G;842!RnJ7D0xaBo0SS1jj`f>zBTzYjc1>@cJmn)sIA;!
zXmfOj!}Hd^N^?Fy^g8kO3u*pGw&)}~g@k|kQdDYinE8#Cvisv)!k&u$MRGgjIK_fkV%@S
zQ0;_p>?wy#Ye%5Dn+1Q3$1k$aIP(QZ^n#!|Z$Q%?**Zo+{XbwX8q0fIc>U&lWc+}4Q1d=*d;f4k;F
zM{JyYivI56#uCTFnIJ-4?|R5)tiS4#1Z-I~<8!ophY$+u-q`w7NCfr`$ug9>H7{tx
zWX1Sl)>8H&2U6rgUDUF_5K_XV?o>^))4;>}qUC&A>W#l($-;R2Rz+|@x&7A9eLf1E
zFsP4VQ-T@L2z|y&?ELfjuh0@huLoz!_3PcLiRqP(x$r*bXz&)1_0z#@H|)E9DhI$j
z?zUdF5$P=)HtNGzat&HB>QTb^#JOvV8F^IK+e%G<@qFB>1P9RIb8bRr%3qwkvb3cM
z*{>tU_yG2`%r4*Xh&H%3X_<&5J;yFmh#+lp1=J>?eZuoEs3zj1^r%_egIvR)gkCQA
zf^E(ubJM%24o%GYELdL7gT3h!7L^H2!oV+X@(;TLEUXB>6zIXOVJlM#UqM#KYvve}
za8Me)?1p!t*^nxV{|4)AFje`$jFQt%DJ-0CY
zJ$r@fbI$gaDDpVosPJJTKw74648KcFKTF}6uF`xoRBg<@I_|xr$OPss@5bz+04_OP
znG%_tyt2alO~Qwc7bgCCuyVr$cif90fr&VfQ%FVdeu^c
z<#9%|hodf7Y`>_lqph)pWId!p-YEDiXYDLm33Jhk!@|CQf^!n=NtSv^@UXEQVm(3&
z%u_!pKe~O&oQ{L!z4Ty#7IKWxQc6y+gzC89On>u^pN5
zTKVX}i0cB`wlyqDBh!;`qbaGi!C>moF&@<Ph3#Pj-~_thZy+}Ry
znStF!=Y>onUuLFn@4?{b%`S3?X`Ir-Fpe{L_HwO_gUJYD%&lp8z`G28Rq
zFAsS%+j8!GEE#M+9{S0TrSEv6fUpJJ^$y(E{vkoNIpoYB9QgJhVi2NIjm(FjZ`gEu
zQ>5vkL8qwCfi*3}hekfl;7TM*w72p}5Ko5z4VxV+oN&jp$Wq-Ea)s2aFQ*r;&;-Si9Vu^o0veXC^&jwJJa5E
z{wHcBpgHL;&EE;##bC1=2(pI=^)<(=ndB%MA&F}*BZ&1$qveMJvvoHy6?Zy0?s0R}
z{TqaG<}MW7r^Lc{q-9A`Gn9bHGClh(x+8}y31t5`DWDU0w<_N;mi3zdyIQ?A*R-E0
zND^QH=qm4h(RjB-gdfrLR8Q`*f}LrvgTJW`pF1Z_z};C9UT5OiUF|0>B1OJ}SDW6H
z<^SIj#e(+|Rihw#_Pi5ptS_j+cryV?gk_o|eNOtRQBjcLU!6KXJY_^kzCe)vw?7Xi
z<>TdadmoYPD=CYT5ZR)=atd{?^hQ73({bLuF6$ib!+ww)>%2OFp}A0Dbx9gIa!#ta
zzQ2mD`oP2l=7!9i%W@&71=f&HBH(2&z?T!(%f6$e5T7dZQ#jTD~bxe`5u_{6Yoa%X-I=nX-WXJd6=QMbhX)d5xz
z!of=KTr8SZfWZdieTR<@#|)g!uO8~sOVkQFj=ws(+OeM_Rvh5_c>0^Gqf^k)Lj0p`
z!zl?T%!bdXihk$Th5g{e*3*{cvr6ls5tf=X2@j0?So1}g(*7^UBiykNW<+F>#Pf0L
zZi?u5gImkRu&Ocdj|Q)Pyf6Avv71DQ!c(uPb#f%QO}v;H+Uxwa6t;4wcimw9$ap%6
z6elUm7>KD3F~D^SH5@!b`|T5qdS_!;}A6o9SPPD45RW2U*S}GB54diaK%bRxGBA>qVL6pTBz!Gb+Gx!lnW+?DL)si$w6#>?Gy-Fm#-dDoYq&nK)l-uZGNWJu6CKtMT?q}nWa<>&kzSI5O`
z;niZdo8UqRzrL7cQ^p|&&U%U4S1?HsCOe^^nH2$-0^B5h?Rj>3Nq+B#fb64CJk?*}
zhtE);^Bp{hh}2VMJ?v>|z_pQi^QrbNH8pBaV*FBx4XMvG-agSB3oW(gG=l0PWsK>_
zR>yzz!}x$(^AXQC-*3=u)6hQQtS{4OY+8eQreQ|wEFk$lS4dv+k{7jry)-LkMlUJW
z16$zX?(}Qb$j%!l&6NwmxoVw*2)eS{gohT^RfH!Nb$si;-Lhs6HA{H6
z_>d`zxqprmB{H}d_uNIjmcu)&
z)5=2+p+&(}B1G-}vFY0zRlXLTv0I0{c{b;4$MY?;tLQP43sb%G-q=i1+a))#{u=_S
zBQ^f?<=J{duZweKx~u
ztmQmCd8wycHzu5MgWXj@^WOC4H6AZqS89aXn(P^=Ev#m{Rk}jUMkv@@FyQWo_W-3L
z!CdyVzZ9FuR?_b84C0zJo`&7?|C&ILx|m1ni~FwpAy1_zm4+wDoWA;DkAFgC8FwiM
ztKZO6nUNp%RLP(c%_6G$mgr)HiN>jgmjS`8W+OkszL0ppn)$kw~IQy+HrcjF+(@wbGJM%gR1IL4zkZ&EG
z7-s=hY|nDxhpAAC;Jy{(9_h|Vj&Mt)O#O<&BV|Xk9#f|Sv}i)Ci#|J4S`kLA<0%N{
zjdagg$nQB@9gEe4)&x~azL=iX?m!HIOSZjr@&Hrz)Z?j(0GCmk3ctSq**>4T7am
zw{X`LmaN%OHE78(4*bopMx(Zdj;A&SHm_mHG*lT-!*scJzq5c3tjg2oJ;E0GH_sEf
zig@eIvi>jm(>e3kN!TAFGATKQMTlepy07Z@z4ZT4zl~_Otb!Z1fM_~niY{%km?%7)7|-n9slw*b
zNpGRuuoN(PlzPHFzy&w&I#ZIg)B4%BQJM9%J|K5;rQz@>#H7_L6^*X=Q#?qbws`4t
z69sT36MTaj9Sabj+n4LtNxXJ(psS27EG0^P^F}>gZ^)q#r5}6Ny3mPXW*;cJbnM-N
zr%g8>dYm8hTN@F4YFIfu|O-&yFbL4AQG`!I=+=}4oo!&e@^hy-HfHjL6D0^;I!dl8aa
zG){_=!`F9r7lcI5%+if1h(o#sOr88pDU)(b-uxUwnFV|Wsj2C6uTvSr>>Fz<uQP
z_?tzxW!lAsS_Vx70IVVa%YygMGDVE-QXh`#IR$EOo5Y?PQ2W-CzHGoJ%x)Kw0*2#b
zyYx5z4)PijpgFR=-%Znpe`~17nYV5-RfohkbU5|Q2p7$t)I-4Rg-efKM-Muj`<|a|
zR3C|=Mc`0(Es>hMiF=d;J1w7bEy9tg#vR&&j=W`E0B^Q*
z2?9wM%-Px84GX=Xb!MWxHbYAJdC*Dvd0B__f;
z{6d*QuykYxiMC7FY9z0+4xJFeu;a0Q%_4zl7&VF3R2k8LFSq4&Rn+{)9RTN1sv2Y%
zu#IFtd<_*{AZa~aEyIS4zdi#!ETs$XOl5o>MlwaD|&(_~)3{xShj
z1mV|>hK3{vLV@7+cG>gw?4i55Y2edOpIyT+>J7ldQS|BWnRPO!J#4kgiN*bne>;B=
zc-vxI^ZxRO_oaMByR+M^-{vRP>bM_2*rmKW;!G?~J19*Jjs6PF8gf<*|P5{*Zl=w1a@d@4u#dzSL{
zqAz)cgHN0AK4PvLkn?xHSNx6Dg4|O>CNq>W9JMbivM>9H^BkCU_}pjVmylq#^Nr}e
zZoSk>Lf;#UEY(wn^t>b2{6A&1V)E^!%>lmZv!S^`XGOnP-@t_{j{SZqf2i>M%jS!j
zu+OaOLL$MjBz|a$R2nW*Kl(WC3XnTNZ&Q%oe5K7t`GP?U?L6KoC6ZlCugDMDJ?k+J}&s=nS<<
zY7ePsFDyosoP2$Tk#MMvkUlt#P&_0R$hY4uGoC8?qE&d)PDF#cJs^GBj^~ylNz8N0
z+f$yuNgT0Hkh#C3RkN;%q={3pN2f0jj?2t1_2=7lTfX}0>hk5{STaT+%9?oklW1j+
z)6sZCOP~^+(s0T_Xe<^M`q`$z{F;saF|O?Dks!WKy%N;=WZrr
zWXgs1C|^nj@yB^6d=@;zl8QKeQ{RIc&sy~0(WQ~1(L;4~
z&sT{I=;0WI6*?X1S3$QXUw)ygbksa08@#n1nWD149oVpNr`Jk&q;e!oAbVlyU!YAc
zI<0-LxCH4bJuFIFe0R921uT@BuO^x^J)k^jP~LS_uae|qY2DSm@WitIQV6@`Jnn$o
zZQ0SRdDUJ2-d*1@RQ&!h~3iP}y>NagCXPM_lXUfm#%0d@!>?9qUFIoFaaKs5_q4$Q}
z_keH-mOifTrS?L*VRPHAX0YzR#FzH%gCe(x!m-KRy?mkd&0fNHrl;+<0&Sg{(Ut$9
z6v_Y?y*Qyhx^!~sIs&1~&xF|)nNQA$i39@kj|
zYsz>+!S7gS7KXe%5S(B%Bujti?WO9ElDDG7!RWF^?+Q(FmTdGfbZoS{X$3;0k3Z4t
zrMnRpF1n`HRSj&wwS*275!1LtdL43!({ywm+yMp{F@IAT}agxT8Q1
z3b>wtDHHnBt3BlSnKm|TO^ntV=w!r<-0RY=;TSEA36(S{_7u1
zeQy(gV&Gh^-up@<vGVVX4AKn$Hv#DgK_bX$`-y5(=Xp>p_
zWt4%}r_xY!PCwM{ErCD=Z#k7U^)sL&p(Inx%>X$lh@s^i`*K1lUkV<
z#QJrMDW~MKz@>5OJrgvX*aw?19f9h<4!Nj8pUGE`@u9^3R~zd+&tglVC+5B7D5{@W
zYL9tO%YvGGt($jdfww-`9lki~tZY~;m)=BpoQ@S#O_4FCb@f=rOIcN(AvgfjM!I90
z*q>5zrq}mqX@Y+`nbypd?^Aw^o)P(mkYF4AHvdqB^i32WfdtEJH8$9fv8Jl(KtOzz1
zhpo3c&F1=63qfZk2MiN*^*x)V!#7a=(^R)IarCi7hDYxpNtU~C_~N8mEJl8NySvsB
z8`JNN)FLf$6jMq#pnY%uy2CLVwO;C>BmB_|tl63$57H4In)-Ca|
znOztK$hhxU(TrEn-78JMIo^ZT8>qw2YCkSHI8a4&i9W-Z_as=B-O1}^u9&)i)EkAV
z9O+m-o?b9EJ$9gN2_lE~%fUK8y@Ov9wFp+~F_9#ODe1nrIhn`NTV|&>Fk3ygIMoty
zF$~Z#XZ{F)NgGw@2qR0e1S?408W2)^@B>k<4`f`AhvyT*@`=^^REV@Ug-$&ARhH(
z(Y}UTQ_aGDntioAUyQ}w75+EXpu9a&5X^2E2He?fsR#PpPp&*RKD0iZiBw?&YnMMe
zglZ*Vz<-ZaN=5|eS$F@@wgxme$UiPrG)9y+QZ_y-aAx)uR(!kwVOH6kq;S3)n@l
z`dn3)?qg`AH$zS7ynJa1@va?^AY%M!PrrG2Nay?-;I;wlhkkD>vRw)wC0$eFasQ`s8+Uy*lWJe?^J=YjzK
zYd2QLX+j52`!)4z}Jd|0aU
zg_%?gTHYTrxEv*MMfnEvKBm6uNM6ZcXU%~X|5|B
zMz{9HB~@*feLNH|%>Mh*bU{RpF{sc!PFREk^yaJ9ys+K$=q5{vNV|{!9^7k#l@oiG
zsn0)iS(9u%R|n;?=&t0u?8qR}RF_6h;RHq2bLSWC?XseH;iMCr2qL)mlxdY$D8WP(^G2(Cx%>LfYj_t`LO*eTVu_uXL
z?ZFWZOx$!)@By&d^c?<-s!tYRYJa|^&dmz^F*>=n!@Bug*6eV=TNz@KqX#e5jxR7F
z6ja;6yrkssY!P(a!q=d{b}n-jhZJRkWF-je^BsrQf}|+06F6rL
z#s;*NcK+w-CW#rJDIFiD#!Q0kF2f*$V$lw>$4sPDA`SYXZ}oOdg^fau6{>x?+8uQV
zh?pIj^Tknm%zj8@k2gzYmzfx$6zJ)>3jM|y`rVtX#
z8O;lPtgrcZZ}%&?t%BEu*^jsIV%BQWzQW%bB0|unJdC9@_uvnP{bN$93IZsTgWK)(
zfQ+mHJ#tN&^l>3qz!dRjivyK>>992{fACIBF%F>4P)^8ibjsnuE%eCcXgSdPhhV6y
zRv1i@3aLL*(E+uyc<`uKc=xUL*^p_%)fYiw1MDz{jh|>h0Wib>p0t+UG*dO#>{wA%
z)+r4l*m}%xU?LGn?zK*6o?VR{Jgs*>ZFilF=+xNd*t(mV1fewWEd4n{;$T#2fO`7M
z)fK;Ou-|)Bu{K3Yc`>F#+S>th{wsj$7N48b>8)8hKxvf;-eO9Cs5Q`>e_cenQV{o1
zd>hbA7CUc;TczIKAM(jbZe6!M?^=A^&ytO;A_qk+HV@NbAavgr-7C
z_oha)6YpSk&-WfP)CSIah4{mf8ih8;rP`Iro+RHoq%ZB8oM)|?qN~1_YpLA758TkQ_E+A<&Cq&@s{gQmjpf$Rz8^(_X9l+wP
zE0D{5;y>^1d+7ZuzUSEliOYKsg`sEB9j)J0dH*!1>;|2K(u&)v=9<_jA}?Qgh&%ol
z_pFVPq|#oD)kj+-KzLz%umh%Px^kb)y;0~T&`Okb_zoGfHBQs};;AxUeBc|5PkQLI
z0x0QWVUe8)wtgZ0$>1KA7jY?50W!;aEPeH5Ncy23^N)1KV08JDAU?n!Lad-N*l|An
zv=?EQG-o3a8Z%kCq$I(}0W5kjYdfx}JG|i*3BiX}NRSdb%5WJ>t|9
zwQWLq>cQ92D0<1aBD7`q0tMC%MDMKM{-8zfxnTnY6R_$k%vMW=VvPhvbw2=qA5yf%C
z#UDqh?!KbJ+C$$m{jC)B^fMjeOF;tKLp}eQX_^%seEn8|G%yyl@4H$pTuC0dYBzlM
zS$NwMeN60B4k}vWiq&KxKb2KaNKu#mTq6r^P)P
z3G%Eop9qnVL-IM(^uYAa5!yBs{uF>D5_rEfeC-1!ePE3f7bF_%J#sB;nO)0^NgZF`
z>Quzr#pXmg2A^s_ORNbiF
z(z;I`0M_SgA;#6cnrH*b3~hAtq8?zOCA-~H5ES7=ujx}QGyw*FPg>!;-0G0cTH;t6AxLuvT749NH{Rgpu#^rJis$4K@Ok;Nih}1#uGU#~TjtWlc
zUZlvLrX6YEc2a
z;Rw2ZwPT?blcllp5){v$13miuyJM`W!mY{wt~~~H3zE!R&phB#~MZ!?34F*Ps
z8z=y79lc0x5$8L+9n!3SVo{C(DZGoJa9byf#?4Z&BK{=tlw}N7t#z1kE34R{aB
zI;h0>qk2@Pg@uM({1e|fv8F#oO^zV~6hWpB2ddWfV|j}Q2=$l+MR
z{(QPxFU||-q9**6B0;?1whIRzu1|VEWlxjwttcHXw+<{ROSGU#vZN)Gsi|EZ?wI^?
z`u-zXR!$$LGvW_D_xL!u|6Mk6fpJE(p2gqP*G~yE{CK|LmF?~j+V$A{?%T|nsNI}*
z{%85)71P;JY7Q|m*PBi!8e;Wt0WOT`Mgx~wyX3E}8_RaC&1
zHB|!oz(&N`dKj<@p@Osww6{^(%+AA0ibA8doE?)xglI;d`H)k101FFj9qcGAtYGnC
zA79@~OdPvUWbba=5IkZ990}34*lSeHUdnl;dr{Y&Ko7hMRi>SWGvA89@IZhjJ-`E~
z5RXfkRg=oiG`HZNhGDAK)WiGnH|cO2QH{c}9s4VMHFwZIbSPyE(*F>kb73$A_WN)S
z^-27c51n}2U1x8_*wnYJ_PuSvmkLTcQUxVqTrq1F
zlo-VFTR|2O*4~S&)(c4K6+5tMx=Bc9$?qxsV+IEH`22XY^Sf5bi_8}5d;O1Jw>b8l
zKm-h4V*sCt)ICVShBaH+xOttGEyiK|D?W0y@KO!Sr-S#`36}>1A`?LAmaT6MpbQ;}Gx-G!eiiNkOn_!U#|~^!Fmqn`>%sD=Qjwl~4Cq;73Ipv)bf-3YJ
zB-8Z=55%!_E@N)h-O7K~0#q9Ij*_$r1%cMC9PF45VZC{26~^^Z6`+Qm+|;sON?3rz
z!v5#2Ks{~bRh^2q)#BcZ^9;Y+T+Bg-Qd=9cPz2&rP1DdVG+@+eds~7
zap6;bNL}u%;;EyP{5j=?nN)&Kc>@c>OW0)k4W=m2l~G<54!1CqX}^hzu^9O)+z_D6
zI=?;8rV^t1@}E(cb#*|Hr#sNMij`#WZ9qU_^zB~^aSoJDzx*oYgaouOw7>KIkKRMe
zfwx589j$<-Beyb@#EMm!dd>v059}EK%odG8)(j-L>~XQ9(T=d8T-Qw^SYJBvd*iW2
zsUx;cUt5r_jjNB*ofo9ecoI4fgoiHq?rIEba~!UP(Z=QUjm{)_ET+F=Sw}R$*zir{
zFTJmW#?R2aSgb
zB72e)aJ${W<#=5*AyHI%U8GiiRf_(H6D-$o4A>t^?UvR0;s#Kw6fNhDj0C6a+SD`_
z7cu=(Q68Hp8(rwtT7DO>H=~&D5;Nq)USJ*>&rfVsRdXSFnA$?X79cTc6yu&GS#djq
z=3_XdF)=%`0uYEaMLd&vdfYb2`3>=@_F9_YLrY85{B1vyqATUqt@%mT_)UF_-+aQU
z8=mw`kU|Fp^8XY4YJwkS6{Zq4LXAn6*@K!)XRjTSr3_%x6`4qkbTfbY`?uzBHdkYV
z&FYGG%)no-)LXtMqQWFUvU2#Kt%k2nmia<0GIK(64*RdnGnnv)f15L%)}IldnRwU+
zc+BSXJy!y)XE1d5=cZ|71pJ^cFc`ABNe>+07Vnjo-H`yG?}Vjqew3<7qS!Z6}U&t2l9PwK__j3@xu2{PUL
z$$mU@TW?1(kTwK@y28eg16yTdXR@0}t*n_$NOXxN)ei~zw)ajmQYjX#F)ohZ%5v5B
zaxKPON%g#lb;>KOl)U3>7e00Ad`=N?OIqNC+6T0J+eCUNR_qXh^auzB
z%I>)p1e(VQvD@r{?rF!mjJX0jeXq#RON8b`zS%=_oTc`Ga?d@+hWT|Lgo{cP6O{wmof%NvYHr*;2^;^%RG9hIpL3X9N`N@Tl`izTS_@|Je@MbEOr)P@w`
z_*&)UhV#{9-%W!T-EzfrAU~@J(x9y9XqNMr%CtilP@95RluMrdJ8f_D2Z1$Kc=CQd
z(&$L~^+~{Fo%Q1EDkFuVpnytlqG0*;N9{wQoL;m)ht}boyT7U7v}r{Rc97IBmOAlS
zrCPkAnyRkv)5rp7Jp76Ko_3gF+!>AWl(Y$Kai#W#LZ5Jd^;sCXdH6*_tll%9EA0uK
z>z4gNi+s32+oQD26ph0B8zHit)G9&{L#@XeSaKa&F97JoQnbW?UtEq_%@cB3{zGp!
z2ePFBR}&7K#@uaJZ~2e+`a?^lJXO<^tYJS2x$ztZ7sZGA7b<<0Bz~!Q^2<|Qx%AvL
zDP5)?e{#B9EQ(lQ6?>j($zn@aCt?tbY||H|3LZELU;q&3$9LVHIW|%)jgnje;t$qT
zbjI$z9TI$Nvj|m?=SU2jLo3bdy?XgktFK=2+SW<^r!FsxArtkVT>C8w?y+AUjtPn8
zX_)71aOJKvb+1%FHTN7x_nfi{XIeWDHoF((cxq)uyz3I_)
z(f)9!kFM>7*lAJ~CrieSm(6Dk`a9gN6xtxz>&C%&2Wmg}l!(k?c?V`48Wyt(4|6Sc
z;EH%X0mfwAr}*)q5Uq*Eo!Y9rSr>LyK|
z<1L)qt{3c4RhngGZas^tRObaZUNYX!?Zy@+JuIn`nyT{+{R&1FhpINwVo&H9Dc>p}
zAF@AM<(P_>g1cSPGv?|+buL$@>o%fxwwA6^F^HGwb~UYx0QpEa3O|^z}m+!|CA&sL5qPl1mgq-(csY=B7Mk&vQA2
zIR{c4O2z^u*}-yu{0-gx;@xS`o6u2jq&d>sAl3GaM7Z@CQ!F+ZtQhwj_dh=`v#-V!
zZEKg$iM3>)Q&_t>#8Tik+DQ7`w>Xn~ku`wYY`mb8JpPtJ(^{g;Yc^A;1VC7XmBa%7
zJsPhf;3}?6^l4lLo@Wxd7Ax7%+#A)&RPTI=YH^Mjgwta3>w=Gaj^0km8L4S*FO4MD
zV)@H(+1}VxJ$*TnR-|rjnW@;`z)n(9kdI^IVB8;~u_PcxV6<((?q
z-<$I-hTjeL9^Yqu?2_+BO$;xgKQj&<@T3*#8PkK<5#oYCaicj$E0B}A6XMY-_SR2L
zAyMI&UP>@GES}f=v^c%4pLm=ZK?qEiKOPQz*u0-TpGEr7MXs(*ZIIL7#UwqoXI=Uj
zU6$H&)Io#DZ(H#M;aufth1Tr&=!y^Oe&@FH82Y*!L`@*HH@~J;W?c9pObbgc;X^$z
zg+;d(KaObpOnvOXbv#fU-}l-7L(^48#kDls0|fWr?jGEOhv4oO+}(m}fItZD?(XjH
z?!nz1f;+q+_j`X>%nXawb-HTT-c{8-8W&PacO+2z=KkkgqFN}NR)$+1+SGEEE%O`6
zwHJ^4KPfCrq)XO#fj7OG<7LyX$%$?+sUf|HT+`P>dh;)6gghvyH{?JhpBA;}ZjVL?
zfSn1dd%>P0tYV?Qt~4C2pL=7+6R2m0EJ2Yu8~31W44e}=8($@SLphq1FQ)^Nmj3dc
zrS@>>T#ZB6Z4R4ffzyB9r22lv_Q>7vvu`u;n#1v`C4O^&^x2EeT^ky;Ibs#5ou4kk
zIw0=jeQ(vQP?mPGzJ^AM4ssg`4Wq-%#?;*&^`&pzcP>qzyWy6g+U2w5(V6gX<(b9{
zy`e4@EiCkA?Mj;j-!1#Ljm@IrKXj9{W;GYUo>t}VLLcm0(#Vm!@p@kTI#^N;!vNO6
zK%J)>`zi=g(rm4}%9mK00nuOa;qPTii7LONy|RE}ulj}i^SA5tGOLTeFOhu4fM*df
zM}!C4XMR!W7>ixlus}geQ7JXFW$E?Z(=Ncb_eK^vYy-*A1V`ABZC2vLLf?={ZiRj4OL{`KlJ9Vk?qkted5@jyuK<
zJ0Jq})COF9f0c`UC@#kR%t2bnpUQY+)_DEx?dLn|Drb_gq&VsPs2#mWN6ldySG>oF
z!^_d({VU4iw6c6T;9#_EK0#(g=T2862#b^_y~&;vdgvmW=@<6VXIkV=(IhP|?YbT?
z5&LROc}DY5{e}4S**Cb#Q;Rt%+yc5ZbyDa!2O%w=I&RVuSnXy10=w7(5k}=tgj!+y
zwN_edY8B`V6cl(&n?|5B=EIeDv)X)Gpbn(-R)0i%@l6^~^Z0pd#;K;75z0Ji+Nzmz
z?|5tkXP)1?WM0$^0;9nZHIiAS
zpy+{YXu|CIzAHdoa5JPgTffK?slLNNVHo#HHEk49+$7M(DG=?E-
zfy7Ce$7U~f(c8lwgrH^7y!A}qUasjGUvL1L)Wva|?VqvJhRD3I*m4w8iI~@&aAN9U!)
zsDGb-DTVGx=@+y*`QXUgx
zeo=?Tz5KYfNk@*)0O8QK4t%)TJ2%u0S{hvh_Z`}KnU9#26S+uE8TC{LlYdnWj$=w!
zYcyYwVIqFSqTzi8UINv#wUDuqD!*y0=078h@XjsqN7u-CKc_A*gj!-t!Au?@~JS
z%O+igFEgp?pQ89;jLcSSDAXxol%5!xU$>wOQnHWbQ+UX9UqcFxf|fnYp7Td_S%Agi
zM@f>n;$~zj(aVHpPr7g6qiTeLb+_;5TYaS~(@>^WIyvM*;Om+hzhi<#kh9dIs>-Ze
z^5UCTjh{99lK#_nl$2p^(^yw<)O`HbqsiV}8GTgG6t*L;laa#`rW|FG@n5>
zv0K;R)wp-BBJJ?f(Xe85b?+~$XwQ?AGP0X8>70-ww-uqUY^Y>#fB3L<-S0Mq#e_=*
z^)f<-j>?s{qS!#qTk^%%h+p;nVa2GZh;>7%ve$=>?FyxD%Br>uqfus{v(?8wmq%qD
zC4jP}ZmY?H3Mm+{;_gFHUD=wRR7nWK#w9%}3&PZEmy;d9;_jwhbEZDvV$h_XBe<7j
zjZAE!&3h_aYMLFQ0nKnW45HliXwZZYPnQ0W!TeY&Y3@(SOQQX5eb+0P{}#kqHLFDW
zTr8IdiBn5W!iAAEu0X|Kmj%25&qlv+_Fj#}#U$*A_yV7wl-|us{2esbCQK|UT7xx>
z=Ac^N!Dr_V|9Yl&WvAvR*@^<+b=eOS=kD*tRBEM&0#wvI`)DwxxxttKn)?!D(~MC1
zBdP2nwYxK*P)+S;5gsH}5O)~pY+Q(SpQgN+mS|;}isf87drd4Dj%KOGk9zGj4|0dr
zv(UmirW3m+^Y(9C-Z;YJb9_TPQ-7j(?5RA}8Zhg5z3G<~>yoZ&^O^l *~}zooS=
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