rc-qlc 0.3.24__cp311-cp311-win32.whl → 0.3.27__cp311-cp311-win32.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. qlc/cli/__init__.py +100 -9
  2. qlc/cli/installer.py +23 -5
  3. qlc/cli/qlc_main.py +54 -32
  4. qlc/cli/qlc_py_main.py +43 -38
  5. qlc/config/json/qlc_config.json +94 -10
  6. qlc/config/nml/mars_A1_sfc.nml +4 -5
  7. qlc/config/nml/mars_A3_sfc.nml +0 -1
  8. qlc/config/nml/mars_B1_pl.nml +2 -2
  9. qlc/{examples/cams_case_1/config/nml/mars_A3_sfc.nml → config/nml/mars_B1_sfc.nml} +7 -8
  10. qlc/config/nml/mars_C1_pl.nml +1 -1
  11. qlc/{examples/cams_case_1/config/nml/mars_C1_pl.nml → config/nml/mars_C1_sfc.nml} +7 -8
  12. qlc/config/nml/mars_C2_pl.nml +1 -1
  13. qlc/{examples/cams_case_1/config/qlc_cams.conf → config/qlc.conf} +80 -18
  14. qlc/{examples/cams_case_1/mod/b2ro/2018/b2ro_20181215-20181231_A3_sfc.grb → doc/CAMS_b2ro-b2rn_20181201-20181221_qlc_Z1-png_202509090814.pdf} +0 -0
  15. qlc/doc/README.md +213 -49
  16. qlc/doc/USAGE.md +266 -29
  17. qlc/examples/cams_case_1/mod/b2rn/2018/b2rn_20181201-20181221_B1_pl.grb +0 -0
  18. qlc/examples/cams_case_1/mod/b2rn/2018/b2rn_20181201-20181221_C1_sfc.grb +0 -0
  19. qlc/examples/cams_case_1/mod/b2ro/2018/b2ro_20181201-20181221_B1_pl.grb +0 -0
  20. qlc/examples/cams_case_1/mod/b2ro/2018/b2ro_20181201-20181221_C1_sfc.grb +0 -0
  21. qlc/install.py +272 -107
  22. qlc/py/__main__.cp311-win32.pyd +0 -0
  23. qlc/py/averaging.cp311-win32.pyd +0 -0
  24. qlc/py/bias_plots.cp311-win32.pyd +0 -0
  25. qlc/py/control.cp311-win32.pyd +0 -0
  26. qlc/py/io.cp311-win32.pyd +0 -0
  27. qlc/py/loadmod.cp311-win32.pyd +0 -0
  28. qlc/py/loadobs.cp311-win32.pyd +0 -0
  29. qlc/py/logging_utils.cp311-win32.pyd +0 -0
  30. qlc/py/map_plots.cp311-win32.pyd +0 -0
  31. qlc/py/matched.cp311-win32.pyd +0 -0
  32. qlc/py/plot_config.cp311-win32.pyd +0 -0
  33. qlc/py/plotting.cp311-win32.pyd +0 -0
  34. qlc/py/plugin_loader.cp311-win32.pyd +0 -0
  35. qlc/py/processing.cp311-win32.pyd +0 -0
  36. qlc/py/scatter_plots.cp311-win32.pyd +0 -0
  37. qlc/py/stations.cp311-win32.pyd +0 -0
  38. qlc/py/statistics.cp311-win32.pyd +0 -0
  39. qlc/py/style.cp311-win32.pyd +0 -0
  40. qlc/py/timeseries_plots.cp311-win32.pyd +0 -0
  41. qlc/py/utils.cp311-win32.pyd +0 -0
  42. qlc/py/version.cp311-win32.pyd +0 -0
  43. qlc/sh/qlc_A1.sh +30 -11
  44. qlc/sh/qlc_B1a.sh +1 -18
  45. qlc/sh/qlc_B2.sh +8 -1
  46. qlc/sh/qlc_C5.sh +90 -65
  47. qlc/sh/qlc_D1.sh +287 -56
  48. qlc/sh/qlc_Z1.sh +6 -6
  49. qlc/sh/qlc_batch.sh +61 -0
  50. qlc/sh/qlc_common_functions.sh +17 -29
  51. qlc/sh/qlc_main.sh +49 -26
  52. qlc/sh/tex_template/beamercolorthemeCAMS2_35.sty +51 -0
  53. qlc/sh/tex_template/beamerfontthemeCAMS2_35.sty +166 -0
  54. qlc/sh/tex_template/beamerthemeCAMS2_35.sty +25 -0
  55. qlc/sh/tex_template/subcaption.sty +170 -0
  56. qlc/sh/tex_template/template.tex +109 -0
  57. rc_qlc-0.3.27.dist-info/METADATA +309 -0
  58. rc_qlc-0.3.27.dist-info/RECORD +103 -0
  59. qlc/config/json/qlc_config_example_1a_all-obs.json +0 -237
  60. qlc/config/json/qlc_config_example_1b_all-mod.json +0 -353
  61. qlc/config/json/qlc_config_example_1c_all-coll.json +0 -266
  62. qlc/config/json/qlc_config_example_2a_all-obs.json +0 -237
  63. qlc/config/json/qlc_config_example_2b_all-mod.json +0 -353
  64. qlc/config/json/qlc_config_example_2c_all-coll.json +0 -265
  65. qlc/config/json/qlc_config_example_3a-us_obs.json +0 -82
  66. qlc/config/json/qlc_config_example_3b-us_mod.json +0 -122
  67. qlc/config/json/qlc_config_example_3c-us_coll.json +0 -46
  68. qlc/config/json/qlc_config_example_4a_eu-obs.json +0 -41
  69. qlc/config/json/qlc_config_example_4b_eu-mod.json +0 -122
  70. qlc/config/json/qlc_config_example_4c_eu-coll.json +0 -45
  71. qlc/config/qlc_cams.conf +0 -26
  72. qlc/config/qlc_test.conf +0 -26
  73. qlc/config/qlc_tex.conf +0 -107
  74. qlc/examples/cams_case_1/config/json/qlc_config.json +0 -41
  75. qlc/examples/cams_case_1/config/nml/mars_B1_pl.nml +0 -19
  76. qlc/examples/cams_case_1/mod/iqi9/2018/iqi9_20181215-20181231_A3_sfc.grb +0 -0
  77. qlc/sh/qlc_start.sh +0 -23
  78. qlc/sh/qlc_start_batch.sh +0 -46
  79. rc_qlc-0.3.24.dist-info/METADATA +0 -142
  80. rc_qlc-0.3.24.dist-info/RECORD +0 -113
  81. {rc_qlc-0.3.24.dist-info → rc_qlc-0.3.27.dist-info}/WHEEL +0 -0
  82. {rc_qlc-0.3.24.dist-info → rc_qlc-0.3.27.dist-info}/entry_points.txt +0 -0
  83. {rc_qlc-0.3.24.dist-info → rc_qlc-0.3.27.dist-info}/licenses/LICENSE +0 -0
  84. {rc_qlc-0.3.24.dist-info → rc_qlc-0.3.27.dist-info}/top_level.txt +0 -0
