PBS Scripts#

In production mode, we usually submit a PBS (Portable Batch System) job to the HPC for a high-performance timeseries generation for the all available CESM output components and variables. Below we show three Zsh scripts that work for CESM1, 2, and 3, respectively. Each script follows the same workflow:

  1. Python scripts generation

  2. PBS job scripts generation

  3. PBS jobs submission

CESM1 Example#

#!/bin/zsh

export hist_root=/glade/derecho/scratch/jiangzhu/archive
export ts_root=/glade/campaign/cesm/development/cross-wg/diagnostic_framework/x4c/timeseries
export ts_staging=/glade/derecho/scratch/fengzhu/x4c/gen_ts
export casename=b.e13.B1850.f19_g16.icesm131_icam6_paleo.PI.010
export syr=$1
export eyr=$2
export timestep=100
export timestep_unit=year
export task_name=gts
export overwrite=True
export account=P93300324
export pyenv=x4c-py313

# =====================================================================
# create d case directory
# =====================================================================
mkdir -p ${casename}
cd ${casename}

# =====================================================================
# define functions
# =====================================================================
gen_py_script() {
  local name=$1
  local comps=$2
  local comps_info=$3
  local ncpus=$4

  cat >! ${task_name}_${name}_${syr}-${eyr}.py << EOF
import os
import x4c
import time

start = time.time()

dirpath = '$hist_root/$casename'
case = x4c.History(dirpath, comps=$comps, comps_info=${comps_info})

output_dirpath = '$ts_root/$casename'
staging_dirpath = '$ts_staging/$casename'
case.gen_ts(
    comps=$comps,
    output_dirpath=output_dirpath,
    staging_dirpath=staging_dirpath,
    timespan=('$syr', '$eyr'),
    timestep=$timestep,
    timestep_unit='$timestep_unit',
    nproc=$ncpus,
    overwrite=$overwrite,
)

end = time.time()
print(f'Elapsed wall-clock time: {(end-start)/60:.1f} mins')
EOF
}

gen_pbs_script() {
  local name=$1
  local nnodes=$2
  local ncpus=$3

  cat >! ${task_name}_${name}_${syr}-${eyr}.pbs << EOF
#!/bin/bash
#PBS -N ${task_name}_${name}_${syr}-${eyr}
#PBS -q main
#PBS -l select=$nnodes:ncpus=$ncpus:mpiprocs=1
#PBS -l walltime=12:00:00
#PBS -A ${account}

source \$LMOD_ROOT/lmod/init/zsh

module load ncarenv/23.09
module load nco
module load conda
conda activate ${pyenv}

mpiexec -n $nnodes python ${task_name}_${name}_${syr}-${eyr}.py
EOF
}

# =====================================================================
# call functions
# =====================================================================
# Define task entries: name|components|comps_info|nndoes|ncpus
task_list=(
  "o|['ocn']|{}|1|128"
  "ai|['atm', 'ice']|{}|1|128"
  "lr|['lnd', 'rof']|{}|1|128"
)

for entry in "${task_list[@]}"; do
  IFS='|' read -r name comps comps_info nnodes ncpus <<< "$entry"

  gen_py_script "$name" "$comps" "${comps_info}" "$ncpus"
  gen_pbs_script "$name"
  qsub "${task_name}_${name}_${syr}-${eyr}.pbs"
done

exit

CESM2 Example#

#!/bin/zsh

export hist_root=/glade/campaign/cesm/development/cross-wg/diagnostic_framework/CESM_output_for_testing
export ts_root=/glade/campaign/cesm/development/cross-wg/diagnostic_framework/x4c/timeseries
export ts_staging=/glade/derecho/scratch/fengzhu/x4c/gen_ts
export casename=b.e23_alpha17f.BLT1850.ne30_t232.092
export syr=$1
export eyr=$2
export timestep=10
export timestep_unit=year
export task_name=gts
export overwrite=True
export account=P93300324
export pyenv=x4c-py313

# =====================================================================
# create d case directory
# =====================================================================
mkdir -p ${casename}
cd ${casename}

# =====================================================================
# define functions
# =====================================================================
gen_py_script() {
  local name=$1
  local comps=$2
  local comps_info=$3
  local ncpus=$4

  cat >! ${task_name}_${name}_${syr}-${eyr}.py << EOF
import os
import x4c
import time

start = time.time()

dirpath = '$hist_root/$casename'
case = x4c.History(dirpath, comps=$comps, comps_info=${comps_info})

output_dirpath = '$ts_root/$casename'
staging_dirpath = '$ts_staging/$casename'
case.gen_ts(
    comps=$comps,
    output_dirpath=output_dirpath,
    staging_dirpath=staging_dirpath,
    timespan=('$syr', '$eyr'),
    timestep=$timestep,
    timestep_unit='$timestep_unit',
    nproc=$((nnodes * ncpus)),
    overwrite=$overwrite,
)

end = time.time()
print(f'Elapsed wall-clock time: {(end-start)/60:.1f} mins')
EOF
}

