ecconf.cfg 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. #!/bin/bash
  2. # Platform dependent configuration functions for the 'zenobe' machine
  3. #(zenobe.hpc.cenaero.be)
  4. function configure()
  5. {
  6. # This function should configure all settings/modules needed to
  7. # later prepare the EC-Earth run directory and set variables used
  8. # in the run script
  9. # SCRATCH is not defined in MN3, define it here
  10. # and also make sure it is defined when compiling
  11. export SCRATCH=/gpfs/scratch/acad/ecearth/${USER}
  12. # Configure paths for building/running EC-Earth
  13. ecearth_src_dir=${HOME}/models/ecearth_3.3.3.2/sources
  14. run_dir=/gpfs/scratch/acad/ecearth/${USER}/ecearth/run/${exp_name}
  15. ini_data_dir=/gpfs/scratch/acad/ecearth/data/bsc32/v3.3.3.2/inidata
  16. archive_dir=/gpfs/scratch/acad/ecearth/${USER}/ecearth/archive/${exp_name}
  17. # File for standard output.
  18. # NOTE: This will be modified for restart jobs!
  19. stdout_file=${SLURM_SUBMIT_DIR-$PWD}/${SLURM_JOB_NAME-"local"}_${SLURM_JOB_ID-"id"}.log
  20. # Resubmit this job for automatic restarts? [true/false]
  21. # Also, add options for the resubmit command here.
  22. resubmit_job=true
  23. resubmit_opt=""
  24. module purge
  25. module load EasyBuild/2023a
  26. export MODULEPATH=$MODULEPATH:/gpfs/projects/acad/ecearth/softs/easybuild/2023a/modules/all
  27. module load netCDF-Fortran/4.6.1-iompi-2023a
  28. module load CDO/2.2.2-iompi-2023a
  29. module load NCO/5.1.3-iomkl-2023a
  30. module load ecCodes/2.31.0-iompi-2023a
  31. # Configure grib api paths
  32. export GRIB_DEFINITION_PATH=${HOME}/models/ecearth_3.3.3.2/sources/util/grib_table_126:${EBROOTECCODES}/share/eccodes/definitions
  33. export GRIB_SAMPLES_PATH=${EBROOTECCODES}/share/eccodes/ifs_samples/grib1
  34. export GRIB_BIN_PATH=${EBROOTECCODES}/bin
  35. # Configure number of processors per node
  36. proc_per_node=128
  37. # Use machinefiles or not
  38. [[ `echo "$use_machinefile" | tr '[:upper:]' '[:lower:]'` == true ]] && use_machinefile=true || use_machinefile=false
  39. ulimit -s unlimited
  40. # Load specific MPI environment configuration
  41. configure_mpi
  42. }
  43. function configure_python()
  44. {
  45. # specific for python+eccodes setup - used for OSM pre/post-processing
  46. # it would be simple to do the following in configure
  47. # module load eccodes/2.8.0 python/2.7.13
  48. module load eccodes/2.8.0 python/2.7.13
  49. unset GRIB_DEFINITION_PATH
  50. unset GRIB_SAMPLES_PATH
  51. unset GRIB_BIN_PATH
  52. export GRIB_BIN_PATH=/apps/ECCODES/2.8.0/INTEL/bin
  53. }
  54. function configure_mpi()
  55. {
  56. [ -z "${OMP_NUM_THREADS-}" ] && export OMP_NUM_THREADS=1
  57. #export I_MPI_DEBUG=5
  58. #export I_MPI_ADJUST_BCAST=3
  59. #export PSM2_MTU=8196
  60. #export PSM2_MEMORY=large
  61. #export PSM2_MQ_RNDV_HFI_THRESH=1
  62. #export I_MPI_FABRIC=ofi
  63. #unset I_MPI_PMI_LIBRARY
  64. #export I_MPI_JOB_RESPECT_PROCESS_PLACEMENT=0
  65. #export I_MPI_FABRICS=shm:ofi
  66. }
  67. function get_hosts()
  68. {
  69. # This function uses a scheduler command to get the hosts allocated for the current job
  70. hosts=(`scontrol show hostname | paste -s`)
  71. }
  72. function machinefile_config()
  73. {
  74. # User configuration starts here
  75. # hard-coded c4mip configurations, must use the proper _numproc settings
  76. if has_config ifs nemo pisces rnfmapper xios lpjg ; then
  77. if ! has_config tm5 ; then
  78. ifs_ppn=48 ; [[ ${ifs_numproc} != 336 ]] && info "wrong numproc setting for ifs in machinefile_config" || true
  79. nem_ppn=43 ; [[ ${nem_numproc} != 380 ]] && info "wrong numproc setting for nemo in machinefile_config" || true
  80. xio_ppn=5 ; [[ ${xio_numproc} != 5 ]] && info "wrong numproc setting for xios in machinefile_config" || true
  81. lpjg_ppn=5 ; [[ ${lpjg_numproc} != 40 ]] && info "wrong numproc setting for lpjg in machinefile_config" || true
  82. else
  83. ifs_ppn=48 ; [[ ${ifs_numproc} != 256 ]] && info "wrong numproc setting for ifs in machinefile_config" || true
  84. nem_ppn=46 ; [[ ${nem_numproc} != 192 ]] && info "wrong numproc setting for nemo in machinefile_config" || true
  85. xio_ppn=2 ; [[ ${xio_numproc} != 2 ]] && info "wrong numproc setting for xios in machinefile_config" || true
  86. lpjg_ppn=2 ; [[ ${lpjg_numproc} != 8 ]] && info "wrong numproc setting for lpjg in machinefile_config" || true
  87. tm5_ppn=4 ; [[ ${tm5_numproc} != 4 ]] && info "wrong numproc setting for tm5 in machinefile_config" || true
  88. fi
  89. else
  90. # Add any new exclusive binary here
  91. ifs_exc=TRUE
  92. nem_exc=TRUE
  93. xio_exc=TRUE
  94. lpjg_exc=TRUE
  95. tm5_exc=TRUE
  96. # Modify the allocation to each binary using more than one process here
  97. ifs_ppn=48
  98. nem_ppn=48
  99. xio_ppn=48
  100. lpjg_ppn=48
  101. tm5_ppn=45
  102. fi
  103. }
  104. function machinefile_init()
  105. {
  106. # Get max processes per node from the platform variable
  107. max_ppn=$proc_per_node
  108. components=( ifs nem xio rnf amip lpjg )
  109. if $(has_config tm5)
  110. then
  111. components=( "${components[@]}" "tm5" )
  112. fi
  113. for component in ${components[@]}
  114. do
  115. eval ${component}_exc=FALSE
  116. eval ${component}_ppn=1
  117. done
  118. # Call user configuration and get_host functions
  119. machinefile_config
  120. get_hosts
  121. # Declare array to store the processes as they are assigned
  122. declare -a -g processes_hosts
  123. for n in `seq 0 ${#hosts[@]}`
  124. do
  125. processes_hosts[$n]=0
  126. done
  127. > machinefile
  128. current_hostid=0
  129. }
  130. machinefile_find_available_node()
  131. {
  132. while [ $((${processes_hosts[$current_hostid]} + ${!ppn})) -gt $max_ppn ]
  133. do
  134. let "current_hostid += 1"
  135. done
  136. }
  137. machinefile_add()
  138. {
  139. total_proc=$2
  140. # Iterate through all the possible binaries
  141. for component in ${components[@]}
  142. do
  143. binary="${component}_exe_file"
  144. exclusive="${component}_exc"
  145. # Check if the current binary matches the input executable
  146. if [ ./$(basename ${!binary}) = "$1" ]
  147. then
  148. ppn="${component}_ppn"
  149. # Exclusive mode: start allocation at the first empty node
  150. if [[ ${!exclusive} == "TRUE" ]]
  151. then
  152. while [ ${processes_hosts[$current_hostid]} -gt 0 ]
  153. do
  154. let "current_hostid += 1"
  155. done
  156. # Shared mode: start allocation in the first node with enough free cores
  157. # Notice that only the first node is checked
  158. # Then, if a previous binary had "exc=TRUE", allocation space is not ensure in subsequent nodes
  159. else
  160. current_hostid=0
  161. machinefile_find_available_node
  162. fi
  163. # Allocate ppn cores in each of the subsequent nodes till there are no more processes to assign
  164. count=0
  165. while [ ${total_proc} -gt 0 ]
  166. do
  167. if [ ${current_hostid} -ge ${#hosts[@]} ]
  168. then
  169. echo "Not enough computing nodes"
  170. exit 1
  171. fi
  172. current_hostname=${hosts[$current_hostid]}
  173. while [[ ${total_proc} -gt 0 && ${count} -lt ${!ppn} ]]
  174. do
  175. echo ${hosts[$current_hostid]} >> machinefile
  176. let "count += 1"
  177. let "processes_hosts[$current_hostid] += 1"
  178. let "total_proc -= 1" || true
  179. done
  180. if [ ${count} -eq ${!ppn} ]
  181. then
  182. let "current_hostid += 1"
  183. machinefile_find_available_node
  184. count=0
  185. fi
  186. done
  187. fi
  188. done
  189. }
  190. function launch()
  191. {
  192. # Compute and check the node distribution
  193. info "======================="
  194. info "Node/proc distribution:"
  195. info "-----------------------"
  196. info "IFS: ${ifs_numproc}"
  197. info "NEMO: ${nem_numproc}"
  198. info "XIOS: ${xio_numproc}"
  199. info "RUNOFF: ${rnf_numproc}"
  200. info "======================="
  201. cmd="mpirun"
  202. cat /dev/null > prog.conf
  203. proc_id=0
  204. if [ "$use_machinefile" = "true" ]
  205. then
  206. cmd="mpirun -machinefile machinefile"
  207. machinefile_init
  208. fi
  209. while (( "$#" ))
  210. do
  211. # Get number of MPI ranks and executable name
  212. nranks=$1
  213. executable=./$(basename $2)
  214. if [ "$use_machinefile" = "true" ]
  215. then
  216. machinefile_add $executable $nranks
  217. fi
  218. shift
  219. shift
  220. cmd+=" -n $nranks $executable"
  221. # Add any arguments to executable
  222. while (( "$#" )) && [ "$1" != "--" ]
  223. do
  224. cmd+=" $1"
  225. shift
  226. done
  227. shift || true
  228. for i in $(eval echo "{1..${nranks}}")
  229. do
  230. echo "$proc_id ${executable}" >> prog.conf
  231. proc_id=$(($proc_id+1))
  232. done
  233. # Add colon of more executables follow
  234. (( "$#" )) && cmd+=" :"
  235. done
  236. #cmd="srun --kill-on-bad-exit=1 --multi-prog prog.conf"
  237. pwd
  238. echo $cmd
  239. #exit
  240. $cmd
  241. }
  242. function finalise()
  243. {
  244. # This function should execute of any post run functionality, e.g.
  245. # platform dependent cleaning or a resubmit
  246. if ${resubmit_job} && [ $(date -d "${leg_end_date}" +%s) -lt $(date -d "${run_end_date}" +%s) ]
  247. then
  248. info "Resubmitting job for leg $((leg_number+1))"
  249. # Need to go to start_dir to find the run script
  250. cd ${start_dir}
  251. # Submit command
  252. echo "sbatch -N ${SLURM_JOB_NUM_NODES-"1"} -o ${run_dir}/$(basename ${stdout_file}).$(printf %03d $((leg_number+1))) \
  253. -e ${run_dir}/$(basename ${stdout_file}).$(printf %03d $((leg_number+1))) -d ${SLURM_JOB_ID-"id"} \
  254. ./${SLURM_JOB_NAME-"run"}.sh"
  255. # Note: This does not work if you specify a job name with sbatch -J jobname!
  256. sbatch -N ${SLURM_JOB_NUM_NODES-"1"} \
  257. -o ${run_dir}/$(basename ${stdout_file}).$(printf %03d $((leg_number+1))) \
  258. -e ${run_dir}/$(basename ${stdout_file}).$(printf %03d $((leg_number+1))) \
  259. -d ${SLURM_JOB_ID-"id"} \
  260. ./${SLURM_JOB_NAME-"run"}.sh
  261. fi
  262. }