qlc/sh/qlc_B2.sh CHANGED
@@ -1,4 +1,4 @@
1
- #!/bin/sh -e
1
+ #!/bin/bash -e
2
2
 
3
3
  # Source the configuration file to load the settings
4
4
  . "$CONFIG_FILE"
@@ -64,6 +64,8 @@ for exp in $exps ; do
64
64
  mkdir -p "$tpath"
65
65
  fi
66
66
 
67
+ log "----------------------------------------------------------------------------------------"
68
+
67
69
  for name in "${MARS_RETRIEVALS[@]}"; do
68
70
 
69
71
  # Define the corresponding arrays based on the name
@@ -76,12 +78,16 @@ for exp in $exps ; do
76
78
  ncvar=("${!ncvar_var}")
77
79
  myvar=("${!myvar_var}")
78
80
 
81
+ log "ipath : ${ipath}"
82
+ log "tpath : ${tpath}"
83
+
79
84
  log "name : ${name}"
80
85
  log "param: ${param}"
81
86
  log "ncvar: ${ncvar}"
82
87
  log "myvar: ${myvar}"
83
88
 
84
89
  cd $ipath
90
+ pwd -P
85
91
 
86
92
  set +e
87
93
  # List available NC-files
@@ -92,6 +98,7 @@ for exp in $exps ; do
92
98
  log "ncfiles : ${ncfiles}"
93
99
 
94
100
  cd $tpath
101
+ pwd -P
95
102
 
96
103
  # Loop through the variables for this $name
