Script Bash per automatizzare i calcoli HPC
Sep 01 2020
Sono uno studente di chimica che lavora su un semplice script bash per automatizzare i calcoli della teoria funzionale della densità HPC utilizzando Quantum Espresso (pw.x). Sono un principiante nello scripting di shell e apprezzerei alcune critiche / feedback prima di provare a implementarlo sul cluster. Lo script chiama ingen.py che è uno script Python che ho scritto per generare nuovi file di input se determinate soglie di parametri nel file di registro non vengono soddisfatte.
#!/bin/bash
#SBATCH --job-name=2x2x6_PbCO3 # job name
#SBATCH --output=slurm.out # Output file name
#SBATCH --error=slurm.err # Error file name
#SBATCH --partition=batch # Partition
#SBATCH --qos=medium+ # Queue
#SBATCH --time=24:00:00 # Time limit
#SBATCH --nodes=3 # Number of nodes
#SBATCH --ntasks-per-node=16 # MPI processes per node
errors='MPI_ABORT|error|aborted|SIGTERM|TIME|CANCELLED|SIGCONT|terminated|fork'
job='2x2x6_PbCO3'
max_runs=5
prefix=PbCO3
#-------------------------------------------------------------------------------
Clear ()
{
# Checks for input/log from a completed batch script
if [[ -f "$prefix.in" && -f "$prefix.log" ]]; then
# If both are found a new input file is generated
python ~/path-to-in-gen.py $prefix.log $prefix.in $job override if [ -z "$(ls -A ../logs_and_inputs)" ]; then
index=1
else
indices=()
# Old input/log are tagged and stored
for entry in "../logs_and_inputs"/$prefix.in-*; do indices+=("${entry: -1}")
done
max=${indices[0]} for n in "${indices[@]}" ; do
((n > max)) && max=$n done index=$((max+1))
rm -r *x*x*
mv $prefix.in ../logs_and_inputs/$prefix.in-$index mv $prefix.log ../logs_and_inputs/$prefix.log-$index
mv $prefix.in-new $prefix.in
fi
fi
}
#-------------------------------------------------------------------------------
# Creates a directory for old logs and inputs to be stored with a numerical tag from 1 to k
Sort ()
{
if [ ! -d "../logs_and_inputs" ]; then
mkdir ../logs_and_inputs
iter=1
else
if [ -z "$(ls -A ../logs_and_inputs)" ]; then iter=1 else indices=() for entry in "../logs_and_inputs"/$prefix.in-*; do
indices+=("${entry: -1}") done max=${indices[0]}
for n in "${indices[@]}" ; do ((n > max)) && max=$n
done
iter=$((max+1)) fi fi max_iter=$((iter+max_runs))
}
#-------------------------------------------------------------------------------
Automode ()
{
mpirun ~/path-to-pw.x < $prefix.in > $prefix.log
# Runs pw.x job, checks for completion and errors
if grep -E -q -- $errors "slurm.err"; then exit 1 fi if grep -q "job DONE." "$prefix.log"; then
# Clear wavefunction files and temp directories
rm -r *x*x*
# Generates new input file
python ~/path-to-in-gen.py $prefix.log $prefix.in $job # Tags and stores the previous input and log mv $prefix.in ../logs_and_inputs/$prefix.in-$iter
mv $prefix.log ../logs_and_inputs/$prefix.log-$iter else exit 1 fi # Checks for generation of new input file if test -f "$prefix.in-new"; then
mv $prefix.in-new $prefix.in
else
exit 1
fi
let "iter=iter+1"
}
#-------------------------------------------------------------------------------
Clear
Sort
while ((iter < max_iter)); do
Automode
done
Risposte
4 l0b0 Sep 01 2020 at 10:02
Suggerimenti specifici:
- I nomi delle funzioni sono per convenzione
snake_case. - Usa più citazioni ™ .
- [[dovrebbe essere usato al posto di[ , perché è più sicuro.
[[ EXPRESSION ]] && [[ EXPRESSION ]]sarebbe più chiaro di[[ EXPRESSION && EXPRESSION ]], a mio parere.set -o errexit -o noclobber -o nounset -o pipefaileshopt -s globfailrenderebbe la gestione degli errori molto più rigorosa.- Questo non è più un codice banale, quindi consiglierei di implementarlo in un linguaggio non shell come Python.
Suggerimenti per gli strumenti:
- Eseguire
shellcheckregolarmente lo script è un buon modo per acquisire possibili problemi. In questo caso l'unica cosa che trova è perrm -r *x*x*:SC2035: usa ./ glob o - glob in modo che i nomi con trattini non diventino opzioni.