gen_pbs_script() {
  local name=$1
  local nnodes=$2
  local ncpus=$3

  cat >! ${task_name}_${name}_${syr}-${eyr}.pbs << EOF
#!/bin/bash
#PBS -N ${task_name}_${name}_${syr}-${eyr}
#PBS -q main
#PBS -l select=$nnodes:ncpus=$ncpus:mpiprocs=1
#PBS -l walltime=12:00:00
#PBS -A ${account}

source \$LMOD_ROOT/lmod/init/zsh

module load ncarenv/23.09
module load nco
module load conda
conda activate ${pyenv}

mpiexec -n $nnodes python ${task_name}_${name}_${syr}-${eyr}.py
EOF
}

# =====================================================================
# call functions
# =====================================================================
# Define task entries: name|components|comps_info|nnodes|ncpus
task_list=(
  "o.sfc|['ocn']|{'ocn': ['mom6.h.sfc']}|1|128"
  "o.z|['ocn']|{'ocn': ['mom6.h.z']}|1|128"
  "o.rho2|['ocn']|{'ocn': ['mom6.h.rho2']}|1|128"
  "o.native|['ocn']|{'ocn': ['mom6.h.native']}|1|128"
  "a.h0a|['atm']|{'atm': ['cam.h0a']}|1|128"
  "lir|['lnd', 'ice', 'rof']|{}|1|128"
)

for entry in "${task_list[@]}"; do
  IFS='|' read -r name comps comps_info nnodes ncpus <<< "$entry"

  gen_py_script "$name" "$comps" "${comps_info}" "$ncpus"
  gen_pbs_script "$name"
  qsub "${task_name}_${name}_${syr}-${eyr}.pbs"
done

exit

CESM3 Example#

#!/bin/zsh

export hist_root=/glade/campaign/cesm/development/cross-wg/diagnostic_framework/CESM_output_for_testing
export ts_root=/glade/campaign/cesm/development/cross-wg/diagnostic_framework/x4c/timeseries
export ts_staging=/glade/derecho/scratch/fengzhu/x4c/gen_ts
export casename=b.e30_beta02.BLT1850.ne30_t232.104
export syr=$1
export eyr=$2
export timestep=10
export timestep_unit=year
export task_name=gts
export overwrite=True
export account=P93300324
export pyenv=x4c-py313

# =====================================================================
# create d case directory
# =====================================================================
mkdir -p ${casename}
cd ${casename}

# =====================================================================
# define functions
# =====================================================================
gen_py_script() {
  local name=$1
  local comps=$2
  local comps_info=$3
  local ncpus=$4

  cat >! ${task_name}_${name}_${syr}-${eyr}.py << EOF
import os
import x4c
import time

start = time.time()

dirpath = '$hist_root/$casename'
case = x4c.History(dirpath, comps=$comps, comps_info=${comps_info})

output_dirpath = '$ts_root/$casename'
staging_dirpath = '$ts_staging/$casename'
case.gen_ts(
    comps=$comps,
    output_dirpath=output_dirpath,
    staging_dirpath=staging_dirpath,
    timespan=('$syr', '$eyr'),
    timestep=$timestep,
    timestep_unit='$timestep_unit',
    nproc=$((nnodes * ncpus)),
    overwrite=$overwrite,
)

end = time.time()
print(f'Elapsed wall-clock time: {(end-start)/60:.1f} mins')
EOF
}

gen_pbs_script() {
  local name=$1

  cat >! ${task_name}_${name}_${syr}-${eyr}.pbs << EOF
#!/bin/bash
#PBS -N ${task_name}_${name}_${syr}-${eyr}
#PBS -q main
#PBS -l select=$nnodes:ncpus=$ncpus:mpiprocs=1
#PBS -l walltime=12:00:00
#PBS -A ${account}

source \$LMOD_ROOT/lmod/init/zsh

module load ncarenv/23.09
module load nco
module load conda
conda activate ${pyenv}

mpiexec -n $nnodes python ${task_name}_${name}_${syr}-${eyr}.py
EOF
}

