|
| 1 | +#!/usr/bin/env bash |
| 2 | +#SBATCH --job-name=era5_ic_{cfg.casename}_{cfg.startdate_sim_yyyymmddhh} |
| 3 | +#SBATCH --time={cfg.walltime_era5_ic} |
| 4 | +#SBATCH --partition={cfg.compute_queue} |
| 5 | +#SBATCH --constraint={cfg.constraint} |
| 6 | +#SBATCH --ntasks=1 |
| 7 | +#SBATCH --output={cfg.logfile} |
| 8 | +#SBATCH --open-mode=append |
| 9 | +#SBATCH --chdir={cfg.icon_work} |
| 10 | + |
| 11 | +# --------------------------------------------------------------------- |
| 12 | +# ERA5 -> ICON initial conditions (GLOBAL, IC only) |
| 13 | +# |
| 14 | +# This script is submitted by jobs/era5_ic.py. |
| 15 | +# It MUST write the final IC file exactly to: |
| 16 | +# {inidata_filename} |
| 17 | +# |
| 18 | +# Design: |
| 19 | +# - Use case config for input locations + partab |
| 20 | +# - Use staged ICON files from prepare_icon (cfg.input_files_scratch_*) |
| 21 | +# - Keep all intermediate files inside cfg.icon_work |
| 22 | +# --------------------------------------------------------------------- |
| 23 | +# |
| 24 | +set -euo pipefail |
| 25 | +set -x |
| 26 | +ulimit -s unlimited |
| 27 | + |
| 28 | +# Optional: load modules needed for cdo/nco on Euler. |
| 29 | +# Adjust these to your environment/stack. |
| 30 | +module load stack/2024-06 || true |
| 31 | +module load cdo/2.2.2 nco/5.1.6 netcdf-c/4.9.2 || true |
| 32 | + |
| 33 | +# --------------------------------------------------------------------- |
| 34 | +# Inputs (from cfg) |
| 35 | +# --------------------------------------------------------------------- |
| 36 | +ERA5_DIR="{cfg.era5_dir}" |
| 37 | +ERA5_ML="{cfg.era5_ml_filename}" |
| 38 | +ERA5_SFC="{cfg.era5_sfc_filename}" |
| 39 | +# Replace {ymd} placeholder using values prepared in era5_ic.py |
| 40 | +ERA5_ML="${{ERA5_ML/\{ymd\}/{cfg.era5_ymd}}}" |
| 41 | +ERA5_SFC="${{ERA5_SFC/\{ymd\}/{cfg.era5_ymd}}}" |
| 42 | +PARTAB="{cfg.era5_partab}" |
| 43 | +GRID_TRI="{cfg.input_files_scratch_dynamics_grid_filename}" |
| 44 | +EXTPAR="{cfg.input_files_scratch_extpar_filename}" |
| 45 | +OUTFILE="{inidata_filename}" |
| 46 | + |
| 47 | +# --------------------------------------------------------------------- |
| 48 | +# Working directory cleanup |
| 49 | +# --------------------------------------------------------------------- |
| 50 | +work="{cfg.icon_work}/era5_ic_work" |
| 51 | +mkdir -p "$work" |
| 52 | +cd "$work" |
| 53 | + |
| 54 | +# --------------------------------------------------------------------- |
| 55 | +# 1) GRIB preprocessing: pick first timestep and convert to NetCDF |
| 56 | +# --------------------------------------------------------------------- |
| 57 | +# |
| 58 | +# Note: your colleague used splitsel,1; keep it to ensure we only have t0. |
| 59 | +cdo splitsel,1 "${{ERA5_DIR}}/${{ERA5_ML}}" era5_ml_ |
| 60 | +cdo splitsel,1 "${{ERA5_DIR}}/${{ERA5_SFC}}" era5_sfc_ |
| 61 | + |
| 62 | +# Find the produced split files (avoid hardcoding the exact suffix) |
| 63 | +ml_grb="$(ls -1 era5_ml_* | head -n 1)" |
| 64 | +sfc_grb="$(ls -1 era5_sfc_* | head -n 1)" |
| 65 | +cdo -t ecmwf -f nc copy "$ml_grb" era5_ml.nc |
| 66 | +cdo -t ecmwf -f nc copy "$sfc_grb" era5_sfc.nc |
| 67 | +cdo merge era5_ml.nc era5_sfc.nc era5_original.nc |
| 68 | + |
| 69 | +# Rename variables / metadata to ICON-consistent naming via partab |
| 70 | +# (Your partab is the "contract" between ERA5 and ICON naming expectations.) |
| 71 | +cdo setpartabn,"$PARTAB",convert era5_original.nc tmp.nc |
| 72 | + |
| 73 | +# Order variables (helps reproducibility and easier diffs) |
| 74 | +ncks tmp.nc data_in.nc |
| 75 | +rm -f tmp.nc era5_ml.nc era5_sfc.nc era5_original.nc "$ml_grb" "$sfc_grb" |
| 76 | + |
| 77 | +# --------------------------------------------------------------------- |
| 78 | +# 2) Build the ICON triangular grid description for CDO remapping |
| 79 | +# --------------------------------------------------------------------- |
| 80 | +cdo -s selgrid,1 "$GRID_TRI" triangular-grid.nc |
| 81 | + |
| 82 | +# --------------------------------------------------------------------- |
| 83 | +# 3) Land/sea-aware remapping for sensitive surface variables |
| 84 | +# --------------------------------------------------------------------- |
| 85 | +# |
| 86 | +# Input land-sea mask from renamed ERA5 data |
| 87 | +cdo selname,LSM data_in.nc LSM_in.nc |
| 88 | +ncrename -h -v LSM,FR_LAND LSM_in.nc |
| 89 | + |
| 90 | +# Output land fraction from EXTPAR |
| 91 | +cdo selname,FR_LAND "$EXTPAR" LSM_out_tmp.nc |
| 92 | + |
| 93 | +# Add time dimension and align time coordinate |
| 94 | +ncecat -O -u time LSM_out_tmp.nc LSM_out_tmp.nc |
| 95 | +ncks -h -A -v time LSM_in.nc LSM_out_tmp.nc |
| 96 | + |
| 97 | +# Build land/ocean masks (input and output) |
| 98 | +cdo -L setctomiss,0. -ltc,0.5 LSM_in.nc oceanmask_in.nc |
| 99 | +cdo -L setctomiss,0. -gec,0.5 LSM_in.nc landmask_in.nc |
| 100 | +cdo -L setctomiss,0. -ltc,0.5 LSM_out_tmp.nc oceanmask_out.nc |
| 101 | +cdo -L setctomiss,0. -gec,0.5 LSM_out_tmp.nc landmask_out.nc |
| 102 | +cdo setrtoc2,0.5,1.0,1,0 LSM_out_tmp.nc LSM_out.nc |
| 103 | +rm -f LSM_in.nc LSM_out_tmp.nc |
| 104 | + |
| 105 | +# Variables defined only on sea |
| 106 | +ncks -h -v SST,CI data_in.nc datasea_in.nc |
| 107 | + |
| 108 | +# Variables defined on both but should not mix land/sea |
| 109 | +ncks -h -v SKT,STL1,STL2,STL3,STL4,ALB_SNOW,W_SNOW,T_SNOW data_in.nc dataland_in.nc |
| 110 | + |
| 111 | +# Ocean part: mask -> fill -> remap -> unmask |
| 112 | +cdo div dataland_in.nc oceanmask_in.nc tmp1_land.nc |
| 113 | +cdo div datasea_in.nc oceanmask_in.nc tmp1_sea.nc |
| 114 | +cdo setmisstodis tmp1_land.nc tmp2_land.nc |
| 115 | +cdo setmisstodis tmp1_sea.nc tmp2_sea.nc |
| 116 | +cdo remapdis,triangular-grid.nc tmp2_land.nc tmp3_land.nc |
| 117 | +cdo remapdis,triangular-grid.nc tmp2_sea.nc tmp3_sea.nc |
| 118 | +cdo div tmp3_land.nc oceanmask_out.nc dataland_ocean_out.nc |
| 119 | +cdo div tmp3_sea.nc oceanmask_out.nc datasea_ocean_out.nc |
| 120 | +rm -f tmp*_land.nc tmp*_sea.nc oceanmask_in.nc oceanmask_out.nc |
| 121 | + |
| 122 | +# Land part: mask -> fill -> remap -> unmask |
| 123 | +cdo div dataland_in.nc landmask_in.nc tmp1.nc |
| 124 | +cdo setmisstodis tmp1.nc tmp2.nc |
| 125 | +cdo remapdis,triangular-grid.nc tmp2.nc tmp3.nc |
| 126 | +cdo div tmp3.nc landmask_out.nc dataland_land_out.nc |
| 127 | +rm -f tmp*.nc landmask_in.nc landmask_out.nc dataland_in.nc datasea_in.nc |
| 128 | + |
| 129 | +# Merge land+ocean contributions |
| 130 | +cdo ifthenelse LSM_out.nc dataland_land_out.nc dataland_ocean_out.nc dataland_out.nc |
| 131 | +rm -f dataland_ocean_out.nc dataland_land_out.nc |
| 132 | + |
| 133 | +# Remap all remaining variables together |
| 134 | +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 |
| 135 | +cdo -s remapdis,triangular-grid.nc datarest_in.nc era5_final.nc |
| 136 | +rm -f datarest_in.nc |
| 137 | + |
| 138 | +# Fill missing SST/CI after remap (sea-only fields) |
| 139 | +cdo setmisstodis -selname,SST,CI datasea_ocean_out.nc datasea_ocean_out_filled.nc |
| 140 | +rm -f datasea_ocean_out.nc |
| 141 | + |
| 142 | +# Merge special remapped variables + land fraction (renamed back to LSM) |
| 143 | +ncks -h -A dataland_out.nc era5_final.nc |
| 144 | +ncks -h -A datasea_ocean_out_filled.nc era5_final.nc |
| 145 | +ncks -h -A -v FR_LAND LSM_out.nc era5_final.nc |
| 146 | +ncrename -h -v FR_LAND,LSM era5_final.nc |
| 147 | +rm -f LSM_out.nc dataland_out.nc datasea_ocean_out_filled.nc |
| 148 | + |
| 149 | +# --------------------------------------------------------------------- |
| 150 | +# 4) Soil moisture index conversion (ERA5 SWVL -> ICON-style SMIL) |
| 151 | +# --------------------------------------------------------------------- |
| 152 | +# Extract soil moisture and soil type |
| 153 | +ncks -h -v SMIL1,SMIL2,SMIL3,SMIL4,SLT data_in.nc swvl.nc |
| 154 | +rm -f data_in.nc |
| 155 | + |
| 156 | +# IFS soil constants (documented in ERA5 data documentation) |
| 157 | +wiltingp=(0 0.059 0.151 0.133 0.279 0.335 0.267 0.151) |
| 158 | +fieldcap=(0 0.244 0.347 0.383 0.448 0.541 0.663 0.347) |
| 159 | +smi_equation="" |
| 160 | +for ilev in {1..4}; do |
| 161 | + smi_equation="${smi_equation}SMIL${ilev}=(SMIL${ilev}-${wiltingp[1]})/(${fieldcap[1]}-${wiltingp[1]})*(SLT==1)" |
| 162 | + for ist in {2..7}; do |
| 163 | + smi_equation="${smi_equation}+(SMIL${ilev}-${wiltingp[$ist]})/(${fieldcap[$ist]}-${wiltingp[$ist]})*(SLT==${ist})" |
| 164 | + done |
| 165 | + smi_equation="${smi_equation};" |
| 166 | +done |
| 167 | +cdo expr,"${smi_equation}" swvl.nc smil_in.nc |
| 168 | +rm -f swvl.nc |
| 169 | + |
| 170 | +# Remap SMIL to triangular grid and overwrite |
| 171 | +cdo -s remapdis,triangular-grid.nc smil_in.nc smil_out.nc |
| 172 | +ncks -A -v SMIL1,SMIL2,SMIL3,SMIL4 smil_out.nc era5_final.nc |
| 173 | +rm -f smil_in.nc smil_out.nc |
| 174 | + |
| 175 | +# --------------------------------------------------------------------- |
| 176 | +# 5) Create LNPS (log surface pressure) and finalize dimensions |
| 177 | +# --------------------------------------------------------------------- |
| 178 | +cdo expr,'LNPS=ln(PS);' era5_final.nc tmp.nc |
| 179 | +ncks -A -v LNPS tmp.nc era5_final.nc |
| 180 | +rm -f tmp.nc |
| 181 | + |
| 182 | +# ICON conventions: rename dimensions |
| 183 | +ncrename -h -d cell,ncells era5_final.nc |
| 184 | +ncrename -h -d nv,vertices era5_final.nc |
| 185 | + |
| 186 | +# Write final IC file to the exact path ICON will read later |
| 187 | +mkdir -p "$(dirname "$OUTFILE")" |
| 188 | +ncks era5_final.nc "$OUTFILE" |
| 189 | + |
| 190 | +# cleanup |
| 191 | +rm -f era5_final.nc triangular-grid.nc |
| 192 | +echo "Wrote ICON initial condition file: $OUTFILE" |
0 commit comments