From ad34790cbc8112759a8356d56f084363b8a3cbe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 18 Dec 2025 16:17:32 +0100 Subject: [PATCH 01/35] Use conda-forge only --- env/environment.yml | 1 - jenkins/Jenkinsfile | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/env/environment.yml b/env/environment.yml index 98b90e44..0070da5b 100644 --- a/env/environment.yml +++ b/env/environment.yml @@ -1,7 +1,6 @@ name: proc-chain channels: - conda-forge - - defaults dependencies: - python=3.11 - cdo diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index 19875218..ba296f34 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -29,8 +29,10 @@ pipeline { sh 'wget -O ${WORKSPACE}/miniconda.sh https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh' sh 'rm -fr ${WORKSPACE}/miniconda' sh 'bash miniconda.sh -b -p $WORKSPACE/miniconda' + sh 'conda config --remove channels defaults' sh 'conda config --set always_yes yes --set changeps1 no' sh 'conda config --add channels conda-forge' + sh 'conda config --set channel_priority strict' sh 'conda update -n base -c defaults conda' sh 'conda env create -f env/environment.yml' sh '''source ${WORKSPACE}/miniconda/etc/profile.d/conda.sh From 43f2874b1b38986e6a5465844982597940a529bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 18 Dec 2025 16:17:52 +0100 Subject: [PATCH 02/35] Adapt setup script for euler and santis --- jenkins/scripts/setup-spack.sh | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/jenkins/scripts/setup-spack.sh b/jenkins/scripts/setup-spack.sh index 76ed1a11..ccc10fde 100755 --- a/jenkins/scripts/setup-spack.sh +++ b/jenkins/scripts/setup-spack.sh @@ -11,15 +11,13 @@ SPACK_TAG_COSMO=v0.18.1.12 if [[ $(hostname) == eu-* ]]; then source /cluster/apps/local/env2lmod.sh - module load git/2.31.1 - SPACK_TAG=main -elif [[ $(hostname) == daint* ]]; then - git clone --depth 1 git@github.com:C2SM/icon.git icon-tag - SPACK_TAG=`cat icon-tag/config/cscs/SPACK_TAG_DAINT` + module load git + git clone --depth 1 git@gitlab.dkrz.de:icon/icon-model.git icon-tag + SPACK_TAG=`cat icon-tag/config/ethz/SPACK_TAG_EULER` rm -fr icon-tag -elif [[ $(hostname) == balfrin* ]]; then - git clone --depth 1 git@github.com:C2SM/icon.git icon-tag - SPACK_TAG=`cat icon-tag/config/cscs/SPACK_TAG_BALFRIN` +elif [[ $(hostname) == santis* ]]; then + git clone --depth 1 git@gitlab.dkrz.de:icon/icon-model.git icon-tag + SPACK_TAG=`cat icon-tag/config/cscs/SPACK_TAG_SANTIS` rm -fr icon-tag else error "Unknown hostname: $(hostname)" From 9dace95e2327220bd1e029dc0e55fa4e7cae3ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 18 Dec 2025 16:22:00 +0100 Subject: [PATCH 03/35] Remove icon-art build --- jenkins/scripts/build_icon-art.sh | 41 ------------------------------- 1 file changed, 41 deletions(-) delete mode 100755 jenkins/scripts/build_icon-art.sh diff --git a/jenkins/scripts/build_icon-art.sh b/jenkins/scripts/build_icon-art.sh deleted file mode 100755 index 68d09fd2..00000000 --- a/jenkins/scripts/build_icon-art.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -set -e -x - -# Check if script is called correctly -[[ $(git rev-parse --show-toplevel 2>/dev/null) = $(pwd) ]] || error "$0 not launched from toplevel of repository" - -source jenkins/scripts/common.sh - -BRANCH=art -GIT_REMOTE=git@github.com:C2SM/icon.git -MODEL=icon-art - -pushd ext - -# Clone the repo if not already existing -if [[ ! -d "${MODEL}" ]]; then - git clone --depth 1 --recurse-submodules -b ${BRANCH} ${GIT_REMOTE} ${MODEL} -fi - -pushd ${MODEL} - -if [[ $(hostname) == eu-* ]]; then - ./jenkins/scripts/jenkins_euler.sh -b -fc gcc --configure euler.cpu.gcc.O2 -elif [[ $(hostname) == daint* ]]; then - SPACK_TAG=`cat config/cscs/SPACK_TAG_DAINT` - . ../spack-c2sm/setup-env.sh - spack env activate -d config/cscs/spack/${SPACK_TAG}/daint_cpu_nvhpc - spack install -u build -elif [[ $(hostname) == balfrin* ]]; then - SPACK_TAG=`cat config/cscs/SPACK_TAG_BALFRIN` - . ../spack-c2sm/setup-env.sh - spack env activate -d config/cscs/spack/${SPACK_TAG}/daint_cpu_nvhpc - spack install -u build -else - error "Unknown hostname: $(hostname)" -fi - -popd - -popd From 6edbdbdd58819bf6f47314f84c17e996e03dca08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 18 Dec 2025 16:29:36 +0100 Subject: [PATCH 04/35] Remove daint and icon-art build --- jenkins/scripts/jenkins.sh | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/jenkins/scripts/jenkins.sh b/jenkins/scripts/jenkins.sh index 8fbe49ff..3eb4870b 100755 --- a/jenkins/scripts/jenkins.sh +++ b/jenkins/scripts/jenkins.sh @@ -21,11 +21,12 @@ set -e -x # Check if we are on Euler if [[ $(hostname) == eu-* ]]; then host=euler -elif [[ $(hostname) == daint* ]]; then - host=daint +elif [[ $(hostname) == santis* ]]; then + host=santis +else + echo "Unknown hostname: $(hostname)" fi - # Activate conda environment eval "$(conda shell.bash hook)" conda activate proc-chain @@ -85,14 +86,6 @@ else ./jenkins/scripts/build_icon.sh fi -# Build ICON-ART -if [[ -f ext/icon-art/bin/icon ]]; then - echo icon-art executable already exists - skipping build. -else - echo building icon-art... - ./jenkins/scripts/build_icon-art.sh -fi - # Test COSMO-GHG if [[ "$host" == euler ]]; then echo skipping cosmo-ghg test on Euler... From 6afe8c036761f314588df5bc6efdedeec87d2c9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 18 Dec 2025 20:26:45 +0100 Subject: [PATCH 05/35] Start adapting eccodes path (todo) --- cases/icon-test-euler/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cases/icon-test-euler/config.yaml b/cases/icon-test-euler/config.yaml index 28fd1269..b6f94b33 100644 --- a/cases/icon-test-euler/config.yaml +++ b/cases/icon-test-euler/config.yaml @@ -9,7 +9,7 @@ restart_step: PT6H startdate: 2018-01-01T00:00:00Z enddate: 2018-01-01T12:00:00Z -eccodes_dir: ./input/eccodes_definitions +eccodes_dir: ./ext/spack-c2sm/spack/opt/spack/linux-ubuntu22.04-broadwell/gcc-12.2.0//share/eccodes/definitions iconremap_bin: ./ext/icontools/icontools/iconremap iconsub_bin: ./ext/icontools/icontools/iconsub latbc_filename: ifs_201801_lbc.nc From 7b3bbc6ab337e08b8170ebc32e9d6ee9676a17fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 14:25:04 +0100 Subject: [PATCH 06/35] Cleanup testing script and adapt ICON build on Euler --- jenkins/scripts/build_icon.sh | 24 +++++------ jenkins/scripts/jenkins.sh | 78 ----------------------------------- 2 files changed, 11 insertions(+), 91 deletions(-) diff --git a/jenkins/scripts/build_icon.sh b/jenkins/scripts/build_icon.sh index ea1ab959..29717888 100755 --- a/jenkins/scripts/build_icon.sh +++ b/jenkins/scripts/build_icon.sh @@ -7,8 +7,8 @@ set -e -x source jenkins/scripts/common.sh -BRANCH=main -GIT_REMOTE=git@github.com:C2SM/icon.git +BRANCH=release-2025.10-public +GIT_REMOTE=https://gitlab.dkrz.de/icon/icon-model.git MODEL=icon pushd ext @@ -21,17 +21,15 @@ fi pushd ${MODEL} if [[ $(hostname) == eu-* ]]; then - ./jenkins/scripts/jenkins_euler.sh -b -fc gcc --configure euler.cpu.gcc.O2 -elif [[ $(hostname) == daint* ]]; then - SPACK_TAG=`cat config/cscs/SPACK_TAG_DAINT` - . ../spack-c2sm/setup-env.sh - spack env activate -d config/cscs/spack/${SPACK_TAG}/daint_cpu_nvhpc - spack install -u build -elif [[ $(hostname) == balfrin* ]]; then - SPACK_TAG=`cat config/cscs/SPACK_TAG_BALFRIN` - . ../spack-c2sm/setup-env.sh - spack env activate -d config/cscs/spack/${SPACK_TAG}/daint_cpu_nvhpc - spack install -u build + # Setup spack + SPACK_TAG=$(cat "config/ethz/SPACK_TAG_EULER") + git clone --depth 1 --recurse-submodules --shallow-submodules -b ${SPACK_TAG} https://github.com/C2SM/spack-c2sm.git + . spack-c2sm/setup-env.sh + # Load module to access external services on compute nodes + module load eth_proxy + # Build ICON + spack env activate -d config/ethz/spack/${SPACK_TAG}/euler_cpu_gcc + srun -N 1 -n 12 --mem-per-cpu=1G spack install -j 12 else error "Unknown hostname: $(hostname)" fi diff --git a/jenkins/scripts/jenkins.sh b/jenkins/scripts/jenkins.sh index 3eb4870b..cedb8ba2 100755 --- a/jenkins/scripts/jenkins.sh +++ b/jenkins/scripts/jenkins.sh @@ -50,34 +50,6 @@ else ./jenkins/scripts/get_data.sh fi -# Build icontools -if [[ -f ext/icontools/icontools/iconremap ]]; then - echo icontools already installed - skipping build... -else - echo building icontools... - ./jenkins/scripts/build_icontools.sh -fi - -# Build int2lm -if [[ "$host" == euler ]]; then - echo skipping int2lm build on Euler... -elif [[ -f ext/int2lm/TESTSUITE/int2lm ]]; then - echo int2lm executable already exists - skipping build... -else - echo building int2lm... - ./jenkins/scripts/build_int2lm.sh -fi - -# Build COSMO-GHG -if [[ "$host" == euler ]]; then - echo skipping cosmo-ghg build on Euler... -elif [[ -f ext/cosmo-ghg/cosmo/ACC/cosmo_gpu ]]; then - echo cosmo executable already exists - skipping build. -else - echo building cosmo... - ./jenkins/scripts/build_cosmo-ghg.sh -fi - # Build ICON if [[ -f ext/icon/bin/icon ]]; then echo icon executable already exists - skipping build. @@ -86,57 +58,7 @@ else ./jenkins/scripts/build_icon.sh fi -# Test COSMO-GHG -if [[ "$host" == euler ]]; then - echo skipping cosmo-ghg test on Euler... -elif [[ -f work/cosmo-ghg-test/2015010106_2015010112/checkpoints/finished/post_cosmo && "$force_execution" == false ]]; then - echo cosmo-ghg test case already finished - skipping test. -else - echo running cosmo-ghg test case... - ./jenkins/scripts/test_cosmo-ghg.sh -fi - -# Test COSMO-GHG (spinup) -if [[ "$host" == euler ]]; then - echo skipping cosmo-ghg-spinup test on Euler... -elif [[ -f work/cosmo-ghg-spinup-test/2015010109_2015010118/checkpoints/finished/post_cosmo && "$force_execution" == false ]]; then - echo cosmo-ghg-spinup test case already finished - skipping test. -else - echo running cosmo-ghg-spinup test case... - ./jenkins/scripts/test_cosmo-ghg-spinup.sh -fi - # Test ICON -if [[ "$host" == euler ]]; then - echo skipping icon test on Euler... -elif [[ -f work/icon-test/2018010106_2018010112/checkpoints/finished/icon && "$force_execution" == false ]]; then - echo icon test case already finished - skipping test. -else - echo running icon test case... - ./jenkins/scripts/test_icon.sh -fi - -# Test ICON-ART -if [[ "$host" == euler ]]; then - echo skipping icon-art-oem test on Euler... -elif [[ -f work/icon-art-oem-test/2018010106_2018010112/checkpoints/finished/icon && "$force_execution" == false ]]; then - echo icon-art test case already finished - skipping test. -else - echo running icon-art-oem test case... - ./jenkins/scripts/test_icon-art-oem.sh -fi - -# Test ICON-ART-GLOBAL -if [[ "$host" == euler ]]; then - echo skipping icon-art-global test on Euler... -elif [[ -f work/icon-art-global-test/2018010106_2018010112/checkpoints/finished/icon && "$force_execution" == false ]]; then - echo icon-art-global test case already finished - skipping test. -else - echo running icon-art-global test case... - ./jenkins/scripts/test_icon-art-global.sh -fi - -# Test ICON (Euler) if [[ "$host" == euler ]]; then if [[ -f work/icon-test-euler/2018010106_2018010112/checkpoints/finished/icon && "$force_execution" == false ]]; then echo icon test case already finished - skipping test. From 0e9594c21f43ff794979192a580536a8f69e29bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 15:37:38 +0100 Subject: [PATCH 07/35] Avoid double loading spack --- jenkins/scripts/build_icon.sh | 4 ++-- jenkins/scripts/jenkins.sh | 10 ---------- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/jenkins/scripts/build_icon.sh b/jenkins/scripts/build_icon.sh index 29717888..f4c3fb67 100755 --- a/jenkins/scripts/build_icon.sh +++ b/jenkins/scripts/build_icon.sh @@ -21,12 +21,12 @@ fi pushd ${MODEL} if [[ $(hostname) == eu-* ]]; then + # Load necessary modules + module load stack/2025-06 git eth_proxy # Setup spack SPACK_TAG=$(cat "config/ethz/SPACK_TAG_EULER") git clone --depth 1 --recurse-submodules --shallow-submodules -b ${SPACK_TAG} https://github.com/C2SM/spack-c2sm.git . spack-c2sm/setup-env.sh - # Load module to access external services on compute nodes - module load eth_proxy # Build ICON spack env activate -d config/ethz/spack/${SPACK_TAG}/euler_cpu_gcc srun -N 1 -n 12 --mem-per-cpu=1G spack install -j 12 diff --git a/jenkins/scripts/jenkins.sh b/jenkins/scripts/jenkins.sh index cedb8ba2..aeff8650 100755 --- a/jenkins/scripts/jenkins.sh +++ b/jenkins/scripts/jenkins.sh @@ -31,16 +31,6 @@ fi eval "$(conda shell.bash hook)" conda activate proc-chain -# Setup spack -if [[ -d ext/spack-c2sm ]]; then - echo spack folder already exists - skipping build... -else - echo building spack... - ./jenkins/scripts/setup-spack.sh -fi -echo activating spack... -. ext/spack-c2sm/setup-env.sh - # Preparation size=$(du -sb input | awk '{print $1}') if [[ $size -gt 12000000000 ]]; then From 9916c9a4d0a799ddff9ecac975a6ec8449b46dcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 16:24:30 +0100 Subject: [PATCH 08/35] Adjust icon euler test case --- cases/icon-test-euler/config.yaml | 73 +++--- .../icontools_remap_00_lbc_runjob.cfg | 147 ----------- .../icontools_remap_ic_runjob.cfg | 238 ------------------ .../icontools_remap_lbc_rest_runjob.cfg | 121 --------- workflows.yaml | 18 ++ 5 files changed, 51 insertions(+), 546 deletions(-) delete mode 100755 cases/icon-test-euler/icontools_remap_00_lbc_runjob.cfg delete mode 100755 cases/icon-test-euler/icontools_remap_ic_runjob.cfg delete mode 100755 cases/icon-test-euler/icontools_remap_lbc_rest_runjob.cfg diff --git a/cases/icon-test-euler/config.yaml b/cases/icon-test-euler/config.yaml index b6f94b33..35dffc72 100644 --- a/cases/icon-test-euler/config.yaml +++ b/cases/icon-test-euler/config.yaml @@ -1,55 +1,48 @@ -# Configuration file for the 'icon-async-test' case with ICON +# Global ICON simulation initialized from ERA5 (IC only, no LBC). -workflow: icon +workflow: icon-global-era5 constraint: EPYC_7H12 run_on: cpu compute_queue: normal.4h ntasks_per_node: 12 restart_step: PT6H startdate: 2018-01-01T00:00:00Z -enddate: 2018-01-01T12:00:00Z - -eccodes_dir: ./ext/spack-c2sm/spack/opt/spack/linux-ubuntu22.04-broadwell/gcc-12.2.0//share/eccodes/definitions -iconremap_bin: ./ext/icontools/icontools/iconremap -iconsub_bin: ./ext/icontools/icontools/iconsub -latbc_filename: ifs_201801_lbc.nc -inidata_filename: ifs_init_2018010100.nc -output_filename: NWP_LAM -filename_format: _DOM_ -lateral_boundary_grid_order: lateral_boundary +enddate: 2018-01-01T12:00:00Z walltime: - prepare_icon: '00:10:00' - icontools: '00:30:00' - icon: '00:30:00' + prepare_icon: "00:10:00" + era5_ic: "00:40:00" + icon: "00:30:00" -meteo: - dir: ./input/meteo - prefix: ifs_ - nameformat: '%Y%m%d%H' - suffix: .grb - inc: 3 +era5: + dir: ./input/era5 + ml_filename: "era5_ml_{ymd}.grib" + sfc_filename: "era5_surf_{ymd}.grib" -icontools_runjobs: - - icontools_remap_ic_runjob.cfg - - icontools_remap_00_lbc_runjob.cfg - - icontools_remap_lbc_rest_runjob.cfg +era5_partab: ./cases/icon-euler-test/partab_era5_to_icon.txt +era5_ic_runjob_filename: era5_ic_runjob.cfg +inidata_prefix: "era5_init_R02B05_" +inidata_nameformat: "%Y%m%d%H" +inidata_filename_suffix: ".nc" + +meteo: + dir: ./input/meteo + prefix: ifs_ + nameformat: "%Y%m%d%H" + suffix: .grb + inc: 3 input_files: - radiation_grid_filename: ./input/icon/grid/VERIFY_DOM_DOM01.parent.nc - dynamics_grid_filename: ./input/icon/grid/VERIFY_DOM_DOM01.nc - map_file_latbc: ./input/icon/grid/map_file.latbc - lateral_boundary_grid: ./input/icon/grid/lateral_boundary.grid.nc - extpar_filename: ./input/icon/grid/external_parameter_icon_VERIFY_DOM_DOM01_tiles.nc - cldopt_filename: ./input/icon/rad/rrtm_cldopt.nc - lrtm_filename: ./input/icon/rad/rrtmg_lw.nc - map_file_ana: ./input/icon/mapping/map_file.ana + dynamics_grid_filename: ./input/icon/grid/iconR2B05-DOM01.nc + extpar_filename: ./input/icon/grid/extpar_iconR2B05-DOM01.nc + lrtm_filename: ./input/icon/rad/rrtmg_lw.nc + cldopt_filename: ./input/icon/rad/rrtm_cldopt.nc + map_file_ana: ./input/icon/mapping/map_file.ana icon: - binary_file: ./ext/icon/bin/icon - runjob_filename: icon_runjob.cfg - np_tot: 96 - np_io: 1 - np_restart: 1 - np_prefetch: 1 - + binary_file: /cluster/work/climate/lroither/icon_c2sm/icon/bin/icon + runjob_filename: icon_runjob.cfg + np_tot: 96 + np_io: 1 + np_restart: 1 + np_prefetch: 0 diff --git a/cases/icon-test-euler/icontools_remap_00_lbc_runjob.cfg b/cases/icon-test-euler/icontools_remap_00_lbc_runjob.cfg deleted file mode 100755 index 0708bd96..00000000 --- a/cases/icon-test-euler/icontools_remap_00_lbc_runjob.cfg +++ /dev/null @@ -1,147 +0,0 @@ -#!/usr/bin/env bash -#SBATCH --job-name=iconsub -#SBATCH --chdir={cfg.icon_work} -#SBATCH --partition={cfg.compute_queue} -#SBATCH --constraint={cfg.constraint} -#SBATCH --ntasks=1 -#SBATCH --output={logfile} -#SBATCH --open-mode=append - -ulimit -s unlimited - -set -x - -export ECCODES_DEFINITION_PATH={cfg.eccodes_dir}/definitions.edzw-2.12.5-2:{cfg.eccodes_dir}/definitions - -#----------------------------------------------------------------------------- -# PART I: Create auxiliary grid file which contains only the cells of the -# boundary zone. -#----------------------------------------------------------------------------- -cat > NAMELIST_ICONSUB_{cfg.startdate_sim_yyyymmddhh} << EOF_1 -&iconsub_nml - grid_filename = '{cfg.input_files_scratch_dynamics_grid_filename}', - output_type = 4, - lwrite_grid = .TRUE., -/ -&subarea_nml - ORDER = "{cfg.lateral_boundary_grid_order}", - grf_info_file = '{cfg.input_files_scratch_dynamics_grid_filename}', - min_refin_c_ctrl = 1 - max_refin_c_ctrl = 14 -/ -EOF_1 - -srun -n 1 {cfg.iconsub_bin} \ - --nml NAMELIST_ICONSUB_{cfg.startdate_sim_yyyymmddhh} 2>&1 - -#----------------------------------------------------------------------------- -# PART II: Extract boundary data -#----------------------------------------------------------------------------- -rm -f ncstorage.tmp_lbc_{cfg.startdate_sim_yyyymmddhh}* - -set +x -cat > NAMELIST_ICONREMAP_FIELDS_{cfg.startdate_sim_yyyymmddhh} << EOF -! -&input_field_nml ! temperature - inputname = "T" - outputname = "T" - code = 130 - intp_method = 3 -/ -&input_field_nml ! horiz. wind comp. u - inputname = "U" - outputname = "U" - intp_method = 3 -/ -&input_field_nml ! horiz. wind comp. u - inputname = "V" - outputname = "V" - intp_method = 3 -/ -&input_field_nml ! vertical velocity - inputname = "OMEGA" - outputname = "W" - code = 135 - intp_method = 3 -/ -&input_field_nml ! surface pressure - inputname = "LNSP" - outputname = "LNPS" - code = 152 - intp_method = 3 -/ -&input_field_nml ! geopotential - inputname = "Z" - outputname = "GEOSP" - code = 129 - intp_method = 3 -/ -&input_field_nml ! specific humidity - inputname = "QV" - outputname = "QV" - code = 133 - intp_method = 3 -/ -&input_field_nml ! cloud liquid water content - inputname = "CLWC" - outputname = "QC" - code = 246 - intp_method = 3 -/ -&input_field_nml ! cloud ice water content - inputname = "CIWC" - outputname = "QI" - code = 247 - intp_method = 3 -/ -&input_field_nml ! rain water content - inputname = "CRWC" - outputname = "QR" - code = 75 - intp_method = 3 -/ -&input_field_nml ! snow water content - inputname = "CSWC" - outputname = "QS" - code = 76 - intp_method = 3 -/ -EOF - -#----------------------------------------------------------------------------- -# loop over file list: - -echo "DATAFILELIST is {datafile_list}" -for datafilename in {datafile_list} ; do - datafile="${{datafilename##*/}}" # get filename without path - outdatafile=${{datafile%.*}} # get filename without suffix - cat > NAMELIST_ICONREMAP_lbc_{cfg.startdate_sim_yyyymmddhh} << EOF_2C -&remap_nml - in_grid_filename = '{cfg.meteo_dir}/{cfg.meteo_prefix}{cfg.startdate_sim_yyyymmddhh}{cfg.meteo_suffix}' - in_filename = '{cfg.meteo_dir}/${{datafile}}' - in_type = 1 - out_grid_filename = '{cfg.input_files_scratch_lateral_boundary_grid}' - out_filename = '{cfg.icon_input_icbc}/${{outdatafile}}_lbc.nc' - out_type = 2 - out_filetype = 4 - l_have3dbuffer = .false. -! ncstorage_file = "ncstorage.tmp_lbc_{cfg.startdate_sim_yyyymmddhh}" -/ -EOF_2C - - srun -n 1 {cfg.iconremap_bin} -q \ - --remap_nml NAMELIST_ICONREMAP_lbc_{cfg.startdate_sim_yyyymmddhh} \ - --input_field_nml NAMELIST_ICONREMAP_FIELDS_{cfg.startdate_sim_yyyymmddhh} 2>&1 - -done - -#----------------------------------------------------------------------------- -# clean-up - -rm -f nml.log -rm -f NAMELIST_ICONSUB_{cfg.startdate_sim_yyyymmddhh} NAMELIST_ICONREMAP_lbc_{cfg.startdate_sim_yyyymmddhh} NAMELIST_ICONREMAP_FIELDS_{cfg.startdate_sim_yyyymmddhh} - -#----------------------------------------------------------------------------- -exit -#----------------------------------------------------------------------------- - diff --git a/cases/icon-test-euler/icontools_remap_ic_runjob.cfg b/cases/icon-test-euler/icontools_remap_ic_runjob.cfg deleted file mode 100755 index f8d2275d..00000000 --- a/cases/icon-test-euler/icontools_remap_ic_runjob.cfg +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env bash -#SBATCH --job-name=iconremap_ic -#SBATCH --chdir={cfg.icon_work} -#SBATCH --partition={cfg.compute_queue} -#SBATCH --constraint={cfg.constraint} -#SBATCH --ntasks=1 -#SBATCH --output={logfile} -#SBATCH --open-mode=append - -ulimit -s unlimited - -set -x - -export ECCODES_DEFINITION_PATH={cfg.eccodes_dir}/definitions.edzw-2.12.5-2:{cfg.eccodes_dir}/definitions - -#----------------------------------------------------------------------------- -# Remap inital data onto local (limited-area) grid -#----------------------------------------------------------------------------- -cat > NAMELIST_ICONREMAP_FIELDS << EOF -! -&input_field_nml ! temperature - inputname = "T" - outputname = "T" - code = 130 - intp_method = 3 -/ -&input_field_nml ! horiz. wind comp. u - inputname = "U" - outputname = "U" - intp_method = 3 -/ -&input_field_nml ! horiz. wind comp. u - inputname = "V" - outputname = "V" - intp_method = 3 -/ -&input_field_nml ! vertical velocity - inputname = "OMEGA" - outputname = "W" - code = 135 - intp_method = 3 -/ -&input_field_nml ! surface pressure - inputname = "LNSP" - outputname = "LNPS" - code = 152 - intp_method = 3 -/ -&input_field_nml ! geopotential - inputname = "Z" - outputname = "GEOSP" - code = 129 - intp_method = 3 -/ -&input_field_nml ! geopotential - inputname = "Z" - outputname = "GEOP_SFC" - code = 129 - intp_method = 3 -/ -&input_field_nml ! specific humidity - inputname = "QV" - outputname = "QV" - code = 133 - intp_method = 3 -/ -&input_field_nml ! cloud liquid water content - inputname = "CLWC" - outputname = "QC" - code = 246 - intp_method = 3 -/ -&input_field_nml ! cloud ice water content - inputname = "CIWC" - outputname = "QI" - code = 247 - intp_method = 3 -/ -&input_field_nml ! rain water content - inputname = "CRWC" - outputname = "QR" - code = 75 - intp_method = 3 -/ -&input_field_nml ! snow water content - inputname = "CSWC" - outputname = "QS" - code = 76 - intp_method = 3 -/ -&input_field_nml ! snow temperature - inputname = "TSN" - outputname = "T_SNOW" - code = 238 - intp_method = 3 -/ -&input_field_nml ! water content of snow - inputname = "SD" - outputname = "W_SNOW" - code = 141 - intp_method = 3 -/ -&input_field_nml ! density of snow - inputname = "RSN" - outputname = "RHO_SNOW" - code = 33 - intp_method = 3 -/ -&input_field_nml ! snow albedo - inputname = "ASN" - outputname = "ALB_SNOW" - code = 32 - intp_method = 3 -/ -&input_field_nml ! skin temperature - inputname = "SKT" - outputname = "SKT" - code = 235 - intp_method = 3 -/ -&input_field_nml ! sea surface temperature - inputname = "SST" - outputname = "SST" - code = 34 - intp_method = 3 -/ -&input_field_nml ! soil temperature level 1 - inputname = "STL1" - outputname = "STL1" - code = 139 - intp_method = 3 -/ -&input_field_nml ! soil temperature level 2 - inputname = "STL2" - outputname = "STL2" - code = 170 - intp_method = 3 -/ -&input_field_nml ! soil temperature level 3 - inputname = "STL3" - outputname = "STL3" - code = 183 - intp_method = 3 -/ -&input_field_nml ! soil temperature level 4 - inputname = "STL4" - outputname = "STL4" - code = 236 - intp_method = 3 -/ -&input_field_nml ! sea-ice cover - inputname = "CI" - outputname = "CI" - code = 31 - intp_method = 3 -/ -&input_field_nml ! water cont. of interception storage - inputname = "SRC" - outputname = "W_I" - code = 198 - intp_method = 3 -/ -&input_field_nml ! surface roughness - inputname = "SR" - outputname = "Z0" - code = 173 - intp_method = 3 -/ -&input_field_nml ! Land/sea mask - inputname = "LSM" - outputname = "LSM" - code = 172 - intp_method = 3 -/ -&input_field_nml ! soil moisture index layer 1 - inputname = "SWVL1" - outputname = "SMIL1" - code = 80 - intp_method = 3 -/ -&input_field_nml ! soil moisture index layer 2 - inputname = "SWVL2" - outputname = "SMIL2" - code = 81 - intp_method = 3 -/ -&input_field_nml ! soil moisture index layer 3 - inputname = "SWVL3" - outputname = "SMIL3" - code = 82 - intp_method = 3 -/ -&input_field_nml ! soil moisture index layer 4 - inputname = "SWVL4" - outputname = "SMIL4" - code = 83 - intp_method = 3 -/ -EOF - -#----------------------------------------------------------------------------- -# loop over file list: - -datafilename={cfg.meteo_dir}/{cfg.meteo_prefix}{cfg.startdate_sim_yyyymmddhh}{cfg.meteo_suffix} -datafile="${{datafilename##*/}}" # get filename without path -outdatafile=${{datafile%.*}} # get filename without suffix - -# create ICON master namelist -# ------------------------ -# For a complete list see Namelist_overview and Namelist_overview.pdf - -cat > NAMELIST_ICONREMAP << EOF -&remap_nml - in_grid_filename = '{cfg.meteo_dir}/{cfg.meteo_prefix}{cfg.startdate_sim_yyyymmddhh}{cfg.meteo_suffix}' - in_filename = '{cfg.meteo_dir}/${{datafile}}' - in_type = 1 - out_grid_filename = '{cfg.input_files_scratch_dynamics_grid_filename}' - out_filename = '{cfg.icon_input_icbc}/${{outdatafile}}.nc' - out_type = 2 - out_filetype = 4 - l_have3dbuffer = .false. -/ -EOF - -srun -n 1 {cfg.iconremap_bin} \ - -vvvvv -q --remap_nml NAMELIST_ICONREMAP \ - --input_field_nml NAMELIST_ICONREMAP_FIELDS 2>&1 - - -#----------------------------------------------------------------------------- -# clean-up - -rm -f ncstorage.tmp* -rm -f nml.log NAMELIST_SUB NAMELIST_ICONREMAP NAMELIST_ICONREMAP_FIELDS - -#----------------------------------------------------------------------------- -exit -#----------------------------------------------------------------------------- diff --git a/cases/icon-test-euler/icontools_remap_lbc_rest_runjob.cfg b/cases/icon-test-euler/icontools_remap_lbc_rest_runjob.cfg deleted file mode 100755 index 7f1d7968..00000000 --- a/cases/icon-test-euler/icontools_remap_lbc_rest_runjob.cfg +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env bash -#SBATCH --job-name=iconremap_lbc -#SBATCH --chdir={cfg.icon_work} -#SBATCH --partition={cfg.compute_queue} -#SBATCH --constraint={cfg.constraint} -#SBATCH --ntasks=1 -#SBATCH --output={logfile} -#SBATCH --open-mode=append - -ulimit -s unlimited - -set -x - -export ECCODES_DEFINITION_PATH={cfg.eccodes_dir}/definitions.edzw-2.12.5-2:{cfg.eccodes_dir}/definitions - -#----------------------------------------------------------------------------- -# Extract boundary data -#----------------------------------------------------------------------------- - -rm -f ncstorage.tmp_lbc_{cfg.startdate_sim_yyyymmddhh}* - -cat > NAMELIST_ICONREMAP_FIELDS_{cfg.startdate_sim_yyyymmddhh} << EOF -! -&input_field_nml ! temperature - inputname = "T" - outputname = "T" - code = 130 - intp_method = 3 -/ -&input_field_nml ! horiz. wind comp. u - inputname = "U" - outputname = "U" - intp_method = 3 -/ -&input_field_nml ! horiz. wind comp. v - inputname = "V" - outputname = "V" - intp_method = 3 -/ -&input_field_nml ! vertical velocity - inputname = "OMEGA" - outputname = "W" - code = 135 - intp_method = 3 -/ -&input_field_nml ! surface pressure - inputname = "LNSP" - outputname = "LNPS" - code = 152 - intp_method = 3 -/ -&input_field_nml ! specific humidity - inputname = "QV" - outputname = "QV" - code = 133 - intp_method = 3 -/ -&input_field_nml ! cloud liquid water content - inputname = "CLWC" - outputname = "QC" - code = 246 - intp_method = 3 -/ -&input_field_nml ! cloud ice water content - inputname = "CIWC" - outputname = "QI" - code = 247 - intp_method = 3 -/ -&input_field_nml ! rain water content - inputname = "CRWC" - outputname = "QR" - code = 75 - intp_method = 3 -/ -&input_field_nml ! snow water content - inputname = "CSWC" - outputname = "QS" - code = 76 - intp_method = 3 -/ -EOF - -#----------------------------------------------------------------------------- -# loop over file list: - -echo "DATAFILELIST is {datafile_list_rest}" -for datafilename in {datafile_list_rest} ; do - datafile="${{datafilename##*/}}" # get filename without path - outdatafile=${{datafile%.*}} # get filename without suffix - cat > NAMELIST_ICONREMAP_lbc_{cfg.startdate_sim_yyyymmddhh} << EOF_2C -&remap_nml - in_grid_filename = '{cfg.meteo_dir}/{cfg.meteo_prefix}{cfg.startdate_sim_yyyymmddhh}{cfg.meteo_suffix}' - in_filename = '{cfg.meteo_dir}/${{datafile}}' - in_type = 1 - out_grid_filename = '{cfg.input_files_scratch_lateral_boundary_grid}' - out_filename = '{cfg.icon_input_icbc}/${{outdatafile}}_lbc.nc' - out_type = 2 - out_filetype = 4 - l_have3dbuffer = .false. -! ncstorage_file = "ncstorage.tmp_lbc_{cfg.startdate_sim_yyyymmddhh}" -/ -EOF_2C - - srun -n 1 {cfg.iconremap_bin} -q \ - --remap_nml NAMELIST_ICONREMAP_lbc_{cfg.startdate_sim_yyyymmddhh} \ - --input_field_nml NAMELIST_ICONREMAP_FIELDS_{cfg.startdate_sim_yyyymmddhh} 2>&1 - -done - -#----------------------------------------------------------------------------- -# clean-up - -#rm -f ncstorage.tmp_lbc_{cfg.startdate_sim_yyyymmddhh}* -rm -f nml.log -rm -f NAMELIST_ICONSUB_{cfg.startdate_sim_yyyymmddhh} NAMELIST_ICONREMAP_lbc_{cfg.startdate_sim_yyyymmddhh} NAMELIST_ICONREMAP_FIELDS_{cfg.startdate_sim_yyyymmddhh} - -#----------------------------------------------------------------------------- -exit -#----------------------------------------------------------------------------- - diff --git a/workflows.yaml b/workflows.yaml index abe778d7..4ccc5b9f 100644 --- a/workflows.yaml +++ b/workflows.yaml @@ -165,6 +165,24 @@ icon: previous: - icon +icon-global-era5: + features: + - restart + jobs: + - prepare_icon + - era5_ic + - icon + dependencies: + era5_ic: + current: + - prepare_icon + icon: + current: + - prepare_icon + - era5_ic + previous: + - icon + icon-art: features: - restart From 638fa24f80c864ae8ad2d797a6d0df00fe946088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 16:26:05 +0100 Subject: [PATCH 09/35] Add ERA5 IC job --- jobs/era5_ic.py | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 jobs/era5_ic.py diff --git a/jobs/era5_ic.py b/jobs/era5_ic.py new file mode 100644 index 00000000..0ecd6ff2 --- /dev/null +++ b/jobs/era5_ic.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +era5_ic.py +Processing-chain job that generates ICON initial conditions (IC) from ERA5 input. + +Design goals +------------ +- Keep the job modular: + * all paths and filenames come from cfg / case templates + * the actual transformation is executed in a Slurm job script produced + from a case-provided template (similar to icontools runjobs) +- Support global runs: + * generate a single IC file on the ICON grid + * do NOT generate LBC files +""" + +import logging +from pathlib import Path +from . import tools, prepare_icon +BASIC_PYTHON_JOB = True + +def _compute_inidata_filename(cfg) -> Path: + """ + Replicate the same IC filename logic used by jobs/icon.py, + so that era5_ic produces *exactly* the file ICON will read. + """ + if hasattr(cfg, 'inicond_filename'): + return cfg.icon_input_icbc / cfg.inicond_filename + if (hasattr(cfg, 'inidata_prefix') and hasattr(cfg, 'inidata_nameformat') + and hasattr(cfg, 'inidata_filename_suffix')): + return cfg.icon_input_icbc / str( + cfg.startdate.strftime(cfg.inidata_prefix + + cfg.inidata_nameformat + + cfg.inidata_filename_suffix)) + # fallback: match icon.py default behavior + return cfg.icon_input_icbc / str( + cfg.startdate_sim.strftime(cfg.meteo['prefix'] + + cfg.meteo['nameformat']) + '.nc') + +def main(cfg): + """ + 1) Prepare standard ICON paths (same helper as other jobs) + 2) Create a Slurm script from the case template cfg.era5_ic_runjob_filename + 3) Submit it + The Slurm script is responsible for: + - converting ERA5 GRIB -> NetCDF + - renaming variables to ICON-like naming (via a partab) + - remapping to the ICON triangular grid + - writing the final IC file to cfg.icon_input/icbc + """ + + prepare_icon.set_cfg_variables(cfg) + tools.change_logfile(cfg.logfile) + logging.info("Generate global ICON initial conditions from ERA5 (IC only).") + + # Ensure run + icbc directories exist (prepare_icon usually created them, + # but being explicit makes the job robust if invoked in isolation). + tools.create_dir(cfg.icon_work, "icon_work") + tools.create_dir(cfg.icon_input_icbc, "icon_input_icbc") + + # Useful formatted dates for the template (avoid bash date gymnastics) + cfg.era5_ymd = cfg.startdate_sim.strftime('%Y-%m-%d') # e.g. 2021-01-01 + cfg.era5_yyyymmddhh = cfg.startdate_sim.strftime('%Y%m%d%H') # 2021010100 + + # Compute the *exact* file that ICON will later read + inidata_filename = _compute_inidata_filename(cfg) + + # Case template name (kept configurable) + # Put in config.yaml: era5_ic_runjob_filename: era5_ic_runjob.cfg + template_name = getattr(cfg, 'era5_ic_runjob_filename', 'era5_ic_runjob.cfg') + template = (cfg.case_path / template_name).read_text() + script_str = template.format( + cfg=cfg, + inidata_filename=inidata_filename, + ) + script = (cfg.icon_work / 'run_era5_ic.job') + script.write_text(script_str) + logging.info(f"Submitting ERA5 IC generation job: {script}") + cfg.submit('era5_ic', script) + logging.info("OK") From ac08ab423aac31fa8a35cef360a1378762f9de57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 16:27:50 +0100 Subject: [PATCH 10/35] Modify ICON runjob --- cases/icon-test-euler/icon_runjob.cfg | 390 +++++++------------------- 1 file changed, 103 insertions(+), 287 deletions(-) diff --git a/cases/icon-test-euler/icon_runjob.cfg b/cases/icon-test-euler/icon_runjob.cfg index a2bfbb46..d881a0cc 100755 --- a/cases/icon-test-euler/icon_runjob.cfg +++ b/cases/icon-test-euler/icon_runjob.cfg @@ -8,38 +8,31 @@ #SBATCH --chdir={cfg.icon_work} set +x -ulimit -s unlimited +ulimit -s unlimited -# OpenMP environment variables -# ---------------------------- -export OMP_NUM_THREADS=1 -export ICON_THREADS=1 +# OpenMP environment variables +export OMP_NUM_THREADS=1 +export ICON_THREADS=1 export OMP_SCHEDULE=static -export OMP_DYNAMIC="false" -export OMP_STACKSIZE=200M -# -# MPI variables -# ------------- +export OMP_DYNAMIC="false" +export OMP_STACKSIZE=200M + +# MPI settings no_of_nodes=1 -mpi_procs_pernode={cfg.icon_np_tot} -((mpi_total_procs=no_of_nodes * mpi_procs_pernode)) -# -# blocking length -# --------------- +mpi_procs_pernode={cfg.icon_np_tot} +((mpi_total_procs=no_of_nodes * mpi_procs_pernode)) + +# blocking length nproma=64 # ---------------------------------------------------------------------------- -# create ICON master namelist +# ICON master namelist # ---------------------------------------------------------------------------- - cat > icon_master.namelist << EOF -! master_nml: ---------------------------------------------------------------- &master_nml - lrestart = {cfg.lrestart} ! .TRUE.=current experiment is resumed - read_restart_namelists = .true. + lrestart = {cfg.lrestart} + read_restart_namelists = .true. / - -! master_time_control_nml: --------------------------------------------------- &master_time_control_nml calendar = 'proleptic gregorian' restartTimeIntval = '{cfg.restart_step}' @@ -47,295 +40,118 @@ cat > icon_master.namelist << EOF experimentStartDate = '{cfg.ini_datetime_string}' experimentStopDate = '{cfg.end_datetime_string}' / - -! master_model_nml: repeated for each model ---------------------------------- &master_model_nml - model_type = 1 ! identifies which component to run (atmosphere,ocean,...) - model_name = "ATMO" ! character string for naming this component. - model_namelist_filename = "NAMELIST_{cfg.casename}" ! file name containing the model namelists - model_min_rank = 1 ! start MPI rank for this model - model_max_rank = 65536 ! end MPI rank for this model - model_inc_rank = 1 ! stride of MPI ranks + model_type = 1 + model_name = "ATMO" + model_namelist_filename = "NAMELIST_{cfg.casename}" + model_min_rank = 1 + model_max_rank = 65536 + model_inc_rank = 1 / EOF - -# ---------------------------------------------------------------------- -# model namelists -# ---------------------------------------------------------------------- - +# ---------------------------------------------------------------------------- +# Model namelist +# ---------------------------------------------------------------------------- cat > NAMELIST_{cfg.casename} << EOF -! parallel_nml: MPI parallelization ------------------------------------------- ¶llel_nml - nproma = 128 ! loop chunk length - p_test_run = .FALSE. ! .TRUE. means verification run for MPI parallelization - num_io_procs = {cfg.icon_np_io} ! number of I/O processors - num_restart_procs = {cfg.icon_np_restart} ! number of restart processors - num_prefetch_proc = {cfg.icon_np_prefetch} ! number of processors for LBC prefetching - iorder_sendrecv = 3 ! sequence of MPI send/receive calls + nproma = 128 + p_test_run = .FALSE. + num_io_procs = {cfg.icon_np_io} + num_restart_procs = {cfg.icon_np_restart} + num_prefetch_proc = {cfg.icon_np_prefetch} ! must be 0 for global IC-only + iorder_sendrecv = 3 / - - -! run_nml: general switches --------------------------------------------------- &run_nml - ltestcase = .FALSE. ! real case run - num_lev = 60 ! number of full levels (atm.) for each domain - lvert_nest = .FALSE. ! no vertical nesting - dtime = 60. ! timestep in seconds - ldynamics = .TRUE. ! compute adiabatic dynamic tendencies - ltransport = .TRUE. ! compute large-scale tracer transport - ntracer = 0 ! number of advected tracers - iforcing = 3 ! forcing of dynamics and transport by parameterized processes - msg_level = 13 ! detailed report during integration - ltimer = .TRUE. ! timer for monitoring the runtime of specific routines - timers_level = 10 ! performance timer granularity - check_uuid_gracefully = .TRUE. ! give only warnings for non-matching uuids - output = "nml" ! main switch for enabling/disabling components of the model output - lart = .FALSE. ! main switch for ART - debug_check_level = 10 - restart_filename = "{cfg.icon_restart_out}/{cfg.output_filename}_.nc" - activate_sync_timers = .TRUE. + ltestcase = .FALSE. + num_lev = 60 + lvert_nest = .FALSE. + dtime = 60. + ldynamics = .TRUE. + ltransport = .TRUE. + ntracer = 0 + iforcing = 3 + msg_level = 13 + ltimer = .TRUE. + timers_level = 10 + check_uuid_gracefully = .TRUE. + output = "nml" + lart = .FALSE. + debug_check_level = 10 + restart_filename = "{cfg.icon_restart_out}/{cfg.output_filename}_.nc" + activate_sync_timers = .TRUE. / - -! diffusion_nml: horizontal (numerical) diffusion ---------------------------- -&diffusion_nml - lhdiff_vn = .TRUE. ! diffusion on the horizontal wind field - lhdiff_temp = .TRUE. ! diffusion on the temperature field - lhdiff_w = .TRUE. ! diffusion on the vertical wind field - hdiff_order = 5 ! order of nabla operator for diffusion - itype_vn_diffu = 1 ! reconstruction method used for Smagorinsky diffusion - itype_t_diffu = 2 ! discretization of temperature diffusion - hdiff_efdt_ratio = 24.0 ! ratio of e-folding time to time step - hdiff_smag_fac = 0.025 ! scaling factor for Smagorinsky diffusion -/ - -! dynamics_nml: dynamical core ----------------------------------------------- &dynamics_nml - iequations = 3 ! type of equations and prognostic variables - divavg_cntrwgt = 0.50 ! weight of central cell for divergence averaging - lcoriolis = .TRUE. ! Coriolis force + iequations = 3 + divavg_cntrwgt = 0.50 + lcoriolis = .TRUE. / - -! extpar_nml: external data -------------------------------------------------- &extpar_nml - itopo = 1 ! topography (0:analytical) - extpar_filename = '{cfg.input_files_scratch_extpar_filename}' ! filename of external parameter input file - n_iter_smooth_topo = 1,1 ! iterations of topography smoother - heightdiff_threshold = 3000. ! height difference between neighb. grid points - hgtdiff_max_smooth_topo = 750.,750. ! see Namelist doc - heightdiff_threshold = 2250.,1500. + itopo = 1 + extpar_filename = '{cfg.input_files_scratch_extpar_filename}' + n_iter_smooth_topo = 1,1 + heightdiff_threshold = 3000. + hgtdiff_max_smooth_topo = 750.,750. / - -! initicon_nml: specify read-in of initial state ------------------------------ &initicon_nml - init_mode = 2 ! 7: start from DWD fg with subsequent vertical remapping - lread_ana = .FALSE. ! no analysis data will be read - ifs2icon_filename = "{inidata_filename}" ! initial data filename - ana_varnames_map_file = "{cfg.input_files_scratch_map_file_ana}" ! dictionary mapping internal names onto GRIB2 shortNames - ltile_coldstart = .TRUE. ! coldstart for surface tiles - ltile_init = .FALSE. ! set it to .TRUE. if FG data originate from run without tiles + init_mode = 2 + lread_ana = .FALSE. + ifs2icon_filename = "{inidata_filename}" ! produced by era5_ic job + ana_varnames_map_file = "{cfg.input_files_scratch_map_file_ana}" + ltile_coldstart = .TRUE. + ltile_init = .FALSE. / - -! grid_nml: horizontal grid -------------------------------------------------- &grid_nml - dynamics_grid_filename = "{cfg.input_files_scratch_dynamics_grid_filename}" ! array of the grid filenames for the dycore - radiation_grid_filename = "{cfg.input_files_scratch_radiation_grid_filename}" ! array of the grid filenames for the radiation model - dynamics_parent_grid_id = 0 ! array of the indexes of the parent grid filenames - lredgrid_phys = .TRUE. ! .true.=radiation is calculated on a reduced grid - lfeedback = .TRUE. ! specifies if feedback to parent grid is performed - l_limited_area = .TRUE. ! .TRUE. performs limited area run - ifeedback_type = 2 ! feedback type (incremental/relaxation-based) - start_time = 0. ! Time when a nested domain starts to be active [s] + dynamics_grid_filename = "{cfg.input_files_scratch_dynamics_grid_filename}" + radiation_grid_filename = "{cfg.input_files_scratch_dynamics_grid_filename}" + dynamics_parent_grid_id = 0 + lredgrid_phys = .TRUE. + l_limited_area = .FALSE. ! IMPORTANT: global mode / - -! gridref_nml: grid refinement settings -------------------------------------- -&gridref_nml - denom_diffu_v = 150. ! denominator for lateral boundary diffusion of velocity -/ - -! interpol_nml: settings for internal interpolation methods ------------------ -&interpol_nml - nudge_zone_width = 8 ! width of lateral boundary nudging zone - support_baryctr_intp = .FALSE. ! barycentric interpolation support for output - nudge_max_coeff = 0.07 - nudge_efold_width = 2.0 -/ - -! io_nml: general switches for model I/O ------------------------------------- &io_nml - itype_pres_msl = 5 ! method for computation of mean sea level pressure - itype_rh = 1 ! method for computation of relative humidity - lmask_boundary = .TRUE. ! mask out interpolation zone in output - restart_file_type = 5 + itype_pres_msl = 5 + itype_rh = 1 + restart_file_type = 5 / - -! limarea_nml: settings for limited area mode --------------------------------- -&limarea_nml - itype_latbc = 1 ! 1: time-dependent lateral boundary conditions - dtime_latbc = 10800 ! time difference between 2 consecutive boundary data - nlev_latbc = 90 ! Number of vertical levels in boundary data - latbc_boundary_grid = "{cfg.input_files_scratch_lateral_boundary_grid}" ! Grid file defining the lateral boundary - latbc_path = "{cfg.icon_input_icbc}" ! Absolute path to boundary data - latbc_varnames_map_file = "{cfg.input_files_scratch_map_file_latbc}" - latbc_filename = "{cfg.latbc_filename}" ! boundary data input filename - init_latbc_from_fg = .FALSE. ! .TRUE.: take lbc for initial time from first guess -/ - -! lnd_nml: land scheme switches ----------------------------------------------- -&lnd_nml - ntiles = 1 ! number of tiles - nlev_snow = 3 ! number of snow layers - lmulti_snow = .FALSE. ! .TRUE. for use of multi-layer snow model - idiag_snowfrac = 20 ! type of snow-fraction diagnosis - lsnowtile = .TRUE. ! .TRUE.=consider snow-covered and snow-free separately - itype_root = 2 ! root density distribution - itype_heatcond = 3 ! type of soil heat conductivity - itype_lndtbl = 4 ! table for associating surface parameters - itype_evsl = 4 ! type of bare soil evaporation - itype_root = 2 ! root density distribution - cwimax_ml = 5.e-4 ! scaling parameter for max. interception storage - c_soil = 1.75 ! surface area density of the evaporative soil surface - c_soil_urb = 0.5 ! same for urban areas - lseaice = .TRUE. ! .TRUE. for use of sea-ice model - llake = .TRUE. ! .TRUE. for use of lake model -/ - -! nonhydrostatic_nml: nonhydrostatic model ----------------------------------- -&nonhydrostatic_nml - iadv_rhotheta = 2 ! advection method for rho and rhotheta - ivctype = 2 ! type of vertical coordinate - itime_scheme = 4 ! time integration scheme - ndyn_substeps = 5 ! number of dynamics steps per fast-physics step - exner_expol = 0.333 ! temporal extrapolation of Exner function - vwind_offctr = 0.2 ! off-centering in vertical wind solver - damp_height = 12500.0 ! height at which Rayleigh damping of vertical wind starts - rayleigh_coeff = 1.5 ! Rayleigh damping coefficient - divdamp_order = 24 ! order of divergence damping - divdamp_type = 3 ! type of divergence damping - divdamp_fac = 0.004 ! scaling factor for divergence damping - igradp_method = 3 ! discretization of horizontal pressure gradient - l_zdiffu_t = .TRUE. ! specifies computation of Smagorinsky temperature diffusion - thslp_zdiffu = 0.02 ! slope threshold (temperature diffusion) - thhgtd_zdiffu = 125.0 ! threshold of height difference (temperature diffusion) - htop_moist_proc = 22500.0 ! max. height for moist physics - hbot_qvsubstep = 22500.0 ! height above which QV is advected with substepping scheme -/ - -! nwp_phy_nml: switches for the physics schemes ------------------------------ &nwp_phy_nml - inwp_gscp = 2 ! cloud microphysics and precipitation - inwp_convection = 1 ! convection - lshallowconv_only = .FALSE. ! only shallow convection - inwp_radiation = 1 ! radiation - inwp_cldcover = 1 ! cloud cover scheme for radiation - inwp_turb = 1 ! vertical diffusion and transfer - inwp_satad = 1 ! saturation adjustment - inwp_sso = 1 ! subgrid scale orographic drag - inwp_gwd = 0 ! non-orographic gravity wave drag - inwp_surface = 1 ! surface scheme - latm_above_top = .TRUE. ! take into account atmosphere above model top for radiation computation - ldetrain_conv_prec = .TRUE. - efdt_min_raylfric = 7200. ! minimum e-folding time of Rayleigh friction - itype_z0 = 2 ! type of roughness length data - icapdcycl = 3 ! apply CAPE modification to improve diurnalcycle over tropical land - icpl_aero_conv = 1 ! coupling between autoconversion and Tegen aerosol climatology - icpl_aero_gscp = 1 ! coupling between autoconversion and Tegen aerosol climatology - lrtm_filename = '{cfg.input_files_scratch_lrtm_filename}' ! longwave absorption coefficients for RRTM_LW - cldopt_filename = '{cfg.input_files_scratch_cldopt_filename}' ! RRTM cloud optical properties - dt_rad = 720. ! time step for radiation in s - dt_conv = 120.,90.,90. ! time step for convection in s (domain specific) - dt_sso = 120.,360.,360. ! time step for SSO parameterization - dt_gwd = 360.,360.,360. ! time step for gravity wave drag parameterization -/ - -! nwp_tuning_nml: additional tuning parameters ---------------------------------- -&nwp_tuning_nml - itune_albedo = 1 ! reduced albedo (w.r.t. MODIS data) over Sahara - tune_gkwake = 1.8 - tune_gkdrag = 0.01 - tune_minsnowfrac = 0.3 + inwp_gscp = 2 + inwp_convection = 1 + inwp_radiation = 1 + inwp_cldcover = 1 + inwp_turb = 1 + inwp_satad = 1 + inwp_sso = 1 + inwp_gwd = 0 + inwp_surface = 1 + latm_above_top = .TRUE. + efdt_min_raylfric = 7200. + itype_z0 = 2 + lrtm_filename = '{cfg.input_files_scratch_lrtm_filename}' + cldopt_filename = '{cfg.input_files_scratch_cldopt_filename}' + dt_rad = 720. + dt_conv = 120. + dt_sso = 120. + dt_gwd = 360. / - -! output_nml: specifies an output stream -------------------------------------- &output_nml - filetype = 4 ! output format: 2=GRIB2, 4=NETCDFv2 - dom = 1 ! write domain 1 only - output_bounds = 0., 10000000., 3600. ! start, end, increment - steps_per_file = 1 ! number of steps per file - mode = 1 ! 1: forecast mode (relative t-axis), 2: climate mode (absolute t-axis) - include_last = .TRUE. - output_filename = '{cfg.output_filename}' - filename_format = '{cfg.icon_output}/_DOM_' ! file name base - steps_per_file_inclfirst = .FALSE. - output_grid = .TRUE. - remap = 1 ! 1: remap to lat-lon grid - !north_pole = -170.,40. ! definition of north_pole for rotated lat-lon grid - reg_lon_def = -16.0,0.13,36.0 ! - reg_lat_def = 32.0,0.12,74.0 ! - ml_varlist = 'group:PBL_VARS', - 'group:ATMO_ML_VARS', - 'group:precip_vars', - 'group:land_vars', - 'group:nh_prog_vars', - 'z_mc', 'z_ifc', + filetype = 4 + dom = 1 + output_bounds = 0., 10000000., 3600. + steps_per_file = 1 + mode = 1 + include_last = .TRUE. + output_filename = '{cfg.output_filename}' + filename_format = '{cfg.icon_output}/_DOM_' + output_grid = .TRUE. + remap = 1 + reg_lon_def = -179.5,1.0,179.5 + reg_lat_def = 89.5,-1.0,-89.5 / - -! radiation_nml: radiation scheme --------------------------------------------- -&radiation_nml - irad_o3 = 7 ! ozone climatology - irad_aero = 6 ! aerosols - albedo_type = 2 ! type of surface albedo - vmr_co2 = 390.e-06 - vmr_ch4 = 1800.e-09 - vmr_n2o = 322.0e-09 - vmr_o2 = 0.20946 - vmr_cfc11 = 240.e-12 - vmr_cfc12 = 532.e-12 -/ - -! sleve_nml: vertical level specification ------------------------------------- -&sleve_nml - min_lay_thckn = 20.0 ! layer thickness of lowermost layer - top_height = 23000.0 ! height of model top - stretch_fac = 0.65 ! stretching factor to vary distribution of model levels - decay_scale_1 = 4000.0 ! decay scale of large-scale topography component - decay_scale_2 = 2500.0 ! decay scale of small-scale topography component - decay_exp = 1.2 ! exponent of decay function - flat_height = 16000.0 ! height above which the coordinate surfaces are flat -/ - -! transport_nml: tracer transport --------------------------------------------- -&transport_nml - npassive_tracer = 0 ! number of additional passive tracers - ivadv_tracer = 3, 3, 3, 3, 3, 3 ! tracer specific method to compute vertical advection - itype_hlimit = 3, 4, 4, 4, 4, 4 ! type of limiter for horizontal transport - ihadv_tracer = 52, 2, 2, 2, 2, 22 ! tracer specific method to compute horizontal advection - llsq_svd = .TRUE. ! use SV decomposition for least squares design matrix -/ - -! turbdiff_nml: turbulent diffusion ------------------------------------------- -&turbdiff_nml - tkhmin = 0.75 ! scaling factor for minimum vertical diffusion coefficient - tkmmin = 0.75 ! scaling factor for minimum vertical diffusion coefficient - pat_len = 750.0 ! effective length scale of thermal surface patterns - c_diff = 0.2 ! length scale factor for vertical diffusion of TKE - rat_sea = 7.5 ! controls laminar resistance for sea surface - rlam_heat = 1.5 - ltkesso = .TRUE. ! consider TKE-production by sub-grid SSO wakes - frcsmot = 0.2 ! these 2 switches together apply vertical smoothing of the TKE source terms - imode_frcsmot = 2 ! in the tropics (only), which reduces the moist bias in the tropical lower troposphere - itype_sher = 3 ! type of shear forcing used in turbulence - ltkeshs = .TRUE. ! include correction term for coarse grids in hor. shear production term - a_hshr = 2.0 ! length scale factor for separated horizontal shear mode - icldm_turb = 1 ! mode of cloud water representation in turbulence - ldiff_qi = .TRUE. -/ - EOF -# ---------------------------------------------------------------------- -# run the model! -# ---------------------------------------------------------------------- +# ---------------------------------------------------------------------------- +# Run ICON +# ---------------------------------------------------------------------------- source {cfg.chain_src_dir}/ext/icon/modules.env set -x -mpirun -n $mpi_total_procs ./icon +mpirun -n $mpi_total_procs ./{cfg.icon_execname} set +x From 32c5ef7e65b976ed8e1fd5ce22c81e07623c76ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 16:34:46 +0100 Subject: [PATCH 11/35] Add ERA5 IC runscript --- cases/icon-test-euler/era5_ic_runjob.cfg | 192 +++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 cases/icon-test-euler/era5_ic_runjob.cfg diff --git a/cases/icon-test-euler/era5_ic_runjob.cfg b/cases/icon-test-euler/era5_ic_runjob.cfg new file mode 100644 index 00000000..fbe2f24e --- /dev/null +++ b/cases/icon-test-euler/era5_ic_runjob.cfg @@ -0,0 +1,192 @@ +#!/usr/bin/env bash +#SBATCH --job-name=era5_ic_{cfg.casename}_{cfg.startdate_sim_yyyymmddhh} +#SBATCH --time={cfg.walltime_era5_ic} +#SBATCH --partition={cfg.compute_queue} +#SBATCH --constraint={cfg.constraint} +#SBATCH --ntasks=1 +#SBATCH --output={cfg.logfile} +#SBATCH --open-mode=append +#SBATCH --chdir={cfg.icon_work} + +# --------------------------------------------------------------------- +# ERA5 -> ICON initial conditions (GLOBAL, IC only) +# +# This script is submitted by jobs/era5_ic.py. +# It MUST write the final IC file exactly to: +# {inidata_filename} +# +# Design: +# - Use case config for input locations + partab +# - Use staged ICON files from prepare_icon (cfg.input_files_scratch_*) +# - Keep all intermediate files inside cfg.icon_work +# --------------------------------------------------------------------- +# +set -euo pipefail +set -x +ulimit -s unlimited + +# Optional: load modules needed for cdo/nco on Euler. +# Adjust these to your environment/stack. +module load stack/2024-06 || true +module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 || true + +# --------------------------------------------------------------------- +# Inputs (from cfg) +# --------------------------------------------------------------------- +ERA5_DIR="{cfg.era5_dir}" +ERA5_ML="{cfg.era5_ml_filename}" +ERA5_SFC="{cfg.era5_sfc_filename}" +# Replace {ymd} placeholder using values prepared in era5_ic.py +ERA5_ML="${{ERA5_ML/\{ymd\}/{cfg.era5_ymd}}}" +ERA5_SFC="${{ERA5_SFC/\{ymd\}/{cfg.era5_ymd}}}" +PARTAB="{cfg.era5_partab}" +GRID_TRI="{cfg.input_files_scratch_dynamics_grid_filename}" +EXTPAR="{cfg.input_files_scratch_extpar_filename}" +OUTFILE="{inidata_filename}" + +# --------------------------------------------------------------------- +# Working directory cleanup +# --------------------------------------------------------------------- +work="{cfg.icon_work}/era5_ic_work" +mkdir -p "$work" +cd "$work" + +# --------------------------------------------------------------------- +# 1) GRIB preprocessing: pick first timestep and convert to NetCDF +# --------------------------------------------------------------------- +# +# Note: your colleague used splitsel,1; keep it to ensure we only have t0. +cdo splitsel,1 "${{ERA5_DIR}}/${{ERA5_ML}}" era5_ml_ +cdo splitsel,1 "${{ERA5_DIR}}/${{ERA5_SFC}}" era5_sfc_ + +# Find the produced split files (avoid hardcoding the exact suffix) +ml_grb="$(ls -1 era5_ml_* | head -n 1)" +sfc_grb="$(ls -1 era5_sfc_* | head -n 1)" +cdo -t ecmwf -f nc copy "$ml_grb" era5_ml.nc +cdo -t ecmwf -f nc copy "$sfc_grb" era5_sfc.nc +cdo merge era5_ml.nc era5_sfc.nc era5_original.nc + +# Rename variables / metadata to ICON-consistent naming via partab +# (Your partab is the "contract" between ERA5 and ICON naming expectations.) +cdo setpartabn,"$PARTAB",convert era5_original.nc tmp.nc + +# Order variables (helps reproducibility and easier diffs) +ncks tmp.nc data_in.nc +rm -f tmp.nc era5_ml.nc era5_sfc.nc era5_original.nc "$ml_grb" "$sfc_grb" + +# --------------------------------------------------------------------- +# 2) Build the ICON triangular grid description for CDO remapping +# --------------------------------------------------------------------- +cdo -s selgrid,1 "$GRID_TRI" triangular-grid.nc + +# --------------------------------------------------------------------- +# 3) Land/sea-aware remapping for sensitive surface variables +# --------------------------------------------------------------------- +# +# Input land-sea mask from renamed ERA5 data +cdo selname,LSM data_in.nc LSM_in.nc +ncrename -h -v LSM,FR_LAND LSM_in.nc + +# Output land fraction from EXTPAR +cdo selname,FR_LAND "$EXTPAR" LSM_out_tmp.nc + +# Add time dimension and align time coordinate +ncecat -O -u time LSM_out_tmp.nc LSM_out_tmp.nc +ncks -h -A -v time LSM_in.nc LSM_out_tmp.nc + +# Build land/ocean masks (input and output) +cdo -L setctomiss,0. -ltc,0.5 LSM_in.nc oceanmask_in.nc +cdo -L setctomiss,0. -gec,0.5 LSM_in.nc landmask_in.nc +cdo -L setctomiss,0. -ltc,0.5 LSM_out_tmp.nc oceanmask_out.nc +cdo -L setctomiss,0. -gec,0.5 LSM_out_tmp.nc landmask_out.nc +cdo setrtoc2,0.5,1.0,1,0 LSM_out_tmp.nc LSM_out.nc +rm -f LSM_in.nc LSM_out_tmp.nc + +# Variables defined only on sea +ncks -h -v SST,CI data_in.nc datasea_in.nc + +# Variables defined on both but should not mix land/sea +ncks -h -v SKT,STL1,STL2,STL3,STL4,ALB_SNOW,W_SNOW,T_SNOW data_in.nc dataland_in.nc + +# Ocean part: mask -> fill -> remap -> unmask +cdo div dataland_in.nc oceanmask_in.nc tmp1_land.nc +cdo div datasea_in.nc oceanmask_in.nc tmp1_sea.nc +cdo setmisstodis tmp1_land.nc tmp2_land.nc +cdo setmisstodis tmp1_sea.nc tmp2_sea.nc +cdo remapdis,triangular-grid.nc tmp2_land.nc tmp3_land.nc +cdo remapdis,triangular-grid.nc tmp2_sea.nc tmp3_sea.nc +cdo div tmp3_land.nc oceanmask_out.nc dataland_ocean_out.nc +cdo div tmp3_sea.nc oceanmask_out.nc datasea_ocean_out.nc +rm -f tmp*_land.nc tmp*_sea.nc oceanmask_in.nc oceanmask_out.nc + +# Land part: mask -> fill -> remap -> unmask +cdo div dataland_in.nc landmask_in.nc tmp1.nc +cdo setmisstodis tmp1.nc tmp2.nc +cdo remapdis,triangular-grid.nc tmp2.nc tmp3.nc +cdo div tmp3.nc landmask_out.nc dataland_land_out.nc +rm -f tmp*.nc landmask_in.nc landmask_out.nc dataland_in.nc datasea_in.nc + +# Merge land+ocean contributions +cdo ifthenelse LSM_out.nc dataland_land_out.nc dataland_ocean_out.nc dataland_out.nc +rm -f dataland_ocean_out.nc dataland_land_out.nc + +# Remap all remaining variables together +ncks -h -x -v SKT,STL1,STL2,STL3,STL4,SMIL1,SMIL2,SMIL3,SMIL4,ALB_SNOW,W_SNOW,T_SNOW,SST,CI,LSM data_in.nc datarest_in.nc +cdo -s remapdis,triangular-grid.nc datarest_in.nc era5_final.nc +rm -f datarest_in.nc + +# Fill missing SST/CI after remap (sea-only fields) +cdo setmisstodis -selname,SST,CI datasea_ocean_out.nc datasea_ocean_out_filled.nc +rm -f datasea_ocean_out.nc + +# Merge special remapped variables + land fraction (renamed back to LSM) +ncks -h -A dataland_out.nc era5_final.nc +ncks -h -A datasea_ocean_out_filled.nc era5_final.nc +ncks -h -A -v FR_LAND LSM_out.nc era5_final.nc +ncrename -h -v FR_LAND,LSM era5_final.nc +rm -f LSM_out.nc dataland_out.nc datasea_ocean_out_filled.nc + +# --------------------------------------------------------------------- +# 4) Soil moisture index conversion (ERA5 SWVL -> ICON-style SMIL) +# --------------------------------------------------------------------- +# Extract soil moisture and soil type +ncks -h -v SMIL1,SMIL2,SMIL3,SMIL4,SLT data_in.nc swvl.nc +rm -f data_in.nc + +# IFS soil constants (documented in ERA5 data documentation) +wiltingp=(0 0.059 0.151 0.133 0.279 0.335 0.267 0.151) +fieldcap=(0 0.244 0.347 0.383 0.448 0.541 0.663 0.347) +smi_equation="" +for ilev in {1..4}; do + smi_equation="${smi_equation}SMIL${ilev}=(SMIL${ilev}-${wiltingp[1]})/(${fieldcap[1]}-${wiltingp[1]})*(SLT==1)" + for ist in {2..7}; do + smi_equation="${smi_equation}+(SMIL${ilev}-${wiltingp[$ist]})/(${fieldcap[$ist]}-${wiltingp[$ist]})*(SLT==${ist})" + done + smi_equation="${smi_equation};" +done +cdo expr,"${smi_equation}" swvl.nc smil_in.nc +rm -f swvl.nc + +# Remap SMIL to triangular grid and overwrite +cdo -s remapdis,triangular-grid.nc smil_in.nc smil_out.nc +ncks -A -v SMIL1,SMIL2,SMIL3,SMIL4 smil_out.nc era5_final.nc +rm -f smil_in.nc smil_out.nc + +# --------------------------------------------------------------------- +# 5) Create LNPS (log surface pressure) and finalize dimensions +# --------------------------------------------------------------------- +cdo expr,'LNPS=ln(PS);' era5_final.nc tmp.nc +ncks -A -v LNPS tmp.nc era5_final.nc +rm -f tmp.nc + +# ICON conventions: rename dimensions +ncrename -h -d cell,ncells era5_final.nc +ncrename -h -d nv,vertices era5_final.nc + +# Write final IC file to the exact path ICON will read later +mkdir -p "$(dirname "$OUTFILE")" +ncks era5_final.nc "$OUTFILE" + +# cleanup +rm -f era5_final.nc triangular-grid.nc +echo "Wrote ICON initial condition file: $OUTFILE" From dc7e7427798e3102c90e174ca22e549b5f81f7d1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 14 Jan 2026 15:35:13 +0000 Subject: [PATCH 12/35] GitHub Action: Apply Pep8-formatting --- jobs/era5_ic.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/jobs/era5_ic.py b/jobs/era5_ic.py index 0ecd6ff2..a6b51c05 100644 --- a/jobs/era5_ic.py +++ b/jobs/era5_ic.py @@ -1,6 +1,5 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- - """ era5_ic.py Processing-chain job that generates ICON initial conditions (IC) from ERA5 input. @@ -19,8 +18,10 @@ import logging from pathlib import Path from . import tools, prepare_icon + BASIC_PYTHON_JOB = True + def _compute_inidata_filename(cfg) -> Path: """ Replicate the same IC filename logic used by jobs/icon.py, @@ -39,6 +40,7 @@ def _compute_inidata_filename(cfg) -> Path: cfg.startdate_sim.strftime(cfg.meteo['prefix'] + cfg.meteo['nameformat']) + '.nc') + def main(cfg): """ 1) Prepare standard ICON paths (same helper as other jobs) @@ -53,7 +55,8 @@ def main(cfg): prepare_icon.set_cfg_variables(cfg) tools.change_logfile(cfg.logfile) - logging.info("Generate global ICON initial conditions from ERA5 (IC only).") + logging.info( + "Generate global ICON initial conditions from ERA5 (IC only).") # Ensure run + icbc directories exist (prepare_icon usually created them, # but being explicit makes the job robust if invoked in isolation). @@ -61,7 +64,7 @@ def main(cfg): tools.create_dir(cfg.icon_input_icbc, "icon_input_icbc") # Useful formatted dates for the template (avoid bash date gymnastics) - cfg.era5_ymd = cfg.startdate_sim.strftime('%Y-%m-%d') # e.g. 2021-01-01 + cfg.era5_ymd = cfg.startdate_sim.strftime('%Y-%m-%d') # e.g. 2021-01-01 cfg.era5_yyyymmddhh = cfg.startdate_sim.strftime('%Y%m%d%H') # 2021010100 # Compute the *exact* file that ICON will later read @@ -69,7 +72,8 @@ def main(cfg): # Case template name (kept configurable) # Put in config.yaml: era5_ic_runjob_filename: era5_ic_runjob.cfg - template_name = getattr(cfg, 'era5_ic_runjob_filename', 'era5_ic_runjob.cfg') + template_name = getattr(cfg, 'era5_ic_runjob_filename', + 'era5_ic_runjob.cfg') template = (cfg.case_path / template_name).read_text() script_str = template.format( cfg=cfg, From 7b9ef4cf867d76820711583581effa5bc5eadc19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 16:37:06 +0100 Subject: [PATCH 13/35] Remove setup spack stage (included in build) --- jenkins/Jenkinsfile | 11 ---------- jenkins/scripts/setup-spack.sh | 38 ---------------------------------- 2 files changed, 49 deletions(-) delete mode 100755 jenkins/scripts/setup-spack.sh diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index ba296f34..b34b0b64 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -8,17 +8,6 @@ pipeline { } } stages { - stage('Setup spack') { - steps { - sh './jenkins/scripts/setup-spack.sh' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } - } - } stage('Preparation') { parallel { stage('Setup miniconda') { diff --git a/jenkins/scripts/setup-spack.sh b/jenkins/scripts/setup-spack.sh deleted file mode 100755 index ccc10fde..00000000 --- a/jenkins/scripts/setup-spack.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/bash - -set -e -x - -source jenkins/scripts/common.sh - -# Check if script is called correctly -[[ $(git rev-parse --show-toplevel 2>/dev/null) = $(pwd) ]] || error "$0 not launched from toplevel of repository" - -SPACK_TAG_COSMO=v0.18.1.12 - -if [[ $(hostname) == eu-* ]]; then - source /cluster/apps/local/env2lmod.sh - module load git - git clone --depth 1 git@gitlab.dkrz.de:icon/icon-model.git icon-tag - SPACK_TAG=`cat icon-tag/config/ethz/SPACK_TAG_EULER` - rm -fr icon-tag -elif [[ $(hostname) == santis* ]]; then - git clone --depth 1 git@gitlab.dkrz.de:icon/icon-model.git icon-tag - SPACK_TAG=`cat icon-tag/config/cscs/SPACK_TAG_SANTIS` - rm -fr icon-tag -else - error "Unknown hostname: $(hostname)" -fi - -GIT_REMOTE=https://github.com/C2SM/spack-c2sm.git - -rm -fr ext/spack-c2sm - -pushd ext - -# Clone Spack for ICON -git clone --depth 1 --recurse-submodules --shallow-submodules -b ${SPACK_TAG} ${GIT_REMOTE} spack-c2sm - -# Clone Spack for COSMO-GHG -git clone --depth 1 --recurse-submodules --shallow-submodules -b ${SPACK_TAG_COSMO} ${GIT_REMOTE} spack-c2sm-cosmo - -popd From 657dd2ca63b23e205ab4a6f56a128a8d5f0e5a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 16:42:00 +0100 Subject: [PATCH 14/35] Initialize era5_ic job --- jobs/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/jobs/__init__.py b/jobs/__init__.py index a3d75541..393e0ffb 100644 --- a/jobs/__init__.py +++ b/jobs/__init__.py @@ -5,6 +5,7 @@ from . import check_output from . import cosmo from . import emissions +from . import era5_ic from . import icon from . import icontools from . import int2lm From 03b5b10321df9f4affe95e7104825eb3095d1967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 16:46:23 +0100 Subject: [PATCH 15/35] Add global_nudging parameter --- cases/icon-test-euler/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/cases/icon-test-euler/config.yaml b/cases/icon-test-euler/config.yaml index 35dffc72..19da7857 100644 --- a/cases/icon-test-euler/config.yaml +++ b/cases/icon-test-euler/config.yaml @@ -18,6 +18,7 @@ era5: dir: ./input/era5 ml_filename: "era5_ml_{ymd}.grib" sfc_filename: "era5_surf_{ymd}.grib" + global_nudging: False era5_partab: ./cases/icon-euler-test/partab_era5_to_icon.txt era5_ic_runjob_filename: era5_ic_runjob.cfg From e9c7fe03ed3cfd7610bf754a311b0bf6a0a23b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 14 Jan 2026 16:53:01 +0100 Subject: [PATCH 16/35] Restructuring config --- cases/icon-test-euler/config.yaml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cases/icon-test-euler/config.yaml b/cases/icon-test-euler/config.yaml index 19da7857..f02fb174 100644 --- a/cases/icon-test-euler/config.yaml +++ b/cases/icon-test-euler/config.yaml @@ -8,6 +8,14 @@ ntasks_per_node: 12 restart_step: PT6H startdate: 2018-01-01T00:00:00Z enddate: 2018-01-01T12:00:00Z +era5_partab: ./cases/icon-euler-test/partab_era5_to_icon.txt +era5_ic_runjob_filename: era5_ic_runjob.cfg +inidata_prefix: "era5_init_R02B05_" +inidata_nameformat: "%Y%m%d%H" +inidata_filename_suffix: ".nc" +output_filename: icon-test-euler +filename_format: _DOM_ +lateral_boundary_grid_order: lateral_boundary walltime: prepare_icon: "00:10:00" @@ -20,12 +28,6 @@ era5: sfc_filename: "era5_surf_{ymd}.grib" global_nudging: False -era5_partab: ./cases/icon-euler-test/partab_era5_to_icon.txt -era5_ic_runjob_filename: era5_ic_runjob.cfg -inidata_prefix: "era5_init_R02B05_" -inidata_nameformat: "%Y%m%d%H" -inidata_filename_suffix: ".nc" - meteo: dir: ./input/meteo prefix: ifs_ From 78058e1058f0b6472ffebf6561853b2773932a63 Mon Sep 17 00:00:00 2001 From: Laurenz Roither Date: Mon, 16 Feb 2026 14:47:38 +0100 Subject: [PATCH 17/35] Global R02B07 ICON test simulation initialized from era5 grib files from cdsapi. namelist setup is very similar to dyamond, preprocessing of initial conditions is supplied, minimal output postprocessing are handled. bc files need to be gathered and correctly linked (see icon_runjob_parent_global.cfg) --- .../README.md | 8 + .../config.yaml | 81 ++++ .../load_links.txt | 37 ++ .../tables/mypartab | 117 ++++++ .../tables/partab_era5_to_icon.txt | 117 ++++++ .../templates/era5_ic_runjob.cfg | 202 +++++++++ .../templates/icon_runjob_parent_global.cfg | 387 ++++++++++++++++++ .../varlists/parent_eval_hourly_pl.txt | 6 + .../varlists/parent_eval_hourly_sfc.txt | 5 + .../varlists/parent_native_3d_1D_ml.txt | 12 + config.py | 4 +- jobs/era5_ic.py | 21 + jobs/prepare_icon.py | 14 +- workflows.yaml | 43 ++ 14 files changed, 1051 insertions(+), 3 deletions(-) create mode 100644 cases/parent-global-r2b7-era5-update-euler/README.md create mode 100644 cases/parent-global-r2b7-era5-update-euler/config.yaml create mode 100644 cases/parent-global-r2b7-era5-update-euler/load_links.txt create mode 100644 cases/parent-global-r2b7-era5-update-euler/tables/mypartab create mode 100644 cases/parent-global-r2b7-era5-update-euler/tables/partab_era5_to_icon.txt create mode 100644 cases/parent-global-r2b7-era5-update-euler/templates/era5_ic_runjob.cfg create mode 100644 cases/parent-global-r2b7-era5-update-euler/templates/icon_runjob_parent_global.cfg create mode 100644 cases/parent-global-r2b7-era5-update-euler/varlists/parent_eval_hourly_pl.txt create mode 100644 cases/parent-global-r2b7-era5-update-euler/varlists/parent_eval_hourly_sfc.txt create mode 100644 cases/parent-global-r2b7-era5-update-euler/varlists/parent_native_3d_1D_ml.txt diff --git a/cases/parent-global-r2b7-era5-update-euler/README.md b/cases/parent-global-r2b7-era5-update-euler/README.md new file mode 100644 index 00000000..8ae36cd5 --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/README.md @@ -0,0 +1,8 @@ +# Parent global R2B7 ERA5 case (scaffold) + +This case will: +- stage static ICON inputs (grid/extpar/radiation tables) +- generate ERA5-based initial conditions on R2B7 +- run a global NWP-style ICON simulation +- write hourly evaluation outputs +- write daily restarts (at least for 2013-05-05 .. 2013-05-22) diff --git a/cases/parent-global-r2b7-era5-update-euler/config.yaml b/cases/parent-global-r2b7-era5-update-euler/config.yaml new file mode 100644 index 00000000..e142ef0c --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/config.yaml @@ -0,0 +1,81 @@ +# Parent global run: ERA5 IC -> ICON R2B7 (global, no LBC) +workflow: icon-global-era5-parent-r2b7-nosst + +# Simulation window +startdate: 2013-05-25T00:00:00Z +enddate: 2013-05-25T06:00:00Z + +# HPC settings +constraint: EPYC_7H12 +compute_queue: normal.4h +run_on: cpu +ntasks_per_node: 128 + +# Restart cadence (ISO-8601 duration). P1D == PT24H. +restart_step: PT6H +# For the very first parent run from ERA5, lrestart must be false. +# (later chunks can set this automatically via the chain feature "restart") +lrestart: '.FALSE.' + +walltime: + prepare_icon: "00:10:00" + era5_ic: "00:40:00" + icon: "02:00:00" + +# ------------------------------------------------------------------- +# ERA5 inputs for the era5_ic job (MATCHES jobs/era5_ic.py EXPECTATIONS) +# ------------------------------------------------------------------- +era5_dir: /cluster/work/climate/lroither/icon_c2sm/icon_era5_global/era5_raw +era5_ml_filename: "era5_ml_{ymd}.grib" +era5_sfc_filename: "era5_surf_{ymd}.grib" + +# Partab: case-relative path (do NOT hardcode /cases/... here) +era5_partab: tables/partab_era5_to_icon.txt + +# Script template used by jobs/era5_ic.py (path relative to case_path) +era5_ic_runjob_filename: templates/era5_ic_runjob.cfg + +# ------------------------------------------------------------------- +# IC naming contract used by jobs/icon.py when generating inidata filename +# (era5_ic_runjob must write exactly this file) +# ------------------------------------------------------------------- +inidata_prefix: "era5_init_R2B7_" +inidata_nameformat: "%Y%m%d%H" +inidata_filename_suffix: ".nc" + +# ------------------------------------------------------------------- +# Files staged by prepare_icon into icon/input and referenced by runjobs +# Use case-relative paths so the case is self-contained. +# ------------------------------------------------------------------- +input_files: + dynamics_grid_filename: ../../input/icon/grid/zonda_output_I/I_DOM01.nc + radiation_grid_filename: ../../input/icon/grid/zonda_output_I/I_DOM01.parent.nc + extpar_filename: ../../input/icon/grid/zonda_output_I/I_DOM01_external_parameter.nc + + # radiation coeffs + lrtm_filename: /cluster/work/climate/lroither/icon_c2sm/icon/data/rrtmg_lw.nc + cldopt_filename: /cluster/work/climate/lroither/icon_c2sm/icon/data/ECHAM6_CldOptProps.nc + map_file_ana: /cluster/work/climate/lroither/icon_c2sm/icon/run/ana_varnames_map_file.txt + + +ecrad_data_path: /cluster/work/climate/lroither/icon_c2sm/icon/externals/ecrad/data +icon_data_path: /cluster/work/climate/lroither/icon_c2sm/icon/data +start_year: 2013 + +output_filename: "parent_R2B7" +parent_eval_reg_lon_def: "-179.875,0.25,179.875" +parent_eval_reg_lat_def: "89.875,-0.25,-89.875" +parent_eval_p_levels_pa: "100000,92500,85000,70000,50000,30000,20000,10000" + + +# ------------------------------------------------------------------- +# ICON execution config +# runjob_filename is case-relative (recommended). +# ------------------------------------------------------------------- +icon: + binary_file: /cluster/work/climate/lroither/icon_c2sm/icon/bin/icon + runjob_filename: templates/icon_runjob_parent_global.cfg + np_tot: 512 + np_io: 4 + np_restart: 4 + np_prefetch: 0 diff --git a/cases/parent-global-r2b7-era5-update-euler/load_links.txt b/cases/parent-global-r2b7-era5-update-euler/load_links.txt new file mode 100644 index 00000000..29db256d --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/load_links.txt @@ -0,0 +1,37 @@ +in /processing-chain/work/CASE/YYYYMMDD_CHUNK/icon/run do this: + +# Base dirs you showed +ECRAD=/cluster/work/climate/lroither/icon_c2sm/icon/externals/ecrad/data +ICONDATA=/cluster/work/climate/lroither/icon_c2sm/icon/data + +# Kinne (coa) +ln -sf $ECRAD/bc_aeropt_kinne_sw_b14_coa.nc bc_aeropt_kinne_sw_b14_coa.nc +ln -sf $ECRAD/bc_aeropt_kinne_lw_b16_coa.nc bc_aeropt_kinne_lw_b16_coa.nc + +# Kinne (fin) -> ICON expects the generic name without year +ln -sf $ECRAD/bc_aeropt_kinne_sw_b14_fin_2013.nc bc_aeropt_kinne_sw_b14_fin.nc + +# CMIP6 volcanic aerosols for 2013 +ln -sf $ECRAD/bc_aeropt_cmip6_volc_lw_b16_sw_b14_2013.nc bc_aeropt_cmip6_volc_lw_b16_sw_b14_2013.nc + +# MACv2 dataset +ln -sf $ICONDATA/MACv2.0-SP_v1.nc MACv2.0-SP_v1.nc + +# bc_ozone dataset +ln -sf $ECRAD/bc_ozone_ssp370_2013.nc bc_ozone_2013.nc + +then check: + +ls -l bc_aeropt_kinne_sw_b14_coa.nc \ + bc_aeropt_kinne_lw_b16_coa.nc \ + bc_aeropt_kinne_sw_b14_fin.nc \ + bc_aeropt_cmip6_volc_lw_b16_sw_b14_2013.nc \ + MACv2.0-SP_v1.nc + +# and actually test file exists behind link +for f in bc_aeropt_kinne_sw_b14_coa.nc bc_aeropt_kinne_lw_b16_coa.nc bc_aeropt_kinne_sw_b14_fin.nc \ + bc_aeropt_cmip6_volc_lw_b16_sw_b14_2013.nc MACv2.0-SP_v1.nc +do + test -r "$f" && echo "OK: $f" || echo "MISSING: $f" +done + diff --git a/cases/parent-global-r2b7-era5-update-euler/tables/mypartab b/cases/parent-global-r2b7-era5-update-euler/tables/mypartab new file mode 100644 index 00000000..8944c095 --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/tables/mypartab @@ -0,0 +1,117 @@ +¶meter ! temperature +name = "t" +out_name = "T" +/ +¶meter ! horiz. wind comp. u +name = "u" +out_name = "U" +/ +¶meter ! horiz. wind comp. u +name = "v" +out_name = "V" +/ +¶meter ! vertical velocity +name = "w" +out_name = "W" +/ +¶meter ! specific humidity +name = "q" +out_name = "QV" +/ +¶meter ! cloud liquid water content +name = "clwc" +out_name = "QC" +/ +¶meter ! cloud ice water content +name = "ciwc" +out_name = "QI" +/ +¶meter ! rain water content +name = "crwc" +out_name = "QR" +/ +¶meter ! snow water content +name = "cswc" +out_name = "QS" +/ +¶meter ! snow temperature +name = "TSN" +out_name = "T_SNOW" +/ +¶meter ! water content of snow +name = "SD" +out_name = "W_SNOW" +/ +¶meter ! density of snow +name = "RSN" +out_name = "RHO_SNOW" +/ +¶meter ! snow albedo +name = "ASN" +out_name = "ALB_SNOW" +/ +¶meter ! skin temperature +name = "SKT" +out_name = "SKT" +/ +¶meter ! sea surface temperature +name = "SSTK" +out_name = "SST" +/ +¶meter ! soil temperature level 1 +name = "STL1" +out_name = "STL1" +/ +¶meter ! soil temperature level 2 +name = "STL2" +out_name = "STL2" +/ +¶meter ! soil temperature level 3 +name = "STL3" +out_name = "STL3" +/ +¶meter ! soil temperature level 4 +name = "STL4" +out_name = "STL4" +/ +¶meter ! sea-ice cover +name = "CI" +out_name = "CI" +/ +¶meter ! water cont. of interception storage +name = "SRC" +out_name = "W_I" +/ +¶meter ! Land/sea mask +name = "LSM" +out_name = "LSM" +/ +¶meter ! soil moisture index layer 1 +name = "SWVL1" +out_name = "SMIL1" +/ +¶meter ! soil moisture index layer 2 +name = "SWVL2" +out_name = "SMIL2" +/ +¶meter ! soil moisture index layer 3 +name = "SWVL3" +out_name = "SMIL3" +/ +¶meter ! soil moisture index layer 4 +name = "SWVL4" +out_name = "SMIL4" +/ +¶meter ! logarithm of surface pressure +name = "LNSP" +out_name = "LNPS" +/ +¶meter ! logarithm of surface pressure +name = "SP" +out_name = "PS" +/ +¶meter +name = "Z" +out_name = "GEOSP" +/ + diff --git a/cases/parent-global-r2b7-era5-update-euler/tables/partab_era5_to_icon.txt b/cases/parent-global-r2b7-era5-update-euler/tables/partab_era5_to_icon.txt new file mode 100644 index 00000000..8944c095 --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/tables/partab_era5_to_icon.txt @@ -0,0 +1,117 @@ +¶meter ! temperature +name = "t" +out_name = "T" +/ +¶meter ! horiz. wind comp. u +name = "u" +out_name = "U" +/ +¶meter ! horiz. wind comp. u +name = "v" +out_name = "V" +/ +¶meter ! vertical velocity +name = "w" +out_name = "W" +/ +¶meter ! specific humidity +name = "q" +out_name = "QV" +/ +¶meter ! cloud liquid water content +name = "clwc" +out_name = "QC" +/ +¶meter ! cloud ice water content +name = "ciwc" +out_name = "QI" +/ +¶meter ! rain water content +name = "crwc" +out_name = "QR" +/ +¶meter ! snow water content +name = "cswc" +out_name = "QS" +/ +¶meter ! snow temperature +name = "TSN" +out_name = "T_SNOW" +/ +¶meter ! water content of snow +name = "SD" +out_name = "W_SNOW" +/ +¶meter ! density of snow +name = "RSN" +out_name = "RHO_SNOW" +/ +¶meter ! snow albedo +name = "ASN" +out_name = "ALB_SNOW" +/ +¶meter ! skin temperature +name = "SKT" +out_name = "SKT" +/ +¶meter ! sea surface temperature +name = "SSTK" +out_name = "SST" +/ +¶meter ! soil temperature level 1 +name = "STL1" +out_name = "STL1" +/ +¶meter ! soil temperature level 2 +name = "STL2" +out_name = "STL2" +/ +¶meter ! soil temperature level 3 +name = "STL3" +out_name = "STL3" +/ +¶meter ! soil temperature level 4 +name = "STL4" +out_name = "STL4" +/ +¶meter ! sea-ice cover +name = "CI" +out_name = "CI" +/ +¶meter ! water cont. of interception storage +name = "SRC" +out_name = "W_I" +/ +¶meter ! Land/sea mask +name = "LSM" +out_name = "LSM" +/ +¶meter ! soil moisture index layer 1 +name = "SWVL1" +out_name = "SMIL1" +/ +¶meter ! soil moisture index layer 2 +name = "SWVL2" +out_name = "SMIL2" +/ +¶meter ! soil moisture index layer 3 +name = "SWVL3" +out_name = "SMIL3" +/ +¶meter ! soil moisture index layer 4 +name = "SWVL4" +out_name = "SMIL4" +/ +¶meter ! logarithm of surface pressure +name = "LNSP" +out_name = "LNPS" +/ +¶meter ! logarithm of surface pressure +name = "SP" +out_name = "PS" +/ +¶meter +name = "Z" +out_name = "GEOSP" +/ + diff --git a/cases/parent-global-r2b7-era5-update-euler/templates/era5_ic_runjob.cfg b/cases/parent-global-r2b7-era5-update-euler/templates/era5_ic_runjob.cfg new file mode 100644 index 00000000..ca8ae5d6 --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/templates/era5_ic_runjob.cfg @@ -0,0 +1,202 @@ +#!/usr/bin/env bash +#SBATCH --job-name=era5_ic_{cfg.casename}_{cfg.era5_yyyymmddhh} +#SBATCH --time={cfg.walltime_era5_ic} +#SBATCH --partition={cfg.compute_queue} +#SBATCH --constraint={cfg.constraint} +#SBATCH --ntasks=1 +#SBATCH --output={cfg.logfile} +#SBATCH --open-mode=append +#SBATCH --chdir={cfg.icon_work} + +# --------------------------------------------------------------------- +# ERA5 -> ICON initial conditions (GLOBAL, IC only) +# +# This script is submitted by jobs/era5_ic.py. +# It MUST write the final IC file exactly to: +# {inidata_filename} +# --------------------------------------------------------------------- + +set -euo pipefail +set -x +ulimit -s unlimited + + +# Load modules if available (safe on Euler; no hard failure) +module load stack/2024-06 || true +module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 || true +export CDO_FILETYPE=nc2 + + +# --------------------------------------------------------------------- +# Inputs (from cfg) +# --------------------------------------------------------------------- +ERA5_DIR="{cfg.era5_dir}" +ERA5_ML="{cfg.era5_ml_file}" +ERA5_SFC="{cfg.era5_sfc_file}" + +PARTAB="{cfg.era5_partab_path}" + +GRID_TRI="{cfg.input_files_scratch_dynamics_grid_filename}" +EXTPAR="{cfg.input_files_scratch_extpar_filename}" + +OUTFILE="{inidata_filename}" + +work="{cfg.icon_work}/era5_ic_work" +mkdir -p "$work" +cd "$work" + +# --------------------------------------------------------------------- +# 1) GRIB preprocessing: pick first timestep and convert to NetCDF +# --------------------------------------------------------------------- +cdo splitsel,1 "${{ERA5_DIR}}/${{ERA5_ML}}" era5_ml_ +cdo splitsel,1 "${{ERA5_DIR}}/${{ERA5_SFC}}" era5_sfc_ + +ml_grb="$(ls -1 era5_ml_* | head -n 1)" +sfc_grb="$(ls -1 era5_sfc_* | head -n 1)" + +cdo -t ecmwf -f nc copy "$ml_grb" era5_ml.nc +cdo -t ecmwf -f nc copy "$sfc_grb" era5_sfc.nc + +cdo merge era5_ml.nc era5_sfc.nc era5_original.nc + +# Rename variables to ICON naming using partab +cdo setpartabn,"$PARTAB",convert era5_original.nc tmp.nc + +# Stable var order +ncks tmp.nc data_in.nc + +rm -f tmp.nc era5_ml.nc era5_sfc.nc era5_original.nc "$ml_grb" "$sfc_grb" + +# --------------------------------------------------------------------- +# 2) Triangular grid file for CDO remapping +# --------------------------------------------------------------------- +cdo -s selgrid,1 "$GRID_TRI" triangular-grid.nc + +# --------------------------------------------------------------------- +# 3) Land/sea-aware remapping for surface variables +# --------------------------------------------------------------------- +cdo selname,LSM data_in.nc LSM_in.nc +ncrename -h -v LSM,FR_LAND LSM_in.nc + +cdo selname,FR_LAND "$EXTPAR" LSM_out_tmp.nc +ncecat -O -u time LSM_out_tmp.nc LSM_out_tmp.nc +ncks -h -A -v time LSM_in.nc LSM_out_tmp.nc + +# Build 0/1 masks explicitly (robust across CDO/HDF5 quirks) +cdo -L expr,'FR_LAND=FR_LAND<0.5 ? 1 : 0;' LSM_in.nc oceanmask_in.nc +cdo -L expr,'FR_LAND=FR_LAND>=0.5 ? 1 : 0;' LSM_in.nc landmask_in.nc +cdo -L expr,'FR_LAND=FR_LAND<0.5 ? 1 : 0;' LSM_out_tmp.nc oceanmask_out.nc +cdo -L expr,'FR_LAND=FR_LAND>=0.5 ? 1 : 0;' LSM_out_tmp.nc landmask_out.nc +if [ ! -s oceanmask_in.nc ]; then + echo "ERROR: oceanmask_in.nc not created" + exit 1 +fi +if [ ! -s landmask_in.nc ]; then + echo "ERROR: landmask_in.nc not created" + exit 1 +fi +if [ ! -s oceanmask_out.nc ]; then + echo "ERROR: oceanmask_out.nc not created" + exit 1 +fi +if [ ! -s landmask_out.nc ]; then + echo "ERROR: landmask_out.nc not created" + exit 1 +fi + +cdo setrtoc2,0.5,1.0,1,0 LSM_out_tmp.nc LSM_out.nc +rm -f LSM_in.nc LSM_out_tmp.nc + +ncks -h -v SST,CI data_in.nc datasea_in.nc +ncks -h -v SKT,STL1,STL2,STL3,STL4,ALB_SNOW,W_SNOW,T_SNOW data_in.nc dataland_in.nc + +# ocean masked remap +cdo div dataland_in.nc oceanmask_in.nc tmp1_land.nc +cdo div datasea_in.nc oceanmask_in.nc tmp1_sea.nc +cdo setmisstodis tmp1_land.nc tmp2_land.nc +cdo setmisstodis tmp1_sea.nc tmp2_sea.nc +cdo remapdis,triangular-grid.nc tmp2_land.nc tmp3_land.nc +cdo remapdis,triangular-grid.nc tmp2_sea.nc tmp3_sea.nc +cdo div tmp3_land.nc oceanmask_out.nc dataland_ocean_out.nc +cdo div tmp3_sea.nc oceanmask_out.nc datasea_ocean_out.nc +rm -f tmp*_land.nc tmp*_sea.nc oceanmask_in.nc oceanmask_out.nc + +# land masked remap +cdo div dataland_in.nc landmask_in.nc tmp1.nc +cdo setmisstodis tmp1.nc tmp2.nc +cdo remapdis,triangular-grid.nc tmp2.nc tmp3.nc +cdo div tmp3.nc landmask_out.nc dataland_land_out.nc +rm -f tmp*.nc landmask_in.nc landmask_out.nc dataland_in.nc datasea_in.nc + +cdo ifthenelse LSM_out.nc dataland_land_out.nc dataland_ocean_out.nc dataland_out.nc +rm -f dataland_ocean_out.nc dataland_land_out.nc + +# Remap the rest +ncks -h -x -v SKT,STL1,STL2,STL3,STL4,SMIL1,SMIL2,SMIL3,SMIL4,ALB_SNOW,W_SNOW,T_SNOW,SST,CI,LSM data_in.nc datarest_in.nc +cdo -s remapdis,triangular-grid.nc datarest_in.nc era5_final.nc +rm -f datarest_in.nc + +# Fill missing SST/CI +rm -f sst_ci.nc datasea_ocean_out_filled.nc +cdo -s selname,SST,CI datasea_ocean_out.nc sst_ci.nc +cdo -s setmisstodis sst_ci.nc datasea_ocean_out_filled.nc +rm -f sst_ci.nc +test -s datasea_ocean_out_filled.nc + +rm -f datasea_ocean_out.nc + +# Merge special variables + land fraction +ncks -h -A dataland_out.nc era5_final.nc +ncks -h -A datasea_ocean_out_filled.nc era5_final.nc +ncks -h -A -v FR_LAND LSM_out.nc era5_final.nc +ncrename -h -v FR_LAND,LSM era5_final.nc +rm -f LSM_out.nc dataland_out.nc datasea_ocean_out_filled.nc + +# --------------------------------------------------------------------- +# 4) Soil moisture index conversion (SMIL + SLT required) +# --------------------------------------------------------------------- +ncks -h -v SMIL1,SMIL2,SMIL3,SMIL4,SLT data_in.nc swvl.nc +rm -f data_in.nc + +wiltingp=(0 0.059 0.151 0.133 0.279 0.335 0.267 0.151) +fieldcap=(0 0.244 0.347 0.383 0.448 0.541 0.663 0.347) + +smi_equation="" +for ilev in {{1..4}}; do + smi_equation="${{smi_equation}}SMIL${{ilev}}=(SMIL${{ilev}}-${{wiltingp[1]}})/(${{fieldcap[1]}}-${{wiltingp[1]}})*(SLT==1)" + for ist in {{2..7}}; do + smi_equation="${{smi_equation}}+(SMIL${{ilev}}-${{wiltingp[$ist]}})/(${{fieldcap[$ist]}}-${{wiltingp[$ist]}})*(SLT==${{ist}})" + done + smi_equation="${{smi_equation}};" +done + +cdo expr,"${{smi_equation}}" swvl.nc smil_in.nc + +rm -f swvl.nc + +cdo -s remapdis,triangular-grid.nc smil_in.nc smil_out.nc +ncks -A -v SMIL1,SMIL2,SMIL3,SMIL4 smil_out.nc era5_final.nc +rm -f smil_in.nc smil_out.nc + +# --------------------------------------------------------------------- +# 5) Create LNPS and finalize dimensions +# --------------------------------------------------------------------- +cdo expr,'LNPS=ln(PS);' era5_final.nc tmp.nc +ncks -A -v LNPS tmp.nc era5_final.nc +rm -f tmp.nc + +ncrename -h -d cell,ncells era5_final.nc || true +ncrename -h -d nv,vertices era5_final.nc || true + +# sanity: ensure directory exists +mkdir -p "$(dirname "$OUTFILE")" + +ncdump -k era5_final.nc + +# cheap + no-RAM: move the file into place +mv -f era5_final.nc "$OUTFILE" + +# cleanup +rm -f triangular-grid.nc + +echo "Wrote ICON initial condition file: $OUTFILE" diff --git a/cases/parent-global-r2b7-era5-update-euler/templates/icon_runjob_parent_global.cfg b/cases/parent-global-r2b7-era5-update-euler/templates/icon_runjob_parent_global.cfg new file mode 100644 index 00000000..5c152387 --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/templates/icon_runjob_parent_global.cfg @@ -0,0 +1,387 @@ +#!/usr/bin/env bash +#SBATCH --job-name=icon_parent_global_np{cfg.icon_np_tot} +#SBATCH --time={cfg.walltime_icon} +#SBATCH --ntasks={cfg.icon_np_tot} +#SBATCH --constraint={cfg.constraint} +#SBATCH --partition={cfg.compute_queue} +#SBATCH --output=slurm-%x-%j.out +#SBATCH --chdir={cfg.icon_work} +#SBATCH --ntasks-per-node={cfg.ntasks_per_node} +#SBATCH --hint=nomultithread +#SBATCH --cpus-per-task=1 +#SBATCH --open-mode=append +#SBATCH --mem-per-cpu=1800 + + + +set -euo pipefail +ulimit -s unlimited + +export OMP_NUM_THREADS=1 +export ICON_THREADS=1 +export OMP_SCHEDULE=static +export OMP_DYNAMIC="false" +export OMP_STACKSIZE=200M + + + +# ----------------------------------------------------------------------------- +# Read varlists (brace-free, safe with Python .format templates) +# ----------------------------------------------------------------------------- +PARENT_EVAL_SFC_VARS="$(grep -v -E '^\s*($|#)' "{cfg.case_path}/varlists/parent_eval_hourly_sfc.txt" \ + | sed -e 's/\r$//' -e "s/.*/'&'/" | paste -sd, -)" + +PARENT_EVAL_PL_VARS="$(grep -v -E '^\s*($|#)' "{cfg.case_path}/varlists/parent_eval_hourly_pl.txt" \ + | sed -e 's/\r$//' -e "s/.*/'&'/" | paste -sd, -)" + +PARENT_NATIVE_3D_VARS="$(grep -v -E '^\s*($|#)' "{cfg.case_path}/varlists/parent_native_3d_1D_ml.txt" \ + | sed -e 's/\r$//' -e "s/.*/'&'/" | paste -sd, -)" + +# ----------------------------------------------------------------------------- +# Stage required radiation/aerosol/ozone datasets (brace-free) +# ----------------------------------------------------------------------------- +ECRAD="{cfg.ecrad_data_path}" +ICONDATA="{cfg.icon_data_path}" +YEAR="{cfg.start_year}" + +test -e "$ECRAD/bc_aeropt_kinne_sw_b14_coa.nc" || exit 2 +ln -sf "$ECRAD/bc_aeropt_kinne_sw_b14_coa.nc" bc_aeropt_kinne_sw_b14_coa.nc + +test -e "$ECRAD/bc_aeropt_kinne_lw_b16_coa.nc" || exit 2 +ln -sf "$ECRAD/bc_aeropt_kinne_lw_b16_coa.nc" bc_aeropt_kinne_lw_b16_coa.nc + +test -e "$ECRAD/bc_aeropt_kinne_sw_b14_fin_${{YEAR}}.nc" || exit 2 +ln -sf "$ECRAD/bc_aeropt_kinne_sw_b14_fin_${{YEAR}}.nc" bc_aeropt_kinne_sw_b14_fin.nc + +test -e "$ECRAD/bc_aeropt_cmip6_volc_lw_b16_sw_b14_${{YEAR}}.nc" || exit 2 +ln -sf "$ECRAD/bc_aeropt_cmip6_volc_lw_b16_sw_b14_${{YEAR}}.nc" bc_aeropt_cmip6_volc_lw_b16_sw_b14_${{YEAR}}.nc + +test -e "$ICONDATA/MACv2.0-SP_v1.nc" || exit 2 +ln -sf "$ICONDATA/MACv2.0-SP_v1.nc" MACv2.0-SP_v1.nc + +test -e "$ECRAD/bc_ozone_ssp370_${{YEAR}}.nc" || exit 2 +ln -sf "$ECRAD/bc_ozone_ssp370_${{YEAR}}.nc" bc_ozone_${{YEAR}}.nc + + + +# ----------------------------------------------------------------------------- +# ICON master namelist +# ----------------------------------------------------------------------------- +cat > icon_master.namelist << EOF +&master_nml + lrestart = {cfg.lrestart} + read_restart_namelists = .true. +/ + +&master_time_control_nml + calendar = 'proleptic gregorian' + experimentStartDate = '{cfg.ini_datetime_string}' + experimentStopDate = '{cfg.end_datetime_string}' + restartTimeIntval = '{cfg.restart_step}' + checkpointTimeIntval = '{cfg.restart_step}' +/ + +&master_model_nml + model_type = 1 + model_name = "ATMO" + model_namelist_filename = "NAMELIST_{cfg.casename}" + model_min_rank = 1 + model_max_rank = 65536 + model_inc_rank = 1 +/ +EOF + +# ----------------------------------------------------------------------------- +# Model namelist (ATMO) +# ----------------------------------------------------------------------------- +cat > NAMELIST_{cfg.casename} << EOF + +¶llel_nml + nproma = 128 + ! nblocks_e = 0 + l_log_checks = .FALSE. + num_io_procs = {cfg.icon_np_io} + num_restart_procs = {cfg.icon_np_restart} + iorder_sendrecv = 3 +/ + +&grid_nml + dynamics_grid_filename = "{cfg.input_files_scratch_dynamics_grid_filename}" + radiation_grid_filename = "{cfg.input_files_scratch_radiation_grid_filename}" + dynamics_parent_grid_id = 0 + lredgrid_phys = .TRUE. + l_limited_area = .FALSE. + lfeedback = .FALSE. +/ + +&initicon_nml + init_mode = 2 + lread_ana = .FALSE. + ifs2icon_filename = "{inidata_filename}" + ana_varnames_map_file = "{cfg.input_files_scratch_map_file_ana}" + zpbl1 = 500. + zpbl2 = 1000. + ltile_init = .TRUE. + ltile_coldstart = .TRUE. +/ + +&run_nml + modelTimeStep = "PT120S" + num_lev = 120 + lvert_nest = .FALSE. + ldynamics = .TRUE. + ltransport = .TRUE. + iforcing = 3 + lart = .FALSE. + ltestcase = .FALSE. + msg_level = 10 + ltimer = .TRUE. + activate_sync_timers = .TRUE. + timers_level = 10 + output = "nml" + check_uuid_gracefully = .TRUE. + restart_filename = "{cfg.icon_restart_out}/{cfg.output_filename}_.nc" +/ + +&io_nml + itype_pres_msl = 5 + itype_rh = 1 + restart_file_type = 5 + restart_write_mode = "joint procs multifile" + lflux_avg = .TRUE. + lnetcdf_flt64_output = .FALSE. + precip_interval = "PT1H" + runoff_interval = "PT3H" + maxt_interval = "PT3H" + melt_interval = "PT3H" + lmask_boundary = .FALSE. +/ + +&extpar_nml + extpar_filename = "{cfg.input_files_scratch_extpar_filename}" + itopo = 1 + n_iter_smooth_topo = 1 + heightdiff_threshold = 3000. + hgtdiff_max_smooth_topo = 750. + itype_vegetation_cycle = 3 + itype_lwemiss = 2 +/ + +&nwp_phy_nml + inwp_gscp = 2 + inwp_convection = 1 + lshallowconv_only = .FALSE. + inwp_radiation = 4 + inwp_cldcover = 1 + inwp_turb = 1 + inwp_satad = 1 + inwp_sso = 1 + inwp_gwd = 1 + inwp_surface = 1 + icapdcycl = 3 + itype_z0 = 2 + + ! cadence consistent with modelTimeStep=PT120S + dt_conv = 120 + dt_sso = 120 + dt_gwd = 120 + dt_ccov = 120 + dt_rad = 600 + + latm_above_top = .FALSE. + efdt_min_raylfric = 7200.0 + icpl_aero_conv = 0 + icpl_aero_gscp = 0 + ldetrain_conv_prec = .FALSE. + + lrtm_filename = "{cfg.input_files_scratch_lrtm_filename}" + cldopt_filename = "{cfg.input_files_scratch_cldopt_filename}" +/ + +&radiation_nml + ecrad_isolver = 0 + irad_o3 = 5 + irad_o2 = 2 ! Tracer variable (CLM commnity) + irad_cfc11 = 2 ! Tracer variableTracer variable (co2, ch4,n20,o2,cfc11,cfc12)) + irad_cfc12 = 2 ! Tracer Variable (cfc12) + irad_aero = 18 ! was 18, change back if we get file + albedo_type = 2 + direct_albedo = 4 + albedo_whitecap = 1 + vmr_co2 = 390.e-06 + vmr_ch4 = 1800.e-09 + vmr_n2o = 322.0e-09 + vmr_o2 = 0.20946 + vmr_cfc11 = 240.e-12 + vmr_cfc12 = 532.e-12 + ecrad_data_path = "{cfg.ecrad_data_path}" +/ + +&nonhydrostatic_nml + iadv_rhotheta = 2 + ivctype = 2 + itime_scheme = 4 + exner_expol = 0.333 + vwind_offctr = 0.2 + damp_height = 30000. + rayleigh_coeff = 0.5 + divdamp_order = 24 + divdamp_type = 32 + divdamp_fac = 0.004 + divdamp_trans_start = 12500. + divdamp_trans_end = 17500. + igradp_method = 3 + l_zdiffu_t = .TRUE. + thslp_zdiffu = 0.02 + thhgtd_zdiffu = 125. + htop_moist_proc = 22500. + hbot_qvsubstep = 16000. + ndyn_substeps = 5 +/ + +&sleve_nml + min_lay_thckn = 50. + htop_thcknlimit = 15000. + top_height = 85000. + stretch_fac = 0.9 + decay_scale_1 = 4000. + decay_scale_2 = 2500. + decay_exp = 1.2 + flat_height = 25000. +/ + +&dynamics_nml + iequations = 3 + divavg_cntrwgt = 0.50 + lcoriolis = .TRUE. +/ + +&transport_nml + ihadv_tracer = 2,2,2,2,2,2 + itype_hlimit = 4,4,4,4,4,4 + ivadv_tracer = 3,3,3,3,3,3 + itype_vlimit = 1,1,1,1,1,1 + ivlimit_selective = 1,1,1,1,1,1 + llsq_svd = .TRUE. +/ + +&diffusion_nml + hdiff_order = 5 + itype_vn_diffu = 1 + itype_t_diffu = 2 + hdiff_efdt_ratio = 32.0 + hdiff_smag_fac = 0.025 + lhdiff_vn = .TRUE. + lhdiff_temp = .TRUE. +/ + +&turbdiff_nml + tkhmin = 0.6 + tkhmin_strat = 1.0 + tkmmin = 0.75 + pat_len = 750. + c_diff = 0.2 + rlam_heat = 10.0 + rat_sea = 0.8 + ltkesso = .TRUE. + frcsmot = 0.2 + imode_frcsmot = 2 + alpha1 = 0.125 + icldm_turb = 1 + itype_sher = 1 + ltkeshs = .TRUE. + a_hshr = 2.0 +/ + +&lnd_nml + sstice_mode = 1 ! update sst and ice at intervals is mode 6 + ntiles = 3 + nlev_snow = 1 + zml_soil = 0.005,0.02,0.06,0.18,0.54,1.62,4.86,14.58 + lmulti_snow = .FALSE. + itype_heatcond = 3 + idiag_snowfrac = 20 + itype_snowevap = 3 + lsnowtile = .TRUE. + lseaice = .TRUE. + llake = .TRUE. + itype_lndtbl = 4 + itype_evsl = 4 + itype_trvg = 3 + itype_root = 2 + itype_canopy = 2 + cwimax_ml = 5.e-4 + c_soil = 1.25 + c_soil_urb = 0.5 + lprog_albsi = .TRUE. +/ + +! ============================================================ +! OUTPUT STREAM 1a: hourly eval (remapped) - MODEL LEVELS +! ============================================================ +&output_nml + filetype = 5 + dom = 1 + steps_per_file = 1 + include_last = .TRUE. + + output_filename = '{cfg.output_filename}_eval_hourly_sfc' + filename_format = '{cfg.icon_output}/{cfg.output_filename}_eval_hourly_sfc_DOM_' + + output_bounds = 0., 1.0e15, 3600. + + remap = 1 + reg_lon_def = {cfg.parent_eval_reg_lon_def} + reg_lat_def = {cfg.parent_eval_reg_lat_def} + + ml_varlist = ${{PARENT_EVAL_SFC_VARS}} +/ + +! ============================================================ +! OUTPUT STREAM 1b: hourly eval (remapped) - PRESSURE LEVELS +! ============================================================ +&output_nml + filetype = 5 + dom = 1 + steps_per_file = 1 + include_last = .FALSE. ! back to true in actual runs + + output_filename = '{cfg.output_filename}_eval_hourly_pl' + filename_format = '{cfg.icon_output}/{cfg.output_filename}_eval_hourly_pl_DOM_' + + output_bounds = 0., 1.0e15, 86400. ! longer interval than run, no output + + remap = 1 + reg_lon_def = {cfg.parent_eval_reg_lon_def} + reg_lat_def = {cfg.parent_eval_reg_lat_def} + + p_levels = {cfg.parent_eval_p_levels_pa} + pl_varlist = ${{PARENT_EVAL_PL_VARS}} +/ + +! ============================================================ +! OUTPUT STREAM 2: daily native 3D (ICON grid) +! ============================================================ +&output_nml + filetype = 5 + dom = 1 + steps_per_file = 1 + include_last = .FALSE. + + output_filename = '{cfg.output_filename}_native_3d_1D' + filename_format = '{cfg.icon_output}/{cfg.output_filename}_native_3d_1D_DOM_' + + output_bounds = 0., 1.0e15, 86400. + remap = 0 + + ml_varlist = ${{PARENT_NATIVE_3D_VARS}} +/ +EOF + +# ----------------------------------------------------------------------------- +# Run ICON +# ----------------------------------------------------------------------------- +source {cfg.chain_src_dir}/ext/icon/modules.env +set -x +srun -n {cfg.icon_np_tot} ./{cfg.icon_execname} +set +x diff --git a/cases/parent-global-r2b7-era5-update-euler/varlists/parent_eval_hourly_pl.txt b/cases/parent-global-r2b7-era5-update-euler/varlists/parent_eval_hourly_pl.txt new file mode 100644 index 00000000..beda0d19 --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/varlists/parent_eval_hourly_pl.txt @@ -0,0 +1,6 @@ +geopot +temp +u +v +qv +w diff --git a/cases/parent-global-r2b7-era5-update-euler/varlists/parent_eval_hourly_sfc.txt b/cases/parent-global-r2b7-era5-update-euler/varlists/parent_eval_hourly_sfc.txt new file mode 100644 index 00000000..ea29305b --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/varlists/parent_eval_hourly_sfc.txt @@ -0,0 +1,5 @@ +tot_prec_d +pres_sfc +t_2m +u_10m +v_10m diff --git a/cases/parent-global-r2b7-era5-update-euler/varlists/parent_native_3d_1D_ml.txt b/cases/parent-global-r2b7-era5-update-euler/varlists/parent_native_3d_1D_ml.txt new file mode 100644 index 00000000..30e8cd0f --- /dev/null +++ b/cases/parent-global-r2b7-era5-update-euler/varlists/parent_native_3d_1D_ml.txt @@ -0,0 +1,12 @@ +temp +u +v +w +pres +rho +qv +qc +qi +geopot +z_mc +z_ifc diff --git a/config.py b/config.py index 8e1a445f..dbcbf652 100644 --- a/config.py +++ b/config.py @@ -627,7 +627,7 @@ def get_previous_slurm_summary(self, # Get job info for all jobs self.slurm_info = {} for job_name in self.jobs: - for job_id in self.job_ids['previous'][job_name]: + for job_id in self.job_ids['previous'].get(job_name, []): self.slurm_info[job_name] = [] self.slurm_info[job_name].append( self.get_job_info(job_id, slurm_keys=info_keys, @@ -665,7 +665,7 @@ def print_previous_slurm_summary(self): f.write(table_header) f.write('\n') for job_name in self.jobs: - for info in self.slurm_info[job_name]: + for info in self.slurm_info.get(job_name, []): f.write(line_format.format(**info)) f.write('\n') f.write('\n') diff --git a/jobs/era5_ic.py b/jobs/era5_ic.py index a6b51c05..d3acc641 100644 --- a/jobs/era5_ic.py +++ b/jobs/era5_ic.py @@ -67,6 +67,27 @@ def main(cfg): cfg.era5_ymd = cfg.startdate_sim.strftime('%Y-%m-%d') # e.g. 2021-01-01 cfg.era5_yyyymmddhh = cfg.startdate_sim.strftime('%Y%m%d%H') # 2021010100 + # ------------------------------------------------------------------ + # Expand ERA5 input filename patterns from config.yaml + # Supports placeholders like {ymd} and {yyyymmddhh}. + # This is critical because bash will NOT expand "{ymd}". + # ------------------------------------------------------------------ + if hasattr(cfg, "era5_ml_filename"): + cfg.era5_ml_file = cfg.era5_ml_filename.format( + ymd=cfg.era5_ymd, + yyyymmddhh=cfg.era5_yyyymmddhh, + ) + if hasattr(cfg, "era5_sfc_filename"): + cfg.era5_sfc_file = cfg.era5_sfc_filename.format( + ymd=cfg.era5_ymd, + yyyymmddhh=cfg.era5_yyyymmddhh, + ) + + # Make the partab path absolute (case-relative -> absolute) + if hasattr(cfg, "era5_partab"): + p = Path(str(cfg.era5_partab)) + cfg.era5_partab_path = p if p.is_absolute() else (cfg.case_path / p) + # Compute the *exact* file that ICON will later read inidata_filename = _compute_inidata_filename(cfg) diff --git a/jobs/prepare_icon.py b/jobs/prepare_icon.py index 41fc4d25..b9c84431 100644 --- a/jobs/prepare_icon.py +++ b/jobs/prepare_icon.py @@ -22,9 +22,18 @@ def set_cfg_variables(cfg): cfg.input_files_scratch = {} for dsc, file in cfg.input_files.items(): - cfg.input_files[dsc] = (p := Path(file)) + p = Path(file) + if not p.is_absolute(): + # resolve relative input_files paths relative to the case directory + p = (cfg.case_path / p).resolve() + cfg.input_files[dsc] = p cfg.input_files_scratch[dsc] = cfg.icon_input / p.name + +# for dsc, file in cfg.input_files.items(): +# cfg.input_files[dsc] = (p := Path(file)) +# cfg.input_files_scratch[dsc] = cfg.icon_input / p.name + cfg.create_vars_from_dicts() cfg.ini_datetime_string = cfg.startdate.strftime('%Y-%m-%dT%H:00:00Z') @@ -51,6 +60,9 @@ def set_cfg_variables(cfg): cfg, 'species_inicond') and cfg.species_inicond else 0 cfg.startdate_sim_yyyymmdd_hh = cfg.startdate_sim.strftime('%Y%m%d_%H') + cfg.startdate_sim_yyyymmddhh = cfg.startdate_sim.strftime('%Y%m%d%H') + cfg.enddate_sim_yyyymmddhh = cfg.enddate_sim.strftime('%Y%m%d%H') + def main(cfg): diff --git a/workflows.yaml b/workflows.yaml index 4ccc5b9f..ccefb2ec 100644 --- a/workflows.yaml +++ b/workflows.yaml @@ -1,3 +1,46 @@ + +icon-global-era5-parent-r2b7: + features: + - restart + jobs: + - prepare_icon + - era5_ic + - era5_sstice + - icon + dependencies: + era5_ic: + current: + - prepare_icon + era5_sstice: + current: + - prepare_icon + icon: + current: + - prepare_icon + - era5_ic + - era5_sstice + previous: + - icon + +icon-global-era5-parent-r2b7-nosst: + features: + - restart + jobs: + - prepare_icon + - era5_ic + - icon + dependencies: + era5_ic: + current: + - prepare_icon + icon: + current: + - prepare_icon + - era5_ic + previous: + - icon + + cosmo: features: - restart From 28eebed297fee91466268ef6f96eb8cdf61856cc Mon Sep 17 00:00:00 2001 From: Laurenz Roither Date: Mon, 16 Feb 2026 14:54:00 +0100 Subject: [PATCH 18/35] Added expanded conda virtual env setup --- proc-chain-environment.yml | 237 +++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 proc-chain-environment.yml diff --git a/proc-chain-environment.yml b/proc-chain-environment.yml new file mode 100644 index 00000000..9282a3be --- /dev/null +++ b/proc-chain-environment.yml @@ -0,0 +1,237 @@ +name: proc-chain +channels: + - conda-forge + - defaults +dependencies: + - _libgcc_mutex=0.1 + - _openmp_mutex=4.5 + - alabaster=1.0.0 + - alsa-lib=1.2.14 + - attr=2.5.2 + - attrs=25.4.0 + - babel=2.17.0 + - blosc=1.21.6 + - brotli=1.2.0 + - brotli-bin=1.2.0 + - brotli-python=1.2.0 + - bzip2=1.0.8 + - c-ares=1.34.5 + - ca-certificates=2026.1.4 + - cairo=1.18.4 + - cartopy=0.25.0 + - cdo=2.2.0 + - cdsapi=0.7.7 + - certifi=2026.1.4 + - cffi=2.0.0 + - cftime=1.6.4 + - charset-normalizer=3.4.4 + - colorama=0.4.6 + - contourpy=1.3.3 + - cycler=0.12.1 + - cyrus-sasl=2.1.28 + - dbus=1.16.2 + - docutils=0.22.3 + - double-conversion=3.3.1 + - eccodes=2.44.0 + - ecmwf-datastores-client=0.4.1 + - esmf=8.9.0 + - expat=2.7.3 + - f90nml=1.5 + - fftw=3.3.10 + - findlibs=0.1.2 + - font-ttf-dejavu-sans-mono=2.37 + - font-ttf-inconsolata=3.000 + - font-ttf-source-code-pro=2.038 + - font-ttf-ubuntu=0.83 + - fontconfig=2.15.0 + - fonts-conda-ecosystem=1 + - fonts-conda-forge=1 + - fonttools=4.61.0 + - freeglut=3.2.2 + - freetype=2.14.1 + - fribidi=1.0.16 + - geos=3.14.1 + - graphite2=1.3.14 + - gsl=2.7 + - h2=4.3.0 + - harfbuzz=12.2.0 + - hdf4=4.2.15 + - hdf5=1.14.6 + - hpack=4.1.0 + - hyperframe=6.1.0 + - icu=75.1 + - idna=3.11 + - imagesize=1.4.1 + - jasper=4.2.8 + - jinja2=3.1.6 + - joblib=1.5.2 + - keyutils=1.6.3 + - kiwisolver=1.4.9 + - krb5=1.21.3 + - lcms2=2.17 + - ld_impl_linux-64=2.45 + - lerc=4.0.0 + - libaec=1.1.4 + - libblas=3.11.0 + - libbrotlicommon=1.2.0 + - libbrotlidec=1.2.0 + - libbrotlienc=1.2.0 + - libcblas=3.11.0 + - libclang-cpp21.1=21.1.7 + - libclang13=21.1.7 + - libcups=2.3.3 + - libcurl=8.17.0 + - libdeflate=1.25 + - libdrm=2.4.125 + - libedit=3.1.20250104 + - libegl=1.7.0 + - libev=4.33 + - libexpat=2.7.3 + - libffi=3.5.2 + - libfreetype=2.14.1 + - libfreetype6=2.14.1 + - libgcc=15.2.0 + - libgcc-ng=15.2.0 + - libgfortran=15.2.0 + - libgfortran5=15.2.0 + - libgl=1.7.0 + - libglib=2.86.2 + - libglu=9.0.3 + - libglvnd=1.7.0 + - libglx=1.7.0 + - libgomp=15.2.0 + - libiconv=1.18 + - libjpeg-turbo=3.1.2 + - liblapack=3.11.0 + - libllvm21=21.1.7 + - liblzma=5.8.1 + - libnetcdf=4.9.3 + - libnghttp2=1.67.0 + - libnsl=2.0.1 + - libntlm=1.8 + - libopenblas=0.3.30 + - libopengl=1.7.0 + - libpciaccess=0.18 + - libpng=1.6.51 + - libpq=18.1 + - libsqlite=3.51.1 + - libssh2=1.11.1 + - libstdcxx=15.2.0 + - libstdcxx-ng=15.2.0 + - libtiff=4.7.1 + - libudunits2=2.2.28 + - libuuid=2.41.2 + - libvulkan-loader=1.4.328.1 + - libwebp-base=1.6.0 + - libxcb=1.17.0 + - libxcrypt=4.4.36 + - libxkbcommon=1.13.1 + - libxml2=2.15.1 + - libxml2-16=2.15.1 + - libxml2-devel=2.15.1 + - libxslt=1.1.43 + - libzip=1.11.2 + - libzlib=1.3.1 + - lz4-c=1.10.0 + - magics=4.16.0 + - magics-python=1.5.8 + - markupsafe=3.0.3 + - matplotlib=3.10.8 + - matplotlib-base=3.10.8 + - multiurl=0.3.7 + - munkres=1.1.4 + - nco=5.3.6 + - ncurses=6.5 + - netcdf-fortran=4.6.2 + - netcdf4=1.7.4 + - numpy=2.4.1 + - openjpeg=2.5.4 + - openldap=2.6.10 + - openssl=3.6.0 + - packaging=25.0 + - pandas=2.3.3 + - pango=1.56.4 + - pcre2=10.46 + - pillow=12.0.0 + - pip=25.3 + - pixman=0.46.4 + - proj=9.7.1 + - pthread-stubs=0.4 + - pycparser=2.22 + - pygments=2.19.2 + - pyparsing=3.2.5 + - pyproj=3.7.2 + - pyshp=3.0.3 + - pyside6=6.9.3 + - pysocks=1.7.1 + - python=3.11.14 + - python-dateutil=2.9.0.post0 + - python-tzdata=2025.2 + - python_abi=3.11 + - pytz=2025.2 + - pyyaml=6.0.3 + - qhull=2020.2 + - qt6-main=6.9.3 + - readline=8.2 + - requests=2.32.5 + - roman-numerals=3.1.0 + - scikit-learn=1.8.0 + - scipy=1.17.0 + - setuptools=80.9.0 + - shapely=2.1.2 + - simplejson=3.20.2 + - six=1.17.0 + - snappy=1.2.2 + - snowballstemmer=3.0.1 + - sphinx=9.0.4 + - sphinx-copybutton=0.5.2 + - sphinx_rtd_theme=0.4.3 + - sphinxcontrib-applehelp=2.0.0 + - sphinxcontrib-devhelp=2.0.0 + - sphinxcontrib-htmlhelp=2.1.0 + - sphinxcontrib-jsmath=1.0.1 + - sphinxcontrib-qthelp=2.0.0 + - sphinxcontrib-serializinghtml=1.1.10 + - sqlite=3.51.1 + - tempest-remap=2.2.0 + - threadpoolctl=3.6.0 + - tk=8.6.13 + - tornado=6.5.2 + - tqdm=4.67.1 + - typing_extensions=4.15.0 + - tzdata=2025b + - udunits2=2.2.28 + - unicodedata2=17.0.0 + - urllib3=2.5.0 + - wayland=1.24.0 + - wheel=0.45.1 + - xarray=2025.12.0 + - xcb-util=0.4.1 + - xcb-util-cursor=0.1.6 + - xcb-util-image=0.4.0 + - xcb-util-keysyms=0.4.1 + - xcb-util-renderutil=0.3.10 + - xcb-util-wm=0.4.2 + - xkeyboard-config=2.46 + - xorg-libice=1.1.2 + - xorg-libsm=1.2.6 + - xorg-libx11=1.8.12 + - xorg-libxau=1.0.12 + - xorg-libxcomposite=0.4.6 + - xorg-libxcursor=1.2.3 + - xorg-libxdamage=1.1.6 + - xorg-libxdmcp=1.1.5 + - xorg-libxext=1.3.6 + - xorg-libxfixes=6.0.2 + - xorg-libxi=1.8.2 + - xorg-libxrandr=1.5.4 + - xorg-libxrender=0.9.12 + - xorg-libxtst=1.2.5 + - xorg-libxxf86vm=1.1.6 + - xorg-xorgproto=2024.1 + - yaml=0.2.5 + - zlib=1.3.1 + - zlib-ng=2.3.2 + - zstandard=0.25.0 + - zstd=1.5.7 +prefix: /cluster/project/climate/lroither/envs/proc-chain From fc1faf1ab30b0a598cc7fe24408f3d0474694684 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 16 Feb 2026 13:56:09 +0000 Subject: [PATCH 19/35] GitHub Action: Apply Pep8-formatting --- jobs/prepare_icon.py | 1 - 1 file changed, 1 deletion(-) diff --git a/jobs/prepare_icon.py b/jobs/prepare_icon.py index b9c84431..ca041b72 100644 --- a/jobs/prepare_icon.py +++ b/jobs/prepare_icon.py @@ -64,7 +64,6 @@ def set_cfg_variables(cfg): cfg.enddate_sim_yyyymmddhh = cfg.enddate_sim.strftime('%Y%m%d%H') - def main(cfg): """ **ICON Data Preparation** From c5b40745920d7c52a1fe106998188b6cf715b93f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Tue, 31 Mar 2026 11:08:00 +0200 Subject: [PATCH 20/35] Add requirements.txt --- env/environment.yml => environment.yml | 0 proc-chain-environment.yml | 237 ------------------------- requirements.txt | 13 ++ 3 files changed, 13 insertions(+), 237 deletions(-) rename env/environment.yml => environment.yml (100%) delete mode 100644 proc-chain-environment.yml create mode 100644 requirements.txt diff --git a/env/environment.yml b/environment.yml similarity index 100% rename from env/environment.yml rename to environment.yml diff --git a/proc-chain-environment.yml b/proc-chain-environment.yml deleted file mode 100644 index 9282a3be..00000000 --- a/proc-chain-environment.yml +++ /dev/null @@ -1,237 +0,0 @@ -name: proc-chain -channels: - - conda-forge - - defaults -dependencies: - - _libgcc_mutex=0.1 - - _openmp_mutex=4.5 - - alabaster=1.0.0 - - alsa-lib=1.2.14 - - attr=2.5.2 - - attrs=25.4.0 - - babel=2.17.0 - - blosc=1.21.6 - - brotli=1.2.0 - - brotli-bin=1.2.0 - - brotli-python=1.2.0 - - bzip2=1.0.8 - - c-ares=1.34.5 - - ca-certificates=2026.1.4 - - cairo=1.18.4 - - cartopy=0.25.0 - - cdo=2.2.0 - - cdsapi=0.7.7 - - certifi=2026.1.4 - - cffi=2.0.0 - - cftime=1.6.4 - - charset-normalizer=3.4.4 - - colorama=0.4.6 - - contourpy=1.3.3 - - cycler=0.12.1 - - cyrus-sasl=2.1.28 - - dbus=1.16.2 - - docutils=0.22.3 - - double-conversion=3.3.1 - - eccodes=2.44.0 - - ecmwf-datastores-client=0.4.1 - - esmf=8.9.0 - - expat=2.7.3 - - f90nml=1.5 - - fftw=3.3.10 - - findlibs=0.1.2 - - font-ttf-dejavu-sans-mono=2.37 - - font-ttf-inconsolata=3.000 - - font-ttf-source-code-pro=2.038 - - font-ttf-ubuntu=0.83 - - fontconfig=2.15.0 - - fonts-conda-ecosystem=1 - - fonts-conda-forge=1 - - fonttools=4.61.0 - - freeglut=3.2.2 - - freetype=2.14.1 - - fribidi=1.0.16 - - geos=3.14.1 - - graphite2=1.3.14 - - gsl=2.7 - - h2=4.3.0 - - harfbuzz=12.2.0 - - hdf4=4.2.15 - - hdf5=1.14.6 - - hpack=4.1.0 - - hyperframe=6.1.0 - - icu=75.1 - - idna=3.11 - - imagesize=1.4.1 - - jasper=4.2.8 - - jinja2=3.1.6 - - joblib=1.5.2 - - keyutils=1.6.3 - - kiwisolver=1.4.9 - - krb5=1.21.3 - - lcms2=2.17 - - ld_impl_linux-64=2.45 - - lerc=4.0.0 - - libaec=1.1.4 - - libblas=3.11.0 - - libbrotlicommon=1.2.0 - - libbrotlidec=1.2.0 - - libbrotlienc=1.2.0 - - libcblas=3.11.0 - - libclang-cpp21.1=21.1.7 - - libclang13=21.1.7 - - libcups=2.3.3 - - libcurl=8.17.0 - - libdeflate=1.25 - - libdrm=2.4.125 - - libedit=3.1.20250104 - - libegl=1.7.0 - - libev=4.33 - - libexpat=2.7.3 - - libffi=3.5.2 - - libfreetype=2.14.1 - - libfreetype6=2.14.1 - - libgcc=15.2.0 - - libgcc-ng=15.2.0 - - libgfortran=15.2.0 - - libgfortran5=15.2.0 - - libgl=1.7.0 - - libglib=2.86.2 - - libglu=9.0.3 - - libglvnd=1.7.0 - - libglx=1.7.0 - - libgomp=15.2.0 - - libiconv=1.18 - - libjpeg-turbo=3.1.2 - - liblapack=3.11.0 - - libllvm21=21.1.7 - - liblzma=5.8.1 - - libnetcdf=4.9.3 - - libnghttp2=1.67.0 - - libnsl=2.0.1 - - libntlm=1.8 - - libopenblas=0.3.30 - - libopengl=1.7.0 - - libpciaccess=0.18 - - libpng=1.6.51 - - libpq=18.1 - - libsqlite=3.51.1 - - libssh2=1.11.1 - - libstdcxx=15.2.0 - - libstdcxx-ng=15.2.0 - - libtiff=4.7.1 - - libudunits2=2.2.28 - - libuuid=2.41.2 - - libvulkan-loader=1.4.328.1 - - libwebp-base=1.6.0 - - libxcb=1.17.0 - - libxcrypt=4.4.36 - - libxkbcommon=1.13.1 - - libxml2=2.15.1 - - libxml2-16=2.15.1 - - libxml2-devel=2.15.1 - - libxslt=1.1.43 - - libzip=1.11.2 - - libzlib=1.3.1 - - lz4-c=1.10.0 - - magics=4.16.0 - - magics-python=1.5.8 - - markupsafe=3.0.3 - - matplotlib=3.10.8 - - matplotlib-base=3.10.8 - - multiurl=0.3.7 - - munkres=1.1.4 - - nco=5.3.6 - - ncurses=6.5 - - netcdf-fortran=4.6.2 - - netcdf4=1.7.4 - - numpy=2.4.1 - - openjpeg=2.5.4 - - openldap=2.6.10 - - openssl=3.6.0 - - packaging=25.0 - - pandas=2.3.3 - - pango=1.56.4 - - pcre2=10.46 - - pillow=12.0.0 - - pip=25.3 - - pixman=0.46.4 - - proj=9.7.1 - - pthread-stubs=0.4 - - pycparser=2.22 - - pygments=2.19.2 - - pyparsing=3.2.5 - - pyproj=3.7.2 - - pyshp=3.0.3 - - pyside6=6.9.3 - - pysocks=1.7.1 - - python=3.11.14 - - python-dateutil=2.9.0.post0 - - python-tzdata=2025.2 - - python_abi=3.11 - - pytz=2025.2 - - pyyaml=6.0.3 - - qhull=2020.2 - - qt6-main=6.9.3 - - readline=8.2 - - requests=2.32.5 - - roman-numerals=3.1.0 - - scikit-learn=1.8.0 - - scipy=1.17.0 - - setuptools=80.9.0 - - shapely=2.1.2 - - simplejson=3.20.2 - - six=1.17.0 - - snappy=1.2.2 - - snowballstemmer=3.0.1 - - sphinx=9.0.4 - - sphinx-copybutton=0.5.2 - - sphinx_rtd_theme=0.4.3 - - sphinxcontrib-applehelp=2.0.0 - - sphinxcontrib-devhelp=2.0.0 - - sphinxcontrib-htmlhelp=2.1.0 - - sphinxcontrib-jsmath=1.0.1 - - sphinxcontrib-qthelp=2.0.0 - - sphinxcontrib-serializinghtml=1.1.10 - - sqlite=3.51.1 - - tempest-remap=2.2.0 - - threadpoolctl=3.6.0 - - tk=8.6.13 - - tornado=6.5.2 - - tqdm=4.67.1 - - typing_extensions=4.15.0 - - tzdata=2025b - - udunits2=2.2.28 - - unicodedata2=17.0.0 - - urllib3=2.5.0 - - wayland=1.24.0 - - wheel=0.45.1 - - xarray=2025.12.0 - - xcb-util=0.4.1 - - xcb-util-cursor=0.1.6 - - xcb-util-image=0.4.0 - - xcb-util-keysyms=0.4.1 - - xcb-util-renderutil=0.3.10 - - xcb-util-wm=0.4.2 - - xkeyboard-config=2.46 - - xorg-libice=1.1.2 - - xorg-libsm=1.2.6 - - xorg-libx11=1.8.12 - - xorg-libxau=1.0.12 - - xorg-libxcomposite=0.4.6 - - xorg-libxcursor=1.2.3 - - xorg-libxdamage=1.1.6 - - xorg-libxdmcp=1.1.5 - - xorg-libxext=1.3.6 - - xorg-libxfixes=6.0.2 - - xorg-libxi=1.8.2 - - xorg-libxrandr=1.5.4 - - xorg-libxrender=0.9.12 - - xorg-libxtst=1.2.5 - - xorg-libxxf86vm=1.1.6 - - xorg-xorgproto=2024.1 - - yaml=0.2.5 - - zlib=1.3.1 - - zlib-ng=2.3.2 - - zstandard=0.25.0 - - zstd=1.5.7 -prefix: /cluster/project/climate/lroither/envs/proc-chain diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..3255bd1b --- /dev/null +++ b/requirements.txt @@ -0,0 +1,13 @@ +numpy +cartopy +matplotlib +scipy +xarray +netcdf4 +pyyaml +cdsapi +scikit-learn +f90nml +sphinx +sphinx_rtd_theme +sphinx-copybutton From 9ad45cd41875ad35ce5fd51bb08ef8839c8bfe8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Tue, 31 Mar 2026 11:08:41 +0200 Subject: [PATCH 21/35] Adapt scripts for new env location --- jenkins/Jenkinsfile | 2 +- jenkins/scripts/setup_miniconda.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index b34b0b64..c65a536d 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -23,7 +23,7 @@ pipeline { sh 'conda config --add channels conda-forge' sh 'conda config --set channel_priority strict' sh 'conda update -n base -c defaults conda' - sh 'conda env create -f env/environment.yml' + sh 'conda env create -f environment.yml' sh '''source ${WORKSPACE}/miniconda/etc/profile.d/conda.sh conda activate proc-chain conda deactivate diff --git a/jenkins/scripts/setup_miniconda.sh b/jenkins/scripts/setup_miniconda.sh index 3cb2264e..d9317b30 100755 --- a/jenkins/scripts/setup_miniconda.sh +++ b/jenkins/scripts/setup_miniconda.sh @@ -9,7 +9,7 @@ export PATH="$WORKSPACE/miniconda/bin:$PATH" conda config --set always_yes yes --set changeps1 no conda config --add channels conda-forge conda update -n base -c defaults conda -conda env create -f env/environment.yml +conda env create -f environment.yml source "$WORKSPACE/miniconda/etc/profile.d/conda.sh" conda activate proc-chain conda deactivate From a92f1f17ba232cbe7ed2951f8a56612be9e91e60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Tue, 31 Mar 2026 11:31:36 +0200 Subject: [PATCH 22/35] Add pip option --- docs/code-structure.rst | 4 +-- docs/environment.rst | 2 +- jenkins/scripts/jenkins.sh | 4 ++- jenkins/scripts/setup_env.sh | 40 ++++++++++++++++++++++++++++++ jenkins/scripts/setup_miniconda.sh | 16 ------------ 5 files changed, 46 insertions(+), 20 deletions(-) create mode 100755 jenkins/scripts/setup_env.sh delete mode 100755 jenkins/scripts/setup_miniconda.sh diff --git a/docs/code-structure.rst b/docs/code-structure.rst index 9a7ee7ab..6c3a842d 100644 --- a/docs/code-structure.rst +++ b/docs/code-structure.rst @@ -37,8 +37,6 @@ The Processing Chain code is structured as follows: │ │ └── *.csv # CSV files containing table data │ ├── conf.py # configuration file for the Sphinx builder │ └── *.rst # documentation files (reStructuredText) - ├── env/ - │ └── environment.yml # conda environment file ├── ext/ # folder for other code (spack, models, etc.) ├── jenkins/ # automated Jenkins testing │ ├── scripts/ @@ -51,5 +49,7 @@ The Processing Chain code is structured as follows: ├── LICENSE # license file ├── README.md # README file ├── config.py # file containing the Config class + ├── environment.yml # conda environment file + ├── requirements.txt # pip requirements file ├── run_chain.py # main script └── workflows.yaml # file to store workflows with job dependencies diff --git a/docs/environment.rst b/docs/environment.rst index 58707f7a..7af9c25e 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -47,7 +47,7 @@ If you already have the environment but want to update it: .. code-block:: bash - conda env update --file env/environment.yml --prune + conda env update --file environment.yml --prune 3. Store user-specific data ~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/jenkins/scripts/jenkins.sh b/jenkins/scripts/jenkins.sh index aeff8650..85168805 100755 --- a/jenkins/scripts/jenkins.sh +++ b/jenkins/scripts/jenkins.sh @@ -18,9 +18,11 @@ done set -e -x -# Check if we are on Euler +# Check if we are on Euler and load modules if [[ $(hostname) == eu-* ]]; then host=euler + module load stack/2024-06 gcc/12.2.0 openmpi/4.1.6 python/3.12.8 || true + module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 || true elif [[ $(hostname) == santis* ]]; then host=santis else diff --git a/jenkins/scripts/setup_env.sh b/jenkins/scripts/setup_env.sh new file mode 100755 index 00000000..24cb057b --- /dev/null +++ b/jenkins/scripts/setup_env.sh @@ -0,0 +1,40 @@ +#!/bin/bash + + +set -ex + +function error { + echo "*** Error: $@" >&2 + exit 1 +} + +# Check if script is called correctly +[[ $(git rev-parse --show-toplevel 2>/dev/null) = $(pwd) ]] || error "$0 not launched from toplevel of repository" + +# Set WORKSPACE to CWD if unset +if [[ -z "$WORKSPACE" ]]; then + export WORKSPACE="$(pwd)" +fi + +# Check for --pip argument +if [[ "$1" == "--pip" ]]; then + # Create venv and install with pip + python3 -m venv --system-site-packages "$WORKSPACE/venv" + source "$WORKSPACE/venv/bin/activate" + pip install -r "$WORKSPACE/requirements.txt" + deactivate +else + # Use Miniforge installer only for conda + wget -O miniforge.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh + rm -fr miniforge + bash miniforge.sh -b -p "$WORKSPACE/miniforge" + export PATH="$WORKSPACE/miniforge/bin:$PATH" + conda config --set always_yes yes --set changeps1 no + conda config --add channels conda-forge + conda update -n base -c defaults conda + conda env create -f "$WORKSPACE/environment.yml" + source "$WORKSPACE/miniforge/etc/profile.d/conda.sh" + conda activate proc-chain + conda deactivate + rm miniforge.sh +fi \ No newline at end of file diff --git a/jenkins/scripts/setup_miniconda.sh b/jenkins/scripts/setup_miniconda.sh deleted file mode 100755 index d9317b30..00000000 --- a/jenkins/scripts/setup_miniconda.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -set -e -x - -wget -O miniconda.sh https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -rm -fr miniconda -bash miniconda.sh -b -p "$WORKSPACE/miniconda" -export PATH="$WORKSPACE/miniconda/bin:$PATH" -conda config --set always_yes yes --set changeps1 no -conda config --add channels conda-forge -conda update -n base -c defaults conda -conda env create -f environment.yml -source "$WORKSPACE/miniconda/etc/profile.d/conda.sh" -conda activate proc-chain -conda deactivate -rm miniconda.sh \ No newline at end of file From 27f535566bf6731456d115aa6eaaae475413edb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Tue, 31 Mar 2026 11:39:59 +0200 Subject: [PATCH 23/35] Add pip option to master script --- jenkins/scripts/jenkins.sh | 49 ++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/jenkins/scripts/jenkins.sh b/jenkins/scripts/jenkins.sh index 85168805..81ad1229 100755 --- a/jenkins/scripts/jenkins.sh +++ b/jenkins/scripts/jenkins.sh @@ -1,19 +1,25 @@ #!/bin/bash + # Argument parsing force_execution=false +use_pip=false while [[ "$#" -gt 0 ]]; do - case $1 in - -f|--force) - force_execution=true - shift - ;; - *) - echo "Unknown parameter: $1" - exit 1 - ;; - esac + case $1 in + -f|--force) + force_execution=true + shift + ;; + --pip) + use_pip=true + shift + ;; + *) + echo "Unknown parameter: $1" + exit 1 + ;; + esac done set -e -x @@ -29,9 +35,26 @@ else echo "Unknown hostname: $(hostname)" fi -# Activate conda environment -eval "$(conda shell.bash hook)" -conda activate proc-chain + +# Build environment if not present +if [[ "$use_pip" == true ]]; then + if [[ ! -d venv ]]; then + echo "Creating Python venv and installing requirements..." + ./jenkins/scripts/setup_env.sh --pip + else + echo "Python venv already exists - skipping build." + fi + source venv/bin/activate +else + if ! conda info --envs | grep -q "proc-chain"; then + echo "Creating conda environment..." + ./jenkins/scripts/setup_env.sh + else + echo "Conda environment 'proc-chain' already exists - skipping build." + fi + eval "$(conda shell.bash hook)" + conda activate proc-chain +fi # Preparation size=$(du -sb input | awk '{print $1}') From cfbabf80e53d5d636e35bba993806733bf9bf73e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Tue, 31 Mar 2026 12:38:52 +0200 Subject: [PATCH 24/35] Cleanup Jenkinsfile --- jenkins/Jenkinsfile | 138 ++---------------------------------- jenkins/scripts/get_data.sh | 6 +- 2 files changed, 9 insertions(+), 135 deletions(-) diff --git a/jenkins/Jenkinsfile b/jenkins/Jenkinsfile index c65a536d..446bb4e0 100644 --- a/jenkins/Jenkinsfile +++ b/jenkins/Jenkinsfile @@ -4,30 +4,18 @@ pipeline { } agent { node { - label 'daint' + label 'euler' } } stages { stage('Preparation') { parallel { - stage('Setup miniconda') { + stage('Setup env') { environment { - PATH = "${WORKSPACE}/miniconda/bin:$PATH" + PATH = "${WORKSPACE}/miniforge/bin:$PATH" } steps { - sh 'wget -O ${WORKSPACE}/miniconda.sh https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh' - sh 'rm -fr ${WORKSPACE}/miniconda' - sh 'bash miniconda.sh -b -p $WORKSPACE/miniconda' - sh 'conda config --remove channels defaults' - sh 'conda config --set always_yes yes --set changeps1 no' - sh 'conda config --add channels conda-forge' - sh 'conda config --set channel_priority strict' - sh 'conda update -n base -c defaults conda' - sh 'conda env create -f environment.yml' - sh '''source ${WORKSPACE}/miniconda/etc/profile.d/conda.sh - conda activate proc-chain - conda deactivate - rm miniconda.sh''' + ./jenkins/scripts/setup_env.sh --pip } post { failure { @@ -47,39 +35,6 @@ pipeline { } } } - stage('Build int2lm') { - steps { - sh './jenkins/scripts/build_int2lm.sh' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } - } - } - stage('Build icontools') { - steps { - sh './jenkins/scripts/build_icontools.sh' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } - } - } - stage('Build COSMO-GHG') { - steps { - sh './jenkins/scripts/build_cosmo-ghg.sh' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } - } - } stage('Build ICON') { steps { sh './jenkins/scripts/build_icon.sh' @@ -91,51 +46,6 @@ pipeline { } } } - stage('Build ICON-ART') { - steps { - sh './jenkins/scripts/build_icon-art.sh' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } - } - } - } - } - stage('Test COSMO-GHG') { - environment { - PATH = "${WORKSPACE}/miniconda/bin:$PATH" - } - steps { - sh '''source ${WORKSPACE}/miniconda/etc/profile.d/conda.sh - conda activate proc-chain - . ${WORKSPACE}/ext/spack-c2sm/setup-env.sh - ./jenkins/scripts/test_cosmo-ghg.sh''' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } - } - } - stage('Test COSMO-GHG (spinup)') { - environment { - PATH = "${WORKSPACE}/miniconda/bin:$PATH" - } - steps { - sh '''source ${WORKSPACE}/miniconda/etc/profile.d/conda.sh - conda activate proc-chain - . ${WORKSPACE}/ext/spack-c2sm/setup-env.sh - ./jenkins/scripts/test_cosmo-ghg-spinup.sh''' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } } } stage('Test ICON') { @@ -143,44 +53,8 @@ pipeline { PATH = "${WORKSPACE}/miniconda/bin:$PATH" } steps { - sh '''source ${WORKSPACE}/miniconda/etc/profile.d/conda.sh - conda activate proc-chain - . ${WORKSPACE}/ext/spack-c2sm/setup-env.sh - ./jenkins/scripts/test_icon.sh''' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } - } - } - stage('Test ICON-ART (OEM)') { - environment { - PATH = "${WORKSPACE}/miniconda/bin:$PATH" - } - steps { - sh '''source ${WORKSPACE}/miniconda/etc/profile.d/conda.sh - conda activate proc-chain - . ${WORKSPACE}/ext/spack-c2sm/setup-env.sh - ./jenkins/scripts/test_icon-art-oem.sh''' - } - post { - failure { - echo 'Cleaning up workspace' - deleteDir() - } - } - } - stage('Test ICON-ART (global)') { - environment { - PATH = "${WORKSPACE}/miniconda/bin:$PATH" - } - steps { - sh '''source ${WORKSPACE}/miniconda/etc/profile.d/conda.sh - conda activate proc-chain - . ${WORKSPACE}/ext/spack-c2sm/setup-env.sh - ./jenkins/scripts/test_icon-art-global.sh''' + sh 'source "$WORKSPACE/venv/bin/activate"' + sh './jenkins/scripts/test_icon.sh' } post { failure { diff --git a/jenkins/scripts/get_data.sh b/jenkins/scripts/get_data.sh index 19b94def..97ec0c33 100755 --- a/jenkins/scripts/get_data.sh +++ b/jenkins/scripts/get_data.sh @@ -12,7 +12,7 @@ function error { mkdir -p input pushd input - wget ftp://iacftp.ethz.ch/pub_read/mjaehn/input_processing-chain.tgz - tar -xvzf input_processing-chain.tgz - rm -f input_processing-chain.tgz + wget ftp://iacftp.ethz.ch/pub_read/mjaehn/input_processing-chain_icon.tgz + tar -xvzf input_processing-chain_icon.tgz + rm -f input_processing-chain_icon.tgz popd From 7253387a22d417912905d43effb91c47b71798b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Tue, 31 Mar 2026 13:52:27 +0200 Subject: [PATCH 25/35] Remove partition from runjob --- cases/icon-test-euler/era5_ic_runjob.cfg | 1 - 1 file changed, 1 deletion(-) diff --git a/cases/icon-test-euler/era5_ic_runjob.cfg b/cases/icon-test-euler/era5_ic_runjob.cfg index fbe2f24e..74aa564c 100644 --- a/cases/icon-test-euler/era5_ic_runjob.cfg +++ b/cases/icon-test-euler/era5_ic_runjob.cfg @@ -1,7 +1,6 @@ #!/usr/bin/env bash #SBATCH --job-name=era5_ic_{cfg.casename}_{cfg.startdate_sim_yyyymmddhh} #SBATCH --time={cfg.walltime_era5_ic} -#SBATCH --partition={cfg.compute_queue} #SBATCH --constraint={cfg.constraint} #SBATCH --ntasks=1 #SBATCH --output={cfg.logfile} From 0fce9269cdf49205038ac22697c9f2bf9f32c65d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Tue, 31 Mar 2026 15:24:46 +0200 Subject: [PATCH 26/35] Replace daint with santis --- jobs/prepare_icon.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jobs/prepare_icon.py b/jobs/prepare_icon.py index ca041b72..51e76b67 100644 --- a/jobs/prepare_icon.py +++ b/jobs/prepare_icon.py @@ -94,7 +94,7 @@ def main(cfg): logging.info('Copy ICON input data (IC/BC) to working directory') # Copy input files to scratch - if cfg.machine == 'daint': + if cfg.machine == 'santis': script_lines = [ '#!/usr/bin/env bash', f'#SBATCH --job-name="copy_input_{cfg.casename}_{cfg.startdate_sim_yyyymmddhh}_{cfg.enddate_sim_yyyymmddhh}"', @@ -110,7 +110,6 @@ def main(cfg): '#!/usr/bin/env bash', f'#SBATCH --job-name="copy_input_{cfg.casename}_{cfg.startdate_sim_yyyymmddhh}_{cfg.enddate_sim_yyyymmddhh}"', '#SBATCH --time=00:10:00', - f'#SBATCH --partition={cfg.compute_queue}', f'#SBATCH --constraint={cfg.constraint}', '#SBATCH --ntasks=1', f'#SBATCH --output={cfg.logfile}', '#SBATCH --open-mode=append', f'#SBATCH --chdir={cfg.icon_work}', '' From 1960bf3cb4583cde196500c41c77c0b876ecece2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Tue, 31 Mar 2026 15:55:36 +0200 Subject: [PATCH 27/35] fix icon bin and make lbc optional --- cases/icon-test-euler/config.yaml | 2 +- jobs/prepare_icon.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cases/icon-test-euler/config.yaml b/cases/icon-test-euler/config.yaml index f02fb174..e8cab04d 100644 --- a/cases/icon-test-euler/config.yaml +++ b/cases/icon-test-euler/config.yaml @@ -43,7 +43,7 @@ input_files: map_file_ana: ./input/icon/mapping/map_file.ana icon: - binary_file: /cluster/work/climate/lroither/icon_c2sm/icon/bin/icon + binary_file: ./ext/icon/bin/icon runjob_filename: icon_runjob.cfg np_tot: 96 np_io: 1 diff --git a/jobs/prepare_icon.py b/jobs/prepare_icon.py index 51e76b67..42cefc58 100644 --- a/jobs/prepare_icon.py +++ b/jobs/prepare_icon.py @@ -43,11 +43,12 @@ def set_cfg_variables(cfg): cfg.restart_filename = 'restart_atm_DOM01.nc' cfg.restart_file = cfg.icon_restart_in / cfg.restart_filename cfg.restart_file_scratch = cfg.icon_work / cfg.restart_filename - cfg.ini_LBC_filename = cfg.startdate.strftime( - cfg.lbcdata_prefix + cfg.lbcdata_nameformat + - cfg.lbcdata_filename_suffix) - cfg.ini_LBC_file = cfg.icon_input_icbc_prev / cfg.ini_LBC_filename - cfg.ini_LBC_file_scratch = cfg.icon_input_icbc / cfg.ini_LBC_filename + if hasattr(cfg, 'ini_LBC_filename'): + cfg.ini_LBC_filename = cfg.startdate.strftime( + cfg.lbcdata_prefix + cfg.lbcdata_nameformat + + cfg.lbcdata_filename_suffix) + cfg.ini_LBC_file = cfg.icon_input_icbc_prev / cfg.ini_LBC_filename + cfg.ini_LBC_file_scratch = cfg.icon_input_icbc / cfg.ini_LBC_filename # Nudge type (global or nothing) cfg.nudge_type = 2 if hasattr(cfg, From 3730d00f87020d7bcdf8cdde72ace6ae7a4e1efb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Wed, 1 Apr 2026 16:34:08 +0200 Subject: [PATCH 28/35] Add script to activate env on euler --- setup_env_euler.sh | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 setup_env_euler.sh diff --git a/setup_env_euler.sh b/setup_env_euler.sh new file mode 100755 index 00000000..63ce36a0 --- /dev/null +++ b/setup_env_euler.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +module load stack/2024-06 gcc/12.2.0 openmpi/4.1.6 python/3.12.8 +module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 +source venv/bin/activate + From fd1ca0e4357b76a16048af6c868a0623e1cba7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 9 Apr 2026 14:57:26 +0200 Subject: [PATCH 29/35] Change input grids --- cases/icon-test-euler/config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cases/icon-test-euler/config.yaml b/cases/icon-test-euler/config.yaml index e8cab04d..f69e8b1c 100644 --- a/cases/icon-test-euler/config.yaml +++ b/cases/icon-test-euler/config.yaml @@ -36,8 +36,8 @@ meteo: inc: 3 input_files: - dynamics_grid_filename: ./input/icon/grid/iconR2B05-DOM01.nc - extpar_filename: ./input/icon/grid/extpar_iconR2B05-DOM01.nc + dynamics_grid_filename: ./input/icon/grid/icon_grid_0002_R02B06_G.nc + extpar_filename: ./input/icon/grid/icon_extpar_0002_R02B06_G.nc lrtm_filename: ./input/icon/rad/rrtmg_lw.nc cldopt_filename: ./input/icon/rad/rrtm_cldopt.nc map_file_ana: ./input/icon/mapping/map_file.ana From a91e39b34a82cb4b79c09611e80160bb26503eb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 9 Apr 2026 15:23:02 +0200 Subject: [PATCH 30/35] Fix placeholder in era5_ic runjob --- cases/icon-test-euler/era5_ic_runjob.cfg | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/cases/icon-test-euler/era5_ic_runjob.cfg b/cases/icon-test-euler/era5_ic_runjob.cfg index 74aa564c..5f618866 100644 --- a/cases/icon-test-euler/era5_ic_runjob.cfg +++ b/cases/icon-test-euler/era5_ic_runjob.cfg @@ -33,11 +33,8 @@ module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 || true # Inputs (from cfg) # --------------------------------------------------------------------- ERA5_DIR="{cfg.era5_dir}" -ERA5_ML="{cfg.era5_ml_filename}" -ERA5_SFC="{cfg.era5_sfc_filename}" -# Replace {ymd} placeholder using values prepared in era5_ic.py -ERA5_ML="${{ERA5_ML/\{ymd\}/{cfg.era5_ymd}}}" -ERA5_SFC="${{ERA5_SFC/\{ymd\}/{cfg.era5_ymd}}}" +ERA5_ML="{cfg.era5_ml_file}" +ERA5_SFC="{cfg.era5_sfc_file}" PARTAB="{cfg.era5_partab}" GRID_TRI="{cfg.input_files_scratch_dynamics_grid_filename}" EXTPAR="{cfg.input_files_scratch_extpar_filename}" From 3c79762b93b1dc154fd956b48510b93a0f1e56b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 9 Apr 2026 15:23:04 +0200 Subject: [PATCH 31/35] Add pip to install instructions --- README.md | 26 +++++++++++++++++--- docs/environment.rst | 57 ++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 09ff995b..12912d8a 100644 --- a/README.md +++ b/README.md @@ -9,15 +9,35 @@ e.g., by creating your own case or adding new jobs. ## Environment Setup -To setup your conda environment for the Processing Chain, please refer -to the part in the [official documentation](https://c2sm.github.io/processing-chain/latest/environment.html). +You can set up the Processing Chain environment using either **conda** (recommended) or **pip**. + +**Conda:** + + conda env create --prefix $PROJECT/envs/proc-chain -f env/environment.yml + conda activate proc-chain + +**pip (virtual environment):** + +> **Note**: `cdo` and `nco` are not available via pip and must be installed separately. + + python3 -m venv $PROJECT/envs/proc-chain + source $PROJECT/envs/proc-chain/bin/activate + pip install -r requirements.txt + +For full details, refer to the [official documentation](https://c2sm.github.io/processing-chain/latest/environment.html). ## Run the Chain -To activate your conda environment, type: +To activate your environment, type: + +**Conda:** conda activate proc-chain +**pip:** + + source $PROJECT/envs/proc-chain/bin/activate + To test if your environment has been successfully set, use the command line help to display the available arguments for the main script: diff --git a/docs/environment.rst b/docs/environment.rst index 7af9c25e..b21f25ae 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -1,9 +1,12 @@ .. _environment-section: -Conda Environment +Environment Setup ================= -The following steps allow you to create and use your own virtual environment to run the Processing Chain. We recommend using a conda environment for the usage of the provided scripts. Please follow the instructions for the installation. The following steps only need to be performed once. +The following steps allow you to create and use your own virtual environment to run the Processing Chain. You can use either **conda** (recommended) or **pip** with a standard Python virtual environment. Please follow the instructions for your preferred method. The following steps only need to be performed once. + +Option A: Conda +--------------- 1. Install Miniconda ~~~~~~~~~~~~~~~~~~~~ @@ -60,3 +63,53 @@ To register your email address and standard project account, store them in these echo > ~/.forward These settings are optional. The Processing Chain will first check the content of those files. If desired, the corresponding variables can be overridden by setting the ``compute_account`` and ``user_mail`` variables in the ``config.yaml`` file. + +Option B: pip (virtual environment) +------------------------------------- + +If you prefer not to use conda, you can set up a standard Python virtual environment with pip instead. + +.. note:: + Python 3.11 or later is required. Note that ``cdo`` and ``nco`` are not available via pip and must be installed separately (e.g., via your system package manager or a module system). + +1. Create and activate the virtual environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a virtual environment, for example in your ``$PROJECT`` directory: + +.. code-block:: bash + + python3 -m venv $PROJECT/envs/proc-chain + source $PROJECT/envs/proc-chain/bin/activate + +2. Install the requirements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Install all Python dependencies from ``requirements.txt``: + +.. code-block:: bash + + pip install -r requirements.txt + +To update an existing virtual environment: + +.. code-block:: bash + + pip install --upgrade -r requirements.txt + +3. Activate the environment in future sessions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each time you start a new session, activate the environment with: + +.. code-block:: bash + + source $PROJECT/envs/proc-chain/bin/activate + +You can add this line to your ``.bashrc`` to activate it automatically. + +4. Store user-specific data +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Follow the same steps as described in the conda section above (store +``~/.acct`` and ``~/.forward``) if needed. From 572a5e9b936d73ea50ae2ce0b5dd3852d8f56000 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 9 Apr 2026 15:30:44 +0200 Subject: [PATCH 32/35] Add machine-specific instructions --- README.md | 31 +++++++++ docs/environment.rst | 119 +++++++++++++++++++++++++++++++++++ jenkins/scripts/jenkins.sh | 2 +- machines/euler/modules.sh | 12 ++++ machines/euler/setup_env.sh | 35 +++++++++++ machines/santis/modules.sh | 19 ++++++ machines/santis/setup_env.sh | 55 ++++++++++++++++ 7 files changed, 272 insertions(+), 1 deletion(-) create mode 100644 machines/euler/modules.sh create mode 100644 machines/euler/setup_env.sh create mode 100644 machines/santis/modules.sh create mode 100644 machines/santis/setup_env.sh diff --git a/README.md b/README.md index 12912d8a..f73b50cf 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,37 @@ You can set up the Processing Chain environment using either **conda** (recommen For full details, refer to the [official documentation](https://c2sm.github.io/processing-chain/latest/environment.html). +### Machine-specific setup + +Ready-made environment scripts are provided under `machines/` for supported HPC systems. + +**Euler (ETH Zürich)** + +```bash +# Load system modules only (useful in job scripts): +source machines/euler/modules.sh + +# Load modules + activate the venv (recommended for interactive sessions): +source machines/euler/setup_env.sh +``` + +**Santis (CSCS)** + +On Santis, software is provided via `uenv`. Because `uenv start` spawns a new shell, source-based activation is not supported; use the wrapper instead: + +```bash +# Start an interactive shell with the full environment: +bash machines/santis/setup_env.sh + +# Or start the uenv manually: +uenv start climtools/25.2:v1 --view=climtools + +# Run a single command without an interactive shell: +uenv run climtools/25.2:v1 --view=climtools -- ./run_chain.py +``` + +See `machines/` for the structure to follow when adding other machines. + ## Run the Chain To activate your environment, type: diff --git a/docs/environment.rst b/docs/environment.rst index b21f25ae..e9aa6273 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -113,3 +113,122 @@ You can add this line to your ``.bashrc`` to activate it automatically. Follow the same steps as described in the conda section above (store ``~/.acct`` and ``~/.forward``) if needed. + +Machine-specific Setup +---------------------- + +The ``machines/`` directory contains ready-made scripts for loading the +correct system modules and activating the Python environment on supported +HPC systems. Each machine has its own sub-directory: + +.. code-block:: text + + machines/ + ├── euler/ + │ ├── modules.sh # module load commands only + │ └── setup_env.sh # modules + venv activation (one-stop setup) + └── santis/ + ├── modules.sh # uenv image/view reference + └── setup_env.sh # uenv start + venv activation + +Euler (ETH Zürich) +~~~~~~~~~~~~~~~~~~ + +**Load modules only** (useful inside Slurm job scripts): + +.. code-block:: bash + + source machines/euler/modules.sh + +This loads: + +.. code-block:: bash + + module load stack/2024-06 gcc/12.2.0 openmpi/4.1.6 python/3.12.8 + module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 + +**Full interactive-session setup** (modules + venv activation): + +.. code-block:: bash + + source machines/euler/setup_env.sh + +By default this activates the virtual environment at ``/venv``. +To use a different location, set ``PROC_CHAIN_VENV`` before sourcing: + +.. code-block:: bash + + export PROC_CHAIN_VENV=$PROJECT/envs/proc-chain + source machines/euler/setup_env.sh + +If the virtual environment does not exist yet, create it first (see +:ref:`Option B ` above): + +.. code-block:: bash + + python3 -m venv $PROJECT/envs/proc-chain + pip install -r requirements.txt + +Santis (CSCS) +~~~~~~~~~~~~~ + +On Santis, software is provided through **uenv** (user environments) instead +of the traditional module system. Because ``uenv start`` spawns a new shell, +it cannot be sourced inside an existing session. + +**Start an interactive session** with the required environment: + +.. code-block:: bash + + uenv start climtools/25.2:v1 --view=climtools + +**Or use the provided wrapper** (starts the uenv and activates the venv): + +.. code-block:: bash + + bash machines/santis/setup_env.sh + +If the virtual environment already exists and you are **already inside the +uenv**, you can activate it directly: + +.. code-block:: bash + + source machines/santis/setup_env.sh --no-uenv + +To use a custom venv location, set ``PROC_CHAIN_VENV`` first: + +.. code-block:: bash + + export PROC_CHAIN_VENV=$SCRATCH/envs/proc-chain + bash machines/santis/setup_env.sh + +**Run a single command** inside the uenv without entering an interactive shell: + +.. code-block:: bash + + uenv run climtools/25.2:v1 --view=climtools -- ./run_chain.py + +If the virtual environment does not exist yet, enter the uenv first and +create it: + +.. code-block:: bash + + uenv start climtools/25.2:v1 --view=climtools + python3 -m venv $SCRATCH/envs/proc-chain + pip install -r requirements.txt + +Adding support for a new machine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a new sub-directory under ``machines/`` following the same +pattern: + +.. code-block:: text + + machines/ + └── / + ├── modules.sh + └── setup_env.sh + +Use ``machines/euler/`` as a template and adapt the ``module load`` +commands for the target system. diff --git a/jenkins/scripts/jenkins.sh b/jenkins/scripts/jenkins.sh index 81ad1229..03013ad2 100755 --- a/jenkins/scripts/jenkins.sh +++ b/jenkins/scripts/jenkins.sh @@ -24,7 +24,7 @@ done set -e -x -# Check if we are on Euler and load modules +# Prepare the environment (machine-specific) if [[ $(hostname) == eu-* ]]; then host=euler module load stack/2024-06 gcc/12.2.0 openmpi/4.1.6 python/3.12.8 || true diff --git a/machines/euler/modules.sh b/machines/euler/modules.sh new file mode 100644 index 00000000..373eeb30 --- /dev/null +++ b/machines/euler/modules.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash +# machines/euler/modules.sh +# +# Load the system modules required by the Processing Chain on Euler. +# This file can be sourced standalone in interactive sessions or +# included at the top of Slurm job scripts. +# +# Usage: +# source machines/euler/modules.sh + +module load stack/2024-06 gcc/12.2.0 openmpi/4.1.6 python/3.12.8 +module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 diff --git a/machines/euler/setup_env.sh b/machines/euler/setup_env.sh new file mode 100644 index 00000000..044f36a4 --- /dev/null +++ b/machines/euler/setup_env.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# machines/euler/setup_env.sh +# +# Full environment setup for the Processing Chain on Euler. +# Sources the required system modules and activates the Python +# virtual environment. +# +# Usage (interactive session): +# source machines/euler/setup_env.sh +# +# The virtual environment is expected at /venv by default. +# Override by setting PROC_CHAIN_VENV before sourcing: +# export PROC_CHAIN_VENV=/path/to/your/venv +# source machines/euler/setup_env.sh + +# Resolve the repository root relative to this script's location +_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_REPO_ROOT="$(cd "${_SCRIPT_DIR}/../.." && pwd)" + +# 1) Load system modules +source "${_SCRIPT_DIR}/modules.sh" + +# 2) Activate the Python virtual environment (pip) +_VENV_DIR="${PROC_CHAIN_VENV:-${_REPO_ROOT}/venv}" +if [[ -f "${_VENV_DIR}/bin/activate" ]]; then + source "${_VENV_DIR}/bin/activate" + echo "Processing Chain environment activated (${_VENV_DIR})" +else + echo "Warning: virtual environment not found at '${_VENV_DIR}'" >&2 + echo "Create it first:" >&2 + echo " python3 -m venv ${_VENV_DIR}" >&2 + echo " pip install -r ${_REPO_ROOT}/requirements.txt" >&2 +fi + +unset _SCRIPT_DIR _REPO_ROOT _VENV_DIR diff --git a/machines/santis/modules.sh b/machines/santis/modules.sh new file mode 100644 index 00000000..0be15680 --- /dev/null +++ b/machines/santis/modules.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash +# machines/santis/modules.sh +# +# Activate the user environment required by the Processing Chain on Santis. +# On Santis, software is provided via uenv (user environments) instead of +# the traditional module system. +# +# NOTE: 'uenv start' spawns a new shell, so it cannot be sourced inside an +# existing shell session. Use this file as a reference or call it directly +# as a wrapper (see setup_env.sh). +# +# Usage – start an interactive session with the environment: +# uenv start climtools/25.2:v1 --view=climtools +# +# Usage – run a single command inside the environment: +# uenv run climtools/25.2:v1 --view=climtools -- + +UENV_IMAGE="climtools/25.2:v1" +UENV_VIEW="climtools" diff --git a/machines/santis/setup_env.sh b/machines/santis/setup_env.sh new file mode 100644 index 00000000..27fedc1e --- /dev/null +++ b/machines/santis/setup_env.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# machines/santis/setup_env.sh +# +# Full environment setup for the Processing Chain on Santis. +# Starts the required uenv and activates the Python virtual environment +# inside it. +# +# IMPORTANT: 'uenv start' launches a NEW interactive shell. +# Sourcing this script directly is therefore NOT supported. +# Instead, run it as an executable to enter a prepared shell: +# +# bash machines/santis/setup_env.sh +# +# Or, to activate the venv from a session already inside the uenv: +# +# source machines/santis/setup_env.sh --no-uenv +# +# The virtual environment is expected at /venv by default. +# Override by setting PROC_CHAIN_VENV before calling: +# export PROC_CHAIN_VENV=/path/to/your/venv +# bash machines/santis/setup_env.sh + +_SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +_REPO_ROOT="$(cd "${_SCRIPT_DIR}/../.." && pwd)" + +UENV_IMAGE="climtools/25.2:v1" +UENV_VIEW="climtools" +_VENV_DIR="${PROC_CHAIN_VENV:-${_REPO_ROOT}/venv}" + +_activate_venv() { + if [[ -f "${_VENV_DIR}/bin/activate" ]]; then + source "${_VENV_DIR}/bin/activate" + echo "Processing Chain environment activated (${_VENV_DIR})" + else + echo "Warning: virtual environment not found at '${_VENV_DIR}'" >&2 + echo "Create it first (inside the uenv):" >&2 + echo " python3 -m venv ${_VENV_DIR}" >&2 + echo " pip install -r ${_REPO_ROOT}/requirements.txt" >&2 + fi +} + +if [[ "${1:-}" == "--no-uenv" ]]; then + # Already inside the uenv – just activate the venv + _activate_venv +else + # Launch a new shell inside the uenv and activate the venv there + uenv start "${UENV_IMAGE}" --view="${UENV_VIEW}" -- bash -c \ + "source '${_VENV_DIR}/bin/activate' 2>/dev/null \ + && echo 'Processing Chain environment activated (${_VENV_DIR})' \ + || echo 'Warning: venv not found at ${_VENV_DIR}. Run: python3 -m venv ${_VENV_DIR} && pip install -r ${_REPO_ROOT}/requirements.txt' >&2; \ + exec bash" +fi + +unset _SCRIPT_DIR _REPO_ROOT _VENV_DIR +unset -f _activate_venv From 061f2e85d5a83a28fbc5154ea9d7fc29c30a07b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 9 Apr 2026 15:34:11 +0200 Subject: [PATCH 33/35] Revise instructions in README and docs --- README.md | 44 ++++++---- docs/environment.rst | 189 ++++++++++++++++++++++++++----------------- 2 files changed, 143 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index f73b50cf..1156393c 100644 --- a/README.md +++ b/README.md @@ -9,43 +9,57 @@ e.g., by creating your own case or adding new jobs. ## Environment Setup -You can set up the Processing Chain environment using either **conda** (recommended) or **pip**. +Two installation paths are available. See the +[full documentation](https://c2sm.github.io/processing-chain/latest/environment.html) +for step-by-step instructions. -**Conda:** +**Option A — Conda (Miniforge, recommended):** - conda env create --prefix $PROJECT/envs/proc-chain -f env/environment.yml - conda activate proc-chain +```bash +# 1. Install Miniforge (once) +wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh +bash Miniforge3-Linux-x86_64.sh + +# 2. Create the environment +conda env create --prefix $PROJECT/envs/proc-chain -f env/environment.yml -**pip (virtual environment):** +# 3. Activate +conda activate proc-chain +``` -> **Note**: `cdo` and `nco` are not available via pip and must be installed separately. +**Option B — pip (virtual environment):** - python3 -m venv $PROJECT/envs/proc-chain - source $PROJECT/envs/proc-chain/bin/activate - pip install -r requirements.txt +> **Note**: `cdo` and `nco` are not available via pip. On HPC systems, load +> them via the module system first (see machine-specific setup below). -For full details, refer to the [official documentation](https://c2sm.github.io/processing-chain/latest/environment.html). +```bash +python3 -m venv $PROJECT/envs/proc-chain +source $PROJECT/envs/proc-chain/bin/activate +pip install -r requirements.txt +``` ### Machine-specific setup -Ready-made environment scripts are provided under `machines/` for supported HPC systems. +Ready-made scripts under `machines/` load system software and activate the +environment in one step. **Euler (ETH Zürich)** ```bash -# Load system modules only (useful in job scripts): +# Load system modules only (e.g. in job scripts): source machines/euler/modules.sh -# Load modules + activate the venv (recommended for interactive sessions): +# Modules + venv activation (interactive sessions): source machines/euler/setup_env.sh ``` **Santis (CSCS)** -On Santis, software is provided via `uenv`. Because `uenv start` spawns a new shell, source-based activation is not supported; use the wrapper instead: +On Santis, `uenv start` spawns a new shell and cannot be sourced; use the +wrapper instead: ```bash -# Start an interactive shell with the full environment: +# One-stop interactive setup (uenv + venv): bash machines/santis/setup_env.sh # Or start the uenv manually: diff --git a/docs/environment.rst b/docs/environment.rst index e9aa6273..fb0dfc42 100644 --- a/docs/environment.rst +++ b/docs/environment.rst @@ -3,123 +3,145 @@ Environment Setup ================= -The following steps allow you to create and use your own virtual environment to run the Processing Chain. You can use either **conda** (recommended) or **pip** with a standard Python virtual environment. Please follow the instructions for your preferred method. The following steps only need to be performed once. +The following steps guide you through setting up a Python environment for the +Processing Chain. **All steps only need to be performed once.** -Option A: Conda ---------------- +Two installation paths are available: -1. Install Miniconda -~~~~~~~~~~~~~~~~~~~~ +- :ref:`Option A ` — **Conda (Miniforge)**: self-contained, + installs its own Python and all tools including ``cdo`` and ``nco``. + Recommended for most users. +- :ref:`Option B ` — **pip**: uses a system-provided Python. + Requires ``cdo`` and ``nco`` to be available separately + (e.g. via the HPC module system — see :ref:`machine-setup`). -Install Miniconda as user-specific Miniconda, e.g., in your ``$HOME`` directory, which is the default location. +.. _conda-option: -.. note:: - Only conda itself should be installed in your ``$HOME``. All environments should be stored in your ``$PROJECT`` directory; otherwise, you risk filling up your ``$HOME`` directory. See below for instructions. +Option A: Conda (Miniforge) +---------------------------- + +Step 1: Install Miniforge +~~~~~~~~~~~~~~~~~~~~~~~~~~ -To install the latest Miniconda, type: +Install Miniforge as a user-specific conda distribution, e.g., into your +``$HOME`` directory (the default location): .. code-block:: bash - wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh - bash Miniconda3-latest-Linux-x86_64.sh + wget https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh + bash Miniforge3-Linux-x86_64.sh -Further details on Miniconda can be found on the `Miniconda documentation page `_. +.. note:: + Only Miniforge itself should be installed in ``$HOME``. Store all + environments in ``$PROJECT`` (or ``$SCRATCH``) to avoid filling up your + home directory. -2. Create the Conda Environment +Further details can be found on the +`Miniforge documentation page `_. + +Step 2: Create the Environment ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a conda environment ``proc-chain`` and install the requirements: +Create a conda environment named ``proc-chain`` with all dependencies: .. code-block:: bash conda env create --prefix $PROJECT/envs/proc-chain -f env/environment.yml -To be able to activate your conda environment by simply using ``conda activate proc-chain`` instead of the full path, add the following to your ``.bashrc``: +To be able to activate the environment with the short name +``proc-chain`` instead of the full path, add the following to your +``.bashrc``: .. code-block:: bash export CONDA_ENVS_PATH=$PROJECT/envs -Activate the environment (use "source activate" in case "conda activate" does not work): +Step 3: Activate the Environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash conda activate proc-chain -If you already have the environment but want to update it: - -.. code-block:: bash +Use ``source activate proc-chain`` if ``conda activate`` does not work. - conda env update --file environment.yml --prune +You are now ready to :ref:`run the chain `. -3. Store user-specific data -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Step 4: Update the Environment (if needed) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To register your email address and standard project account, store them in these files within your home directory: +If the ``environment.yml`` has changed since you created the environment, +update it with: .. code-block:: bash - echo > ~/.acct - echo > ~/.forward + conda env update --prefix $PROJECT/envs/proc-chain --file env/environment.yml --prune -These settings are optional. The Processing Chain will first check the content of those files. If desired, the corresponding variables can be overridden by setting the ``compute_account`` and ``user_mail`` variables in the ``config.yaml`` file. +.. _pip-option: -Option B: pip (virtual environment) +Option B: pip (Virtual Environment) ------------------------------------- -If you prefer not to use conda, you can set up a standard Python virtual environment with pip instead. - .. note:: - Python 3.11 or later is required. Note that ``cdo`` and ``nco`` are not available via pip and must be installed separately (e.g., via your system package manager or a module system). + Python 3.11 or later is required. ``cdo`` and ``nco`` are not available + via pip and must be provided by the system (e.g. loaded via modules on + HPC clusters — see :ref:`machine-setup`). -1. Create and activate the virtual environment -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Step 1: Load System Python +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +On HPC systems, load the appropriate modules before continuing. +See :ref:`machine-setup` for machine-specific instructions. + +On a generic Linux system with Python 3.11+ already installed, skip +directly to Step 2. -Create a virtual environment, for example in your ``$PROJECT`` directory: +Step 2: Create the Virtual Environment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Create a virtual environment, for example in ``$PROJECT``: .. code-block:: bash python3 -m venv $PROJECT/envs/proc-chain - source $PROJECT/envs/proc-chain/bin/activate -2. Install the requirements -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Step 3: Activate and Install +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Install all Python dependencies from ``requirements.txt``: +Activate the environment and install all Python dependencies: .. code-block:: bash + source $PROJECT/envs/proc-chain/bin/activate pip install -r requirements.txt -To update an existing virtual environment: +Step 4: Activate in Future Sessions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Each time you open a new session, activate the environment with: .. code-block:: bash - pip install --upgrade -r requirements.txt + source $PROJECT/envs/proc-chain/bin/activate -3. Activate the environment in future sessions -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +You can add this line to your ``.bashrc`` to activate it automatically, or +use the machine-specific convenience scripts described in :ref:`machine-setup`. -Each time you start a new session, activate the environment with: +Step 5: Update the Environment (if needed) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .. code-block:: bash - source $PROJECT/envs/proc-chain/bin/activate - -You can add this line to your ``.bashrc`` to activate it automatically. - -4. Store user-specific data -~~~~~~~~~~~~~~~~~~~~~~~~~~~ + pip install --upgrade -r requirements.txt -Follow the same steps as described in the conda section above (store -``~/.acct`` and ``~/.forward``) if needed. +.. _machine-setup: Machine-specific Setup ----------------------- +----------------------- -The ``machines/`` directory contains ready-made scripts for loading the -correct system modules and activating the Python environment on supported -HPC systems. Each machine has its own sub-directory: +The ``machines/`` directory provides ready-made scripts that load the +required system software and optionally activate the Python virtual +environment. Each supported machine has its own sub-directory: .. code-block:: text @@ -134,26 +156,28 @@ HPC systems. Each machine has its own sub-directory: Euler (ETH Zürich) ~~~~~~~~~~~~~~~~~~ -**Load modules only** (useful inside Slurm job scripts): +Euler uses the traditional ``module`` system. + +**1. Load modules** (required before using pip or running job scripts): .. code-block:: bash source machines/euler/modules.sh -This loads: +This executes: .. code-block:: bash module load stack/2024-06 gcc/12.2.0 openmpi/4.1.6 python/3.12.8 module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 -**Full interactive-session setup** (modules + venv activation): +**2. One-stop interactive setup** (modules + venv activation): .. code-block:: bash source machines/euler/setup_env.sh -By default this activates the virtual environment at ``/venv``. +By default, this activates the virtual environment at ``/venv``. To use a different location, set ``PROC_CHAIN_VENV`` before sourcing: .. code-block:: bash @@ -161,35 +185,35 @@ To use a different location, set ``PROC_CHAIN_VENV`` before sourcing: export PROC_CHAIN_VENV=$PROJECT/envs/proc-chain source machines/euler/setup_env.sh -If the virtual environment does not exist yet, create it first (see -:ref:`Option B ` above): +If the virtual environment does not exist yet, load the modules first and +then create it (see :ref:`Option B ` above): .. code-block:: bash + source machines/euler/modules.sh python3 -m venv $PROJECT/envs/proc-chain pip install -r requirements.txt Santis (CSCS) ~~~~~~~~~~~~~ -On Santis, software is provided through **uenv** (user environments) instead -of the traditional module system. Because ``uenv start`` spawns a new shell, -it cannot be sourced inside an existing session. +On Santis, software is provided through **uenv** (user environments). +Because ``uenv start`` spawns a new shell, it cannot be sourced inside an +existing session. -**Start an interactive session** with the required environment: +**1. Start an interactive shell** with the required environment: .. code-block:: bash uenv start climtools/25.2:v1 --view=climtools -**Or use the provided wrapper** (starts the uenv and activates the venv): +**2. One-stop interactive setup** (uenv + venv activation, recommended): .. code-block:: bash bash machines/santis/setup_env.sh -If the virtual environment already exists and you are **already inside the -uenv**, you can activate it directly: +If you are already inside the uenv and only need to activate the venv: .. code-block:: bash @@ -202,14 +226,14 @@ To use a custom venv location, set ``PROC_CHAIN_VENV`` first: export PROC_CHAIN_VENV=$SCRATCH/envs/proc-chain bash machines/santis/setup_env.sh -**Run a single command** inside the uenv without entering an interactive shell: +**Run a single command** without entering an interactive shell: .. code-block:: bash uenv run climtools/25.2:v1 --view=climtools -- ./run_chain.py If the virtual environment does not exist yet, enter the uenv first and -create it: +create it (see :ref:`Option B ` above): .. code-block:: bash @@ -217,18 +241,33 @@ create it: python3 -m venv $SCRATCH/envs/proc-chain pip install -r requirements.txt -Adding support for a new machine -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Adding Support for a New Machine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Create a new sub-directory under ``machines/`` following the same -pattern: +Create a new sub-directory under ``machines/`` following the same pattern: .. code-block:: text machines/ └── / - ├── modules.sh - └── setup_env.sh + ├── modules.sh # load system software + └── setup_env.sh # system software + venv activation Use ``machines/euler/`` as a template and adapt the ``module load`` commands for the target system. + +Store User-specific Data (Optional) +------------------------------------- + +To register your email address and standard compute account, store them in +these files in your home directory: + +.. code-block:: bash + + echo > ~/.acct + echo > ~/.forward + +The Processing Chain reads these files automatically. They can be overridden +at any time by setting ``compute_account`` and ``user_mail`` in your case's +``config.yaml``. + From e39a29a65dd7e9ccb79707cf0164915a2f2ee1a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 9 Apr 2026 15:45:04 +0200 Subject: [PATCH 34/35] Use setup_env from machine directory --- jenkins/scripts/jenkins.sh | 8 ++++---- jenkins/scripts/setup_env.sh | 40 ------------------------------------ 2 files changed, 4 insertions(+), 44 deletions(-) delete mode 100755 jenkins/scripts/setup_env.sh diff --git a/jenkins/scripts/jenkins.sh b/jenkins/scripts/jenkins.sh index 03013ad2..27f2c886 100755 --- a/jenkins/scripts/jenkins.sh +++ b/jenkins/scripts/jenkins.sh @@ -27,8 +27,7 @@ set -e -x # Prepare the environment (machine-specific) if [[ $(hostname) == eu-* ]]; then host=euler - module load stack/2024-06 gcc/12.2.0 openmpi/4.1.6 python/3.12.8 || true - module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 || true + source machines/euler/modules.sh || true elif [[ $(hostname) == santis* ]]; then host=santis else @@ -40,7 +39,8 @@ fi if [[ "$use_pip" == true ]]; then if [[ ! -d venv ]]; then echo "Creating Python venv and installing requirements..." - ./jenkins/scripts/setup_env.sh --pip + python3 -m venv venv + venv/bin/pip install -r requirements.txt else echo "Python venv already exists - skipping build." fi @@ -48,7 +48,7 @@ if [[ "$use_pip" == true ]]; then else if ! conda info --envs | grep -q "proc-chain"; then echo "Creating conda environment..." - ./jenkins/scripts/setup_env.sh + conda env create -f environment.yml else echo "Conda environment 'proc-chain' already exists - skipping build." fi diff --git a/jenkins/scripts/setup_env.sh b/jenkins/scripts/setup_env.sh deleted file mode 100755 index 24cb057b..00000000 --- a/jenkins/scripts/setup_env.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash - - -set -ex - -function error { - echo "*** Error: $@" >&2 - exit 1 -} - -# Check if script is called correctly -[[ $(git rev-parse --show-toplevel 2>/dev/null) = $(pwd) ]] || error "$0 not launched from toplevel of repository" - -# Set WORKSPACE to CWD if unset -if [[ -z "$WORKSPACE" ]]; then - export WORKSPACE="$(pwd)" -fi - -# Check for --pip argument -if [[ "$1" == "--pip" ]]; then - # Create venv and install with pip - python3 -m venv --system-site-packages "$WORKSPACE/venv" - source "$WORKSPACE/venv/bin/activate" - pip install -r "$WORKSPACE/requirements.txt" - deactivate -else - # Use Miniforge installer only for conda - wget -O miniforge.sh https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Linux-x86_64.sh - rm -fr miniforge - bash miniforge.sh -b -p "$WORKSPACE/miniforge" - export PATH="$WORKSPACE/miniforge/bin:$PATH" - conda config --set always_yes yes --set changeps1 no - conda config --add channels conda-forge - conda update -n base -c defaults conda - conda env create -f "$WORKSPACE/environment.yml" - source "$WORKSPACE/miniforge/etc/profile.d/conda.sh" - conda activate proc-chain - conda deactivate - rm miniforge.sh -fi \ No newline at end of file From a218545be4d304cf06b99189770f6e1d2dfec078 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20J=C3=A4hn?= Date: Thu, 9 Apr 2026 16:30:56 +0200 Subject: [PATCH 35/35] fix brackets --- cases/icon-test-euler/era5_ic_runjob.cfg | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cases/icon-test-euler/era5_ic_runjob.cfg b/cases/icon-test-euler/era5_ic_runjob.cfg index 5f618866..cf3b39fa 100644 --- a/cases/icon-test-euler/era5_ic_runjob.cfg +++ b/cases/icon-test-euler/era5_ic_runjob.cfg @@ -153,14 +153,14 @@ rm -f data_in.nc wiltingp=(0 0.059 0.151 0.133 0.279 0.335 0.267 0.151) fieldcap=(0 0.244 0.347 0.383 0.448 0.541 0.663 0.347) smi_equation="" -for ilev in {1..4}; do - smi_equation="${smi_equation}SMIL${ilev}=(SMIL${ilev}-${wiltingp[1]})/(${fieldcap[1]}-${wiltingp[1]})*(SLT==1)" - for ist in {2..7}; do - smi_equation="${smi_equation}+(SMIL${ilev}-${wiltingp[$ist]})/(${fieldcap[$ist]}-${wiltingp[$ist]})*(SLT==${ist})" +for ilev in {{1..4}}; do + smi_equation="${{smi_equation}}SMIL${{ilev}}=(SMIL${{ilev}}-${{wiltingp[1]}})/(${{fieldcap[1]}}-${{wiltingp[1]}})*(SLT==1)" + for ist in {{2..7}}; do + smi_equation="${{smi_equation}}+(SMIL${{ilev}}-${{wiltingp[$ist]}})/(${{fieldcap[$ist]}}-${{wiltingp[$ist]}})*(SLT==${{ist}})" done - smi_equation="${smi_equation};" + smi_equation="${{smi_equation}};" done -cdo expr,"${smi_equation}" swvl.nc smil_in.nc +cdo expr,"${{smi_equation}}" swvl.nc smil_in.nc rm -f swvl.nc # Remap SMIL to triangular grid and overwrite