# =====================================================================
# call functions
# =====================================================================
# Define task entries: name|components|comps_info|nnodes|ncpus
task_list=(
  "o.sfc|['ocn']|{'ocn': ['mom6.h.sfc']}|1|128"
  "o.z|['ocn']|{'ocn': ['mom6.h.z']}|1|128"
  "o.rho2|['ocn']|{'ocn': ['mom6.h.rho2']}|1|128"
  "o.native|['ocn']|{'ocn': ['mom6.h.native']}|1|128"
  "a.h0a|['atm']|{'atm': ['cam.h0a']}|1|128"
  "a.h2a|['atm']|{'atm': ['cam.h2a']}|1|128"
  "a.h3a|['atm']|{'atm': ['cam.h3a']}|1|128"
  "a.h4a|['atm']|{'atm': ['cam.h4a']}|1|128"
  "lir|['lnd', 'ice', 'rof']|{}|1|128"
)

for entry in "${task_list[@]}"; do
  IFS='|' read -r name comps comps_info nnodes ncpus <<< "$entry"

  gen_py_script "$name" "$comps" "${comps_info}" "$ncpus"
  gen_pbs_script "$name"
  qsub "${task_name}_${name}_${syr}-${eyr}.pbs"
done

exit

CMIP7 Example#

#!/bin/zsh

export hist_root=/glade/derecho/scratch/cmip7/archive/
export ts_root=/glade/campaign/cesm/development/cross-wg/diagnostic_framework/x4c/timeseries
export ts_staging=/glade/derecho/scratch/fengzhu/x4c/gen_ts
export casename=b.e30_beta06.B1850C_LTso.ne30_t232_wgx3.192.wrkflw.1
export casefolder=b.e30_beta06.B1850C_LTso.ne30_t232_wgx3.192.wrkflw.1_32
export syr=$1
export eyr=$2
export timestep=10
export timestep_unit=year
export task_name=gts
export overwrite=True
export account=P93300324
export pyenv=x4c-py313

# =====================================================================
# create d case directory
# =====================================================================
mkdir -p ${casefolder}
cd ${casefolder}

# =====================================================================
# define functions
# =====================================================================
gen_py_script() {
  local name=$1
  local comps=$2
  local comps_info=$3
  local ncpus=$4

  cat >! ${task_name}_${name}_${syr}-${eyr}.py << EOF
import os
import x4c
import time

start = time.time()

dirpath = '$hist_root/$casefolder'
case = x4c.History(dirpath, comps=$comps, comps_info=${comps_info}, casename='$casename')

output_dirpath = '$ts_root/$casefolder'
staging_dirpath = '$ts_staging/$casefolder'
case.gen_ts(
    comps=$comps,
    output_dirpath=output_dirpath,
    staging_dirpath=staging_dirpath,
    timespan=('$syr', '$eyr'),
    timestep=$timestep,
    timestep_unit='$timestep_unit',
    nproc=$ncpus,
    overwrite=$overwrite,
)

end = time.time()
print(f'Elapsed wall-clock time: {(end-start)/60:.1f} mins')
EOF
}

gen_pbs_script() {
  local name=$1
  local nnodes=$2
  local ncpus=$3

  cat >! ${task_name}_${name}_${syr}-${eyr}.pbs << EOF
#!/bin/bash
#PBS -N ${task_name}_${name}_${syr}-${eyr}
#PBS -q main
#PBS -l select=$nnodes:ncpus=$ncpus:mpiprocs=1
#PBS -l walltime=12:00:00
#PBS -A ${account}

source \$LMOD_ROOT/lmod/init/zsh

module load ncarenv/23.09
module load nco
module load conda
conda activate ${pyenv}

mpiexec -n $nnodes python ${task_name}_${name}_${syr}-${eyr}.py
EOF
}

# =====================================================================
# call functions
# =====================================================================
# Define task entries: name|components|comps_info|nnodes|ncpus
task_list=(
  "o.sz|['ocn']|{'ocn': ['mom6.h.sfc', 'mom6.h.z']}|1|128"
  "o.nr+r|['ocn', 'rof']|{'ocn': ['mom6.h.native', 'mom6.h.rho2']}|1|128"
  "ail|['atm', 'ice', 'lnd']|{'atm': ['cam.h0a', 'cam.h1a', 'cam.h2a'],'ice': ['cice.h']}|1|128"
  "i.h1|['ice']|{'ice': ['cice.h1']}|13|128"
)

for entry in "${task_list[@]}"; do
  IFS='|' read -r name comps comps_info nnodes ncpus <<< "$entry"

  gen_py_script "$name" "$comps" "${comps_info}" "$ncpus"
  gen_pbs_script "$name" "$nnodes" "$ncpus"
  qsub "${task_name}_${name}_${syr}-${eyr}.pbs"
done

exit