97
104
  for ((i = 0; i < ${#ncvar[@]}; i++)); do
qlc/sh/qlc_C5.sh CHANGED
@@ -1,4 +1,4 @@
1
- #!/bin/sh -e
1
+ #!/bin/bash -e
2
2
 
3
3
  # Source the configuration file to load the settings
4
4
  . "$CONFIG_FILE"
@@ -23,21 +23,56 @@ done
23
23
  log "$0 ANALYSIS_DIRECTORY = $ANALYSIS_DIRECTORY"
24
24
 
25
25
  # module load for ATOS
26
- myOS="`uname -s`"
27
- HOST=`hostname -s | awk '{printf $1}' | cut -c 1`
28
- log "HOST = ${HOST} | `hostname -s`"
29
- log "myOS = ${myOS}"
30
- if [ "${HOST}" == "a" ] && [ "${myOS}" != "Darwin" ]; then
31
- module load ferret/7.6.3
26
+ myOS="$(uname -s)"
27
+ HOST="$(hostname -s | cut -c 1)"
28
+ log "HOST = ${HOST} | $(hostname -s)"
29
+ log "myOS = ${myOS}"
30
+
31
+ if [ "${HOST}" = "a" ] && [ "${myOS}" != "Darwin" ]; then
32
+ # Only on ATOS-like hosts (non-macOS, short host starting with 'a')
33
+ if command -v module >/dev/null 2>&1; then
34
+ module load ferret/7.6.3
35
+ else
36
+ log "[WARN] 'module' command not found; skipping ferret module load"
37
+ fi
38
+ else
39
+ # Conda activation for pyferret_env
40
+ if [ -f "$HOME/miniforge3/etc/profile.d/conda.sh" ]; then
41
+ . "$HOME/miniforge3/etc/profile.d/conda.sh"
42
+ conda activate pyferret_env
43
+ elif [ -f "$HOME/miniforge3/bin/activate" ]; then
44
+ . "$HOME/miniforge3/bin/activate" "pyferret_env"
45
+ else
46
+ log "[WARN] Conda activation scripts not found; relying on PATH for pyferret"
47
+ fi
32
48
  fi
33
49
 
34
- # Check if pyferret exists
35
- if ! command_exists pyferret; then
36
- log "Error: pyferret command not found" >&2
37
- exit 1
38
- else
39
- log "Success: pyferret command found"
40
- which pyferret
50
+ # Determine the pyferret command to use.
51
+ # First, check if pyferret is in the PATH (e.g., from "pip install 'rc-qlc[ferret]'").
52
+ # If not, fall back to the direct path in the conda environment as per the README.
53
+ PYFERRET_CMD=""
54
+ if command -v pyferret &> /dev/null; then
55
+ log "Using 'pyferret' found in system PATH."
56
+ PYFERRET_CMD="pyferret"
57
+ elif [ -x "$HOME/miniforge3/envs/pyferret_env/bin/pyferret" ]; then
58
+ log "Using 'pyferret' from dedicated conda environment."
59
+ PYFERRET_CMD="$HOME/miniforge3/envs/pyferret_env/bin/pyferret"
60
+ fi
61
+
62
+ # Check if we found a valid pyferret command
63
+ if [ -z "$PYFERRET_CMD" ]; then
64
+ log "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
65
+ log "WARNING: pyferret command not found."
66
+ log "The qlc_C5.sh script requires pyferret for generating global map plots."
67
+ log "You can install it as an optional dependency with:"
68
+ log " pip install 'rc-qlc[ferret]'"
69
+ log "For more detailed instructions (e.g., for macOS), please see the"
70
+ log "'Advanced Topics' section in the main README.md file."
71
+ log "Alternatively, you can disable this script by commenting out 'C5' in the"
72
+ log "SUBSCRIPT_NAMES array in your qlc.conf file."
73
+ log "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
74
+ log "Skipping pyferret plots and exiting script gracefully."
75
+ exit 0
41
76
  fi
42
77
 
43
78
  # Create output directory if not existent
@@ -59,6 +94,7 @@ sDate="${sDat//[-:]/}"
59
94
  eDate="${eDat//[-:]/}"
60
95
  mDate="$sDate-$eDate"
61
96
  ext="$PLOTEXTENSION"
97
+ ulev="$UTLS"
62
98
 
63
99
  hpath="$PLOTS_DIRECTORY/${exp1}-${exp2}_${mDate}"
64
100
 
@@ -80,14 +116,15 @@ for exp in $exps ; do
80
116
  log "Processing ${PLOTTYPE} plot for experiment: $exp"
81
117
 
82
118
  log "QLTYPE : $QLTYPE"
83
- log "TEAM_PREFIX : $TEAM_PREFIX"
84
- log "EVALUATION_PREFIX: $EVALUATION_PREFIX"
85
- log "MODEL_RESOLUTION : $MODEL_RESOLUTION"
86
- log "TIME_RESOLUTION : $TIME_RESOLUTION"
119
+ log "TEAM_PREFIX : ${TEAM_PREFIX}"
120
+ log "EVALUATION_PREFIX: ${EVALUATION_PREFIX}"
121
+ log "MODEL_RESOLUTION : ${MODEL_RESOLUTION}"
122
+ log "TIME_RESOLUTION : ${TIME_RESOLUTION}"
87
123
  log "mDate : $mDate"
88
124
  log "ext : $ext"
89
125
  log "exp1 : $exp1"
90
126
  log "exp2 : $exp2"
127
+ log "ulev : $ulev"
91
128
 
92
129
  # definition of plot file base name
93
130
  pfile="${TEAM_PREFIX}_${exp1}-${exp2}_${mDate}_${QLTYPE}"
@@ -198,7 +235,7 @@ for exp in $exps ; do
198
235
  else
199
236
  plev="${nlev}"
200
237
  fi
201
- log "${plev} plot for: $pvar"
238
+ log "Model level array index ${plev} for: $pvar"
202
239
 
203
240
  # definition of plot files for each exp + variable (log, diff for exp1)
204
241
  # tfile="${pfile}_${name}_${pvar}_${exp}"
@@ -213,15 +250,7 @@ for exp in $exps ; do
213
250
  lat='`lat`'
214
251
  lev='`lev`'
215
252
  tim='`tim`'
216
- # crude workaround, needs to be implemented properly
217
- # plev="21" # 1000 hPa
218
- if [ "${plev}" == "21" ]; then
219
- ulev="11:15" # 100:300 hPa
220
- elif [ "${plev}" == "16" ]; then
221
- ulev="11:13" # 100:300 hPa
222
- else
223
- ulev="11:12" # default
224
- fi
253
+ ulev="${ulev}"
225
254
  facS="1*"
226
255
  facB="1*"
227
256
  facZ="1*"
@@ -618,51 +647,51 @@ EOF
618
647
  if [ -f "$ferret.jnl" ]; then
619
648
  cp -p $ferret.jnl .
620
649
  rm -f ${tfile}_burden.${ext} ${tfile}_burden_log.${ext}
621
- log "pyferret -nodisplay -script $ferret.jnl ${ifile} ${pvar} ${MODEL_RESOLUTION} ${exp} ${tfile}_burden ${ext}"
622
- pyferret -nodisplay -script $ferret.jnl ${ifile} ${pvar} ${MODEL_RESOLUTION} ${exp} ${tfile}_burden ${ext}
650
+ log "$PYFERRET_CMD -nodisplay -script $ferret.jnl ${ifile} ${pvar} ${MODEL_RESOLUTION} ${exp} ${tfile}_burden ${ext}"
651
+ $PYFERRET_CMD -nodisplay -script $ferret.jnl ${ifile} ${pvar} ${MODEL_RESOLUTION} ${exp} ${tfile}_burden ${ext}
623
652
  else
624
653
  # ferret plots for default journal file
625
654
  rm -f ${tfile}_burden.${ext} ${tfile}_burden_log.${ext}
626
- log "pyferret -nodisplay -script ${tfile}_burden_1x1.jnl"
627
- pyferret -nodisplay -script ${tfile}_burden_1x1.jnl
655
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_burden_1x1.jnl"
656
+ $PYFERRET_CMD -nodisplay -script ${tfile}_burden_1x1.jnl
628
657
 
629
658
  rm -f ${tfile}_zonal.${ext} ${tfile}_zonal_log.${ext}
630
- log "pyferret -nodisplay -script ${tfile}_zonal_1x1.jnl"
631
- pyferret -nodisplay -script ${tfile}_zonal_1x1.jnl
659
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_zonal_1x1.jnl"
660
+ $PYFERRET_CMD -nodisplay -script ${tfile}_zonal_1x1.jnl
632
661
 
633
662
  rm -f ${tfile}_meridional.${ext} ${tfile}_meridional_log.${ext}
634
- log "pyferret -nodisplay -script ${tfile}_meridional_1x1.jnl"
635
- pyferret -nodisplay -script ${tfile}_meridional_1x1.jnl
663
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_meridional_1x1.jnl"
664
+ $PYFERRET_CMD -nodisplay -script ${tfile}_meridional_1x1.jnl
636
665
 
637
666
  rm -f ${tfile}_surface.${ext} ${tfile}_surface_log.${ext}
638
- log "pyferret -nodisplay -script ${tfile}_surface_1x1.jnl"
639
- pyferret -nodisplay -script ${tfile}_surface_1x1.jnl
667
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_surface_1x1.jnl"
668
+ $PYFERRET_CMD -nodisplay -script ${tfile}_surface_1x1.jnl
640
669
 
641
670
  rm -f ${tfile}_utls.${ext} ${tfile}_utls_log.${ext}
642
- log "pyferret -nodisplay -script ${tfile}_utls_1x1.jnl"
643
- pyferret -nodisplay -script ${tfile}_utls_1x1.jnl
671
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_utls_1x1.jnl"
672
+ $PYFERRET_CMD -nodisplay -script ${tfile}_utls_1x1.jnl
644
673
  fi
645
674
 
646
675
  if [ "${exp}" == "${exp1}" ]; then
647
676
  rm -f ${tfile}_burden_diff.${ext} ${tfile}_burden_log_diff.${ext}
648
- log "pyferret -nodisplay -script ${tfile}_burden_1x1_diff.jnl"
649
- pyferret -nodisplay -script ${tfile}_burden_1x1_diff.jnl
677
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_burden_1x1_diff.jnl"
678
+ $PYFERRET_CMD -nodisplay -script ${tfile}_burden_1x1_diff.jnl
650
679
 
651
680
  rm -f ${tfile}_zonal_diff.${ext} ${tfile}_zonal_log_diff.${ext}
652
- log "pyferret -nodisplay -script ${tfile}_zonal_1x1_diff.jnl"
653
- pyferret -nodisplay -script ${tfile}_zonal_1x1_diff.jnl
681
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_zonal_1x1_diff.jnl"
682
+ $PYFERRET_CMD -nodisplay -script ${tfile}_zonal_1x1_diff.jnl
654
683
 
655
684
  rm -f ${tfile}_meridional_diff.${ext} ${tfile}_meridional_log_diff.${ext}
656
- log "pyferret -nodisplay -script ${tfile}_meridional_1x1_diff.jnl"
657
- pyferret -nodisplay -script ${tfile}_meridional_1x1_diff.jnl
685
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_meridional_1x1_diff.jnl"
686
+ $PYFERRET_CMD -nodisplay -script ${tfile}_meridional_1x1_diff.jnl
658
687
 
659
688
  rm -f ${tfile}_surface_diff.${ext} ${tfile}_surface_log_diff.${ext}
660
- log "pyferret -nodisplay -script ${tfile}_surface_1x1_diff.jnl"
661
- pyferret -nodisplay -script ${tfile}_surface_1x1_diff.jnl
689
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_surface_1x1_diff.jnl"
690
+ $PYFERRET_CMD -nodisplay -script ${tfile}_surface_1x1_diff.jnl
662
691
 
663
692
  rm -f ${tfile}_utls_diff.${ext} ${tfile}_utls_log_diff.${ext}
664
- log "pyferret -nodisplay -script ${tfile}_utls_1x1_diff.jnl"
665
- pyferret -nodisplay -script ${tfile}_utls_1x1_diff.jnl
693
+ log "$PYFERRET_CMD -nodisplay -script ${tfile}_utls_1x1_diff.jnl"
694
+ $PYFERRET_CMD -nodisplay -script ${tfile}_utls_1x1_diff.jnl
666
695
 
667
696
  # files=("${tfile}" "${tfile}_log" "${tfile}_diff" "${tfile}_log_diff")
668
697
  files=("${tfile}_surface" "${tfile}_surface_log" "${tfile}_surface_diff" "${tfile}_surface_log_diff" \
@@ -736,20 +765,15 @@ file_name="${file_name%.*}" # Remove extension
736
765
  # Split the file name into parts
737
766
  IFS="_" read -ra parts <<< "$file_name"
738
767
 
739
- pqlc="${parts[5]}"
740
- pnml="${parts[6]}"
741
- # files without level type (_pl _ml _sfc)
742
- #pvar2="${parts[7]}"
743
- #pexp="${parts[8]}"
744
- #ptyp="${parts[9]}"
745
- #pdif="${parts[11]}"
746
- # files with level type (_pl _ml _sfc)
747
- tlev="${parts[7]}"
748
- pvar2="${parts[8]}"
749
- pexp="${parts[9]}"
750
- ptyp="${parts[10]}"
751
- plog="${parts[11]}"
752
- pdif="${parts[12]}"
768
+ pqlc="${parts[4]}"
769
+ pnml="${parts[5]}"
770
+ tlev="${parts[6]}"
771
+ pvar2="${parts[7]}"
772
+ pexp="${parts[8]}"
773
+ ptyp="${parts[9]}"
774
+ plog="${parts[10]}"
775
+ pdif="${parts[11]}"
776
+
753
777
  if [[ "$pvar2" == *"-"* ]]; then
754
778
  # echo "INFO: variable name '$pvar2' contains dash, display as underscore."
755
779
  pvar=$pvar2
@@ -779,7 +803,7 @@ fi
779
803
  if [ "${tlev}" != "sfc" ] ; then
780
804
  GO="GO"
781
805
  fi
782
-
806
+ #log "${GO} = GO | ${pexp} = ${exp1} | ${plog}"
783
807
  if [ "${GO}" == "GO" ] && [ "${pexp}" == "${exp1}" ] && [ "${plog}" == "" ] ; then
784
808
  plot1="$PLOTS_DIRECTORY/${exp1}/${TEAM_PREFIX}_${exp1}-${exp2}_${mDate}_${QLTYPE}_${pnml}_${tlev}_${pvar}_${exp1}_${ptyp}.${ext}"
785
809
  plot2="$PLOTS_DIRECTORY/${exp2}/${TEAM_PREFIX}_${exp1}-${exp2}_${mDate}_${QLTYPE}_${pnml}_${tlev}_${pvar}_${exp2}_${ptyp}.${ext}"
@@ -812,6 +836,7 @@ cat >> ${texFile} <<EOF
812
836
  EOF
813
837
  fi
814
838
  done # plot
839
+
815
840
  log "----------------------------------------------------------------------------------------"
816
841
  log "${texFile}"
817
842
  cat ${texFile}
qlc/sh/qlc_D1.sh CHANGED
@@ -1,4 +1,4 @@
1
- #!/bin/sh -e
1
+ #!/bin/bash -e
2
2
 
3
3
  # Source the configuration file to load the settings
4
4
  . "$CONFIG_FILE"
@@ -31,13 +31,13 @@ if [ "${HOST}" == "a" ] && [ "${myOS}" != "Darwin" ]; then
31
31
  module load python3/3.10.10-01
32
32
  fi
33
33
 
34
- # Check if python exists
35
- if ! command_exists python; then
36
- log "Error: python command not found" >&2
34
+ # Check if qlc-py exists
35
+ if ! command_exists qlc-py; then
36
+ log "Error: qlc-py command not found" >&2
37
37
  exit 1
38
38
  else
39
- log "Success: python command found"
40
- which python
39
+ log "Success: qlc-py command found"
40
+ which qlc-py
41
41
  fi
42
42
 
43
43
  # Create output directory if not existent
@@ -60,68 +60,299 @@ eDate="${eDat//[-:]/}"
60
60
  mDate="$sDate-$eDate"
61
61
  ext="${QLTYPE}.pdf"
62
62
 
63
- exps="$exp1 $exp2"
64
- for exp in $exps ; do
65
- log "Processing ${PLOTTYPE} plot for experiment: $exp"
66
-
67
- log "TEAM_PREFIX : $TEAM_PREFIX"
68
- log "EVALUATION_PREFIX: $EVALUATION_PREFIX"
69
- log "MODEL_RESOLUTION : $MODEL_RESOLUTION"
70
- log "TIME_RESOLUTION : $TIME_RESOLUTION"
71
- log "mDate : $mDate"
72
- log "ext : $ext"
73
- log "exp1 : $exp1"
74
- log "exp2 : $exp2"
75
-
76
- ipath="$ANALYSIS_DIRECTORY/$exp"
77
- tpath="$PLOTS_DIRECTORY/$exp"
78
- hpath="$PLOTS_DIRECTORY/${exp1}-${exp2}_${mDate}"
79
-
80
- # Create help directory if not existent
81
- if [ ! -d "$hpath" ]; then
82
- mkdir -p "$hpath"
83
- fi
84
-
85
- # Create output directory if not existent
86
- if [ ! -d "$tpath" ]; then
87
- mkdir -p "$tpath"
88
- fi
63
+ # Create a temporary list for TeX files and a temporary JSON config
64
+ hpath="$PLOTS_DIRECTORY/${exp1}-${exp2}_${mDate}"
65
+ texPlotsfile="${hpath}/texPlotfiles_${QLTYPE}.list"
66
+ texFile="${texPlotsfile%.list}.tex"
67
+ temp_config_file="${hpath}/temp_qlc_D1_config.json"
89
68
 
69
+ # Ensure the output directory exists
70
+ mkdir -p "$hpath"
71
+ rm -f "$texPlotsfile" "$temp_config_file" "$texFile"
72
+ touch "$texPlotsfile"
73
+
74
+ # Dynamically discover variables from config, validated against existing .nc files.
75
+ log "Discovering variables from config and validating against files in ${ANALYSIS_DIRECTORY}/${exp1}..."
76
+ validated_vars=()
77
+ if [[ -z "${MARS_RETRIEVALS[*]}" ]]; then
78
+ log "Warning: MARS_RETRIEVALS array is not defined in the configuration. Falling back to filename parsing."
79
+ # Fallback to the old method if config arrays are missing
80
+ myvar_list_array=($(find "${ANALYSIS_DIRECTORY}/${exp1}" -type f -name "*.nc" ! -name "*_tavg.nc" -print0 | \
81
+ xargs -0 -n 1 basename | \
82
+ sed -E 's/.*_[A-Z][0-9]+_[a-z]+_(.*)\.nc/\1/' | \
83
+ sort -u))
84
+ else
90
85
  for name in "${MARS_RETRIEVALS[@]}"; do
86
+ myvar_array_name="myvar_${name}[@]"
87
+ myvars=("${!myvar_array_name}")
88
+
89
+ for var_name in "${myvars[@]}"; do
90
+ # Check if a file for this variable exists for the first experiment.
91
+ # The pattern looks for any file ending in _<var_name>.nc
92
+ if compgen -G "${ANALYSIS_DIRECTORY}/${exp1}/*_${var_name}.nc" > /dev/null; then
93
+ validated_vars+=("$var_name")
94
+ fi
95
+ done
96
+ done
97
+ # De-duplicate the results
98
+ myvar_list_array=($(printf "%s\n" "${validated_vars[@]}" | sort -u))
99
+ fi
100
+
101
+
102
+ if [ ${#myvar_list_array[@]} -eq 0 ]; then
103
+ log "Error: Could not find any variables to process. Check config and analysis files. Exiting."
104
+ exit 1
105
+ fi
106
+ myvar_list_string=$(IFS=,; echo "${myvar_list_array[*]}")
107
+ log "Found variables: ${myvar_list_string}"
108
+
109
+ # Dynamically create a temporary JSON config file with three entries.
110
+ cat > "$temp_config_file" << EOM
111
+ [
112
+ {
113
+ "name": "${TEAM_PREFIX}",
114
+ "logdir": "${QLC_HOME}/log",
115
+ "workdir": "${QLC_HOME}/run",
116
+ "output_base_name": "${hpath}/${QLTYPE}",
117
+ "station_file": "${STATION_FILE:-""}",
118
+ "obs_path": "${OBS_DATA_PATH:-""}",
119
+ "obs_dataset_type": "${OBS_DATASET_TYPE:-""}",
120
+ "obs_dataset_version": "${OBS_DATASET_VERSION:-""}",
121
+ "start_date": "${sDat}",
122
+ "end_date": "${eDat}",
123
+ "variable": "${myvar_list_string}",
124
+ "plot_region": "${REGION:-""}",
125
+ "station_radius_deg": ${STATION_RADIUS_DEG:-0.5},
126
+ "plot_type": "${PLOT_TYPE:-""}",
127
+ "time_average": "${TIME_AVERAGE:-""}",
128
+ "station_plot_group_size": ${STATION_PLOT_GROUP_SIZE:-5},
129
+ "show_stations": false,
130
+ "show_min_max": true,
131
+ "log_y_axis": false,
132
+ "fix_y_axis": true,
133
+ "show_station_map": true,
134
+ "load_station_timeseries_obs": true,
135
+ "show_station_timeseries_obs": true,
136
+ "show_station_timeseries_mod": false,
137
+ "show_station_timeseries_com": false,
138
+ "save_plot_format": "${PLOTEXTENSION}",
139
+ "save_data_format": "nc",
140
+ "multiprocessing": ${MULTIPROCESSING:-false},
141
+ "n_threads": ${N_THREADS:-4},
142
+ "debug": ${DEBUG:-false},
143
+ "global_attributes": {
144
+ "title": "Air pollutants over ${REGION:-""}, ${myvar_list_string}",
145
+ "summary": "netCDF output: ${OBS_DATASET_TYPE:-""} observations for selected stations.",
146
+ "author": "$(echo $USER)",
147
+ "history": "Processed for CAMS2_35bis (qlc_v${QLC_VERSION})",
148
+ "Conventions": "CF-1.8"
149
+ }
150
+ },
151
+ {
152
+ "name": "${TEAM_PREFIX}",
153
+ "logdir": "${QLC_HOME}/log",
154
+ "workdir": "${QLC_HOME}/run",
155
+ "output_base_name": "${hpath}/${QLTYPE}",
156
+ "station_file": "${STATION_FILE:-""}",
157
+ "mod_path": "${ANALYSIS_DIRECTORY:-""}",
158
+ "model": "${MODEL:-""}",
159
+ "experiments": "${exp1},${exp2}",
160
+ "exp_labels": "${EXP_LABELS:-""}",
161
+ "start_date": "${sDat}",
162
+ "end_date": "${eDat}",
163
+ "variable": "${myvar_list_string}",
164
+ "plot_region": "${REGION:-""}",
165
+ "station_radius_deg": ${STATION_RADIUS_DEG:-0.5},
166
+ "model_level": ${MODEL_LEVEL:-null},
167
+ "plot_type": "${PLOT_TYPE:-""}",
168
+ "time_average": "${TIME_AVERAGE:-""}",
169
+ "station_plot_group_size": ${STATION_PLOT_GROUP_SIZE:-5},
170
+ "show_stations": false,
171
+ "show_min_max": true,
172
+ "log_y_axis": false,
173
+ "fix_y_axis": true,
174
+ "show_station_map": true,
175
+ "show_station_timeseries_obs": false,
176
+ "show_station_timeseries_mod": true,
177
+ "show_station_timeseries_com": false,
178
+ "save_plot_format": "${PLOTEXTENSION}",
179
+ "save_data_format": "nc",
180
+ "multiprocessing": ${MULTIPROCESSING:-false},
181
+ "n_threads": ${N_THREADS:-4},
182
+ "debug": ${DEBUG:-false},
183
+ "global_attributes": {
184
+ "title": "Air pollutants over ${REGION:-""}, ${myvar_list_string}",
185
+ "summary": "netCDF output: Model data for ${exp1},${exp2} for selected stations.",
186
+ "author": "$(echo $USER)",
187
+ "history": "Processed for CAMS2_35bis (qlc_v${QLC_VERSION})",
188
+ "Conventions": "CF-1.8"
189
+ }
190
+ },
191
+ {
192
+ "name": "${TEAM_PREFIX}",
193
+ "logdir": "${QLC_HOME}/log",
194
+ "workdir": "${QLC_HOME}/run",
195
+ "output_base_name": "${hpath}/${QLTYPE}",
196
+ "station_file": "${STATION_FILE:-""}",
197
+ "obs_path": "${OBS_DATA_PATH:-""}",
198
+ "obs_dataset_type": "${OBS_DATASET_TYPE:-""}",
199
+ "obs_dataset_version": "${OBS_DATASET_VERSION:-""}",
200
+ "mod_path": "${ANALYSIS_DIRECTORY:-""}",
201
+ "model": "${MODEL:-""}",
202
+ "experiments": "${exp1},${exp2}",
203
+ "exp_labels": "${EXP_LABELS:-""}",
204
+ "start_date": "${sDat}",
205
+ "end_date": "${eDat}",
206
+ "variable": "${myvar_list_string}",
207
+ "plot_region": "${REGION:-""}",
208
+ "station_radius_deg": ${STATION_RADIUS_DEG:-0.5},
209
+ "model_level": ${MODEL_LEVEL:-null},
210
+ "plot_type": "${PLOT_TYPE:-""}",
211
+ "time_average": "${TIME_AVERAGE:-""}",
212
+ "station_plot_group_size": ${STATION_PLOT_GROUP_SIZE:-5},
213
+ "show_stations": false,
214
+ "show_min_max": true,
215
+ "log_y_axis": false,
216
+ "fix_y_axis": true,
217
+ "show_station_map": true,
218
+ "load_station_timeseries_obs": false,
219
+ "show_station_timeseries_obs": false,
220
+ "show_station_timeseries_mod": false,
221
+ "show_station_timeseries_com": true,
222
+ "save_plot_format": "${PLOTEXTENSION}",
223
+ "save_data_format": "nc",
224
+ "multiprocessing": ${MULTIPROCESSING:-false},
225
+ "n_threads": ${N_THREADS:-4},
226
+ "debug": ${DEBUG:-false},
227
+ "global_attributes": {
228
+ "title": "Air pollutants over ${REGION:-""}, ${myvar_list_string}",
229
+ "summary": "netCDF output: Collocated model and observation data for selected stations.",
230
+ "author": "$(echo $USER)",
231
+ "history": "Processed for CAMS2_35bis (qlc_v${QLC_VERSION})",
232
+ "Conventions": "CF-1.8"
233
+ }
234
+ }
235
+ ]
236
+ EOM
91
237
 
92
- log "name : $name"
238
+ log "Generated temporary config file for qlc-py: ${temp_config_file}"
93
239
 
94
- # Define the corresponding arrays based on the name
95
- param_var="param_${name}[@]"
96
- ncvar_var="ncvar_${name}[@]"
97
- myvar_var="myvar_${name}[@]"
240
+ # Execute qlc-py with the temporary config file.
241
+ # Note: qlc-py expects the config via stdin when using '--config -'
242
+ log "Executing qlc-py with the multi-entry config file..."
243
+ qlc-py --config "${temp_config_file}"
98
244
 
99
- # Use variable indirection to access the arrays
100
- param=("${!param_var}")
101
- ncvar=("${!ncvar_var}")
102
- myvar=("${!myvar_var}")
245
+ # After the run, find the specific final collocation plot(s) and add them to the TeX list.
246
+ log "Searching for final collocation plots in ${hpath}..."
247
+ rm -f "$texPlotsfile" # Start with an empty list
248
+ touch "$texPlotsfile" # Ensure the file exists before grep is called
103
249
 
104
- cd $ipath
250
+ # Loop through each variable to control the order of plots in the TeX file
251
+ for var in "${myvar_list_array[@]}"; do
252
+ log "Ordering plots for variable: $var"
105
253
 
106
- # Loop through the variables for this $name
107
- for ((i = 0; i < ${#ncvar[@]}; i++)); do
254
+ # Helper function to find a plot and add it to the list if it exists and is not already there
255
+ add_plot_if_found() {
256
+ local plot_pattern=$1
257
+ # Use find and sort to ensure a consistent order if multiple files match
258
+ find "${hpath}" -maxdepth 1 -type f -name "${plot_pattern}" 2>/dev/null | sort | while IFS= read -r plot_file; do
259
+ if [ -n "$plot_file" ] && ! grep -qF "$plot_file" "$texPlotsfile"; then
260
+ echo "$plot_file" >> "$texPlotsfile"
261
+ log "Added plot to TeX list: $plot_file"
262
+ fi
263
+ done
264
+ }
108
265
 
109
- myvar_name="${myvar[i]}"
110
- log "myvar_name : $myvar_name"
266
+ # Find plots in the specified order using more precise patterns
267
+ # 1. Time series plots (individual experiments first, then collocated)
268
+ add_plot_if_found "*${var}*collocated*regional_mean*.${PLOTEXTENSION}"
269
+
270
+ # 2. Bias plot
271
+ add_plot_if_found "*${var}*collocated*regional_bias*.${PLOTEXTENSION}"
272
+
273
+ # 3. All statistics plots
274
+ add_plot_if_found "*${var}*collocated*stats_plot_Error_Metrics*.${PLOTEXTENSION}"
275
+ add_plot_if_found "*${var}*collocated*stats_plot_Correlation_Metrics*.${PLOTEXTENSION}"
276
+ add_plot_if_found "*${var}*collocated*stats_plot_Descriptive_Statistics*.${PLOTEXTENSION}"
111
277
 
112
- tfile="${EVALUATION_PREFIX}_${exp1}-${exp2}_${myvar_name}_${mDate}_${name}_$ext"
113
- log "${PLOTTYPE} plot for: $myvar_name - $tpath/$tfile"
114
- log "work in progress, plot scripts to be implemented ..."
278
+ # 4. Value map plots (individual experiments)
279
+ add_plot_if_found "*${var}*val.${PLOTEXTENSION}"
280
+
281
+ done
282
+
283
+ # ----------------------------------------------------------------------------------------
284
+ # Generate a .tex file with frames for each plot found, for inclusion in the final presentation.
285
+ # ----------------------------------------------------------------------------------------
286
+ log "Generating TeX file for plots: ${texFile}"
287
+
288
+ # Create the main .tex file for this section with a subsection header
289
+ tQLTYPE=$(echo "$QLTYPE" | sed 's/_/\\_/g')
290
+ cat > "$texFile" <<EOF
291
+ %===============================================================================
292
+ \subsection{${tQLTYPE} -- ${mDate} (${TIME_AVERAGE})}
293
+ EOF
294
+
295
+ # Loop through the found plot files and generate a TeX frame for each
296
+ if [ -s "$texPlotsfile" ]; then
297
+ # Read from the ordered file list
298
+ while IFS= read -r plot_path; do
299
+ plot_filename=$(basename -- "$plot_path")
300
+ var_name_tex=""
301
+ title_prefix=""
115
302
 
116
- touch $tpath/$tfile
117
- ls -lh $tpath/$tfile
303
+ # Extract the variable name for the title
304
+ for var in "${myvar_list_array[@]}"; do
305
+ if [[ "$plot_filename" == *"${var}"* ]]; then
306
+ var_name_tex=$(echo "$var" | sed 's/_/\\_/g')
307
+ break
308
+ fi
309
+ done
310
+
311
+ # Use a case statement for robust title generation
312
+ case "$plot_filename" in
313
+ *regional_bias*)
314
+ title_prefix="Collocation time series bias" ;;
315
+ *stats_plot_Error_Metrics*)
316
+ title_prefix="Collocation error stats" ;;
317
+ *stats_plot_Correlation_Metrics*)
318
+ title_prefix="Collocation correlation stats" ;;
319
+ *stats_plot_Descriptive_Statistics*)
320
+ title_prefix="Collocation descriptive stats" ;;
321
+ *val.*)
322
+ title_prefix="Collocation map value plot" ;;
323
+ *regional_mean*)
324
+ title_prefix="Collocation time series" ;;
325
+ *)
326
+ title_prefix="Collocation station plot" ;;
327
+ esac
328
+
329
+ title_final="${title_prefix} for ${var_name_tex} of ${exp1} vs ${exp2}"
330
+
331
+ # Append the frame to the main .tex file
332
+ cat >> "$texFile" <<EOF
333
+ %===============================================================================
334
+ \frame{
335
+ \frametitle{${title_final}}
336
+ \vspace{0mm}
337
+ \centering
338
+ \includegraphics[width=0.9\textwidth]{${plot_path}}
339
+ }
340
+ EOF
341
+ log "Generated TeX frame for $plot_filename"
342
+ done < "$texPlotsfile"
343
+ log "Finished generating TeX file."
344
+ log "${texFile}"
345
+ cat "${texFile}"
346
+ else
347
+ log "No plots found to generate TeX file."
348
+ fi
118
349
 
119
- done # ncvar
120
- done # name
121
- done # exps
350
+ # ----------------------------------------------------------------------------------------
351
+ # End of TeX file generation
352
+ # ----------------------------------------------------------------------------------------
122
353
 
123
- log "$ipath"
124
- log "$tpath"
354
+ log "$ANALYSIS_DIRECTORY"
355
+ log "$PLOTS_DIRECTORY"
125
356
 
126
357
  log "----------------------------------------------------------------------------------------"
127
358
  log "End ${SCRIPT} at `date`"