4. Best Practices
The following collection of best practice guidelines are intended to prevent bugs and improve the computational performance.
4.1. MPI
The general rules can be summarized as follows:
The first rule of MPI is: You do not send subsets of arrays, only complete continuous data ranges.
The second rule of MPI is: You do not send subsets of arrays, only complete continuous data ranges.
Third rule of MPI: Someone sends non-continuous data, the simulation is over.
Fourth rule: Only two processors to a single send-receive message. One sender and one receiver, no more and no less.
Fifth rule: Only one processor access (read or write) to a shared memory region.
Sixth rule: After nullification of a shared array follows WIN_SYNC and BARRIER because until the sync is complete the status of the memory is undefined, i.e., old or new value or utter nonsense.
Please also read the general implementation information and, e.g., mappings used for elements, sides and nodes in the chapter MPI Implementation.
If you want to break the first/second rule, remember that in FORTRAN the last dimension can be used for slicing.
4.3. Hawk
Before running a simulation, check out the HLRS Wiki pages Batch System PBSPro (Hawk).
4.3.1. Striping
Always use user-defined striping in the simulation case folders that are on the work spaces as the default stiping setting (dynamic striping) has caused massive problems in the past. Add the following code to your submit script
# Set fixed striping to avoid problems with the progressive Lustre file layout
# - Region 1 [0, 1GiB): Stripe-Size=1 MiB, Stripe-Count=1
#lfs setstripe -c 1 -S 1M $PBS_O_WORKDIR
# - Region 2 [1GiB, 4GiB): Stripe-Size=1 MiB, Stripe-Count=4
#lfs setstripe -c 4 -S 1M $PBS_O_WORKDIR
# - Region 3 [4 GiB, EOF): Stripe-Size=4 MiB, Stripe-Count=8
lfs setstripe -c 8 -S 4M $PBS_O_WORKDIR
Note that the correct line should be commented in and the other lines should be commented out, all depending on the size of your output files. Also consider the stripe settings for large mesh files just to be sure.
4.3.2. Species-zero bug
It has repeatedly occurred that particles with species index zero have been produced on hawk. This might be due to the output to .h5, which could reflect the previous section regarding the striping settings, but could also lie deeper the Lustre file system itself. If this problem occurs, the corrupted particles must be removed from the .h5 file by hand if a restart from such a corrupted file is performed in order to prevent piclas from crashing.
4.4. CollectiveStop
When using the CALL abort(__STAMP__,'ERROR ...') subroutine, each MPI process that encounters this
call emits an output to std.out, which can result in a huge amount of output when running on hundreds
or thousands of processes, especially if an error in the .ini files produces the error in the initialization step.
To prevent excessive output to std.out, the CollectiveStop subroutine has been created.
!==================================================================================================================================
!> \brief Safely terminate program using a soft MPI_FINALIZE in the MPI case and write the error message only on the root.
!>
!> Safely terminate program using a soft MPI_FINALIZE in the MPI case and writes the error message only on the root.
!> Terminate program using a soft MPI_FINALIZE in the MPI case and write the error message only on the root.
!> This routine can only be used if ALL processes are guaranteed to generate the same error at the same time!
!> Prime use is to exit PICLAS without MPI errors and with a single error message if some parameters are not set in the init
!> routines or a file is not found.
!>
!> Criteria where CollectiveStop may be used:
!> 0. In case of doubt stick with Abort, which is always safe!
!> 1. A routine is BY DESIGN (!) called by all processes, i.e. does not permit to be called by single processes or subgroups.
!> 2. The criteria for the CollectiveStop must be identical among all processors.
!> 3. The routine is only used during the init phase.
!> 4. The error must not originate from MPI errors (e.g. during MPI init)
!> 5. The error must not originate from checking roundof errors (e.g. accuracy of interpolation matrices)
!>
!==================================================================================================================================
An example where CollectiveStop should be used instead of abort is in gradients.f90
GradLimiterType=GETINT('Grad-LimiterType')
GradLimVktK=GETREAL('Grad-VktK')
SELECT CASE(GradLimiterType)
CASE(0)
LBWRITE(UNIT_stdOut,*)'Limiter = 0 -> first order FV'
CASE(1) !minmax
LBWRITE(UNIT_stdOut,*)'Using Barth-Jespersen Limiter'
CASE(4) !venkatakrishnan
LBWRITE(UNIT_stdOut,*)'Using Venkatakrishnan limiter with K =', GradLimVktK
CASE(9) ! no limiter (central)
LBWRITE(UNIT_stdOut,*)'Not using any limiter'
CASE DEFAULT
CALL abort(__STAMP__,'Limiter type not implemented.')
END SELECT
which should read
GradLimiterType=GETINT('Grad-LimiterType')
GradLimVktK=GETREAL('Grad-VktK')
SELECT CASE(GradLimiterType)
CASE(0)
LBWRITE(UNIT_stdOut,*)'Limiter = 0 -> first order FV'
CASE(1) !minmax
LBWRITE(UNIT_stdOut,*)'Using Barth-Jespersen Limiter'
CASE(4) !venkatakrishnan
LBWRITE(UNIT_stdOut,*)'Using Venkatakrishnan limiter with K =', GradLimVktK
CASE(9) ! no limiter (central)
LBWRITE(UNIT_stdOut,*)'Not using any limiter'
CASE DEFAULT
CALL CollectiveStop(__STAMP__,'Limiter type not implemented.')
END SELECT