rc-qlc 0.3.26__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 (36) hide show
  1. qlc/doc/CAMS_b2ro-b2rn_20181201-20181221_qlc_Z1-png_202509090814.pdf +0 -0
  2. qlc/doc/README.md +131 -3
  3. qlc/doc/USAGE.md +198 -0
  4. qlc/install.py +29 -18
  5. qlc/py/__main__.cp311-win32.pyd +0 -0
  6. qlc/py/averaging.cp311-win32.pyd +0 -0
  7. qlc/py/bias_plots.cp311-win32.pyd +0 -0
  8. qlc/py/control.cp311-win32.pyd +0 -0
  9. qlc/py/io.cp311-win32.pyd +0 -0
  10. qlc/py/loadmod.cp311-win32.pyd +0 -0
  11. qlc/py/loadobs.cp311-win32.pyd +0 -0
  12. qlc/py/logging_utils.cp311-win32.pyd +0 -0
  13. qlc/py/map_plots.cp311-win32.pyd +0 -0
  14. qlc/py/matched.cp311-win32.pyd +0 -0
  15. qlc/py/plot_config.cp311-win32.pyd +0 -0
  16. qlc/py/plotting.cp311-win32.pyd +0 -0
  17. qlc/py/plugin_loader.cp311-win32.pyd +0 -0
  18. qlc/py/processing.cp311-win32.pyd +0 -0
  19. qlc/py/scatter_plots.cp311-win32.pyd +0 -0
  20. qlc/py/stations.cp311-win32.pyd +0 -0
  21. qlc/py/statistics.cp311-win32.pyd +0 -0
  22. qlc/py/style.cp311-win32.pyd +0 -0
  23. qlc/py/timeseries_plots.cp311-win32.pyd +0 -0
  24. qlc/py/utils.cp311-win32.pyd +0 -0
  25. qlc/py/version.cp311-win32.pyd +0 -0
  26. qlc/sh/qlc_A1.sh +16 -15
  27. qlc/sh/qlc_C5.sh +71 -35
  28. qlc/sh/qlc_D1.sh +0 -9
  29. qlc/sh/qlc_batch.sh +3 -3
  30. qlc/sh/qlc_main.sh +17 -0
  31. {rc_qlc-0.3.26.dist-info → rc_qlc-0.3.27.dist-info}/METADATA +134 -3
  32. {rc_qlc-0.3.26.dist-info → rc_qlc-0.3.27.dist-info}/RECORD +36 -35
  33. {rc_qlc-0.3.26.dist-info → rc_qlc-0.3.27.dist-info}/WHEEL +0 -0
  34. {rc_qlc-0.3.26.dist-info → rc_qlc-0.3.27.dist-info}/entry_points.txt +0 -0
  35. {rc_qlc-0.3.26.dist-info → rc_qlc-0.3.27.dist-info}/licenses/LICENSE +0 -0
  36. {rc_qlc-0.3.26.dist-info → rc_qlc-0.3.27.dist-info}/top_level.txt +0 -0
qlc/doc/README.md CHANGED
@@ -10,6 +10,24 @@ The suite streamlines the entire post-processing workflow, from data retrieval a
10
10
 
11
11
  ---
12
12
 
13
+ ## What's New in v0.3.27
14
+
15
+ This release focuses on improving the out-of-the-box installation experience, especially for HPC environments, and significantly expanding the user documentation.
16
+
17
+ - **Installer Overhaul**: The `qlc-install` script is now more robust.
18
+ - It automatically creates the `qlc` -> `qlc_latest` -> `qlc_vX.Y.Z/<mode>` symlink structure, removing the need for manual setup.
19
+ - It now provides clear, actionable instructions on how to update your `PATH` if needed.
20
+ - **Enhanced HPC & Batch Job Support**:
21
+ - The batch submission script (`sqlc`) is more reliable, no longer using hardcoded paths.
22
+ - Shell scripts are now more compatible with typical HPC environments that may only have a `python3` executable.
23
+ - **Expanded Documentation**:
24
+ - The `USAGE.md` guide now includes comprehensive, exhaustive lists of currently available plotting regions, observation datasets, and supported chemical/meteorological variables.
25
+ - A new "Advanced Workflow" section has been added to `USAGE.md`, explaining the underlying shell script pipeline, the `param/ncvar/myvar` variable mapping system, and how to use your own data with the `qlc-py` engine.
26
+ - Added a note on the future integration with the GHOST database.
27
+ - **Dependency Fix**: The `adjustText` library is now included as a core dependency.
28
+
29
+ ---
30
+
13
31
  ## What's New in v0.3.26
14
32
 
15
33
  This version introduces a completely new, high-performance Python processing engine and a more robust installation system.
@@ -56,18 +74,43 @@ qlc b2ro b2rn 2018-12-01 2018-12-21
56
74
 
57
75
  ---
58
76
 
77
+ ## Prerequisites
78
+
79
+ Before running the QLC suite, please ensure the following system-level software is installed and accessible in your environment's `PATH`:
80
+
81
+ - **`pdflatex`**: Required for generating the final PDF reports. It is part of the **TeX Live** distribution.
82
+ - **`CDO` (Climate Data Operators)**: Used for processing NetCDF data.
83
+ - **`eccodes`**: The ECMWF library for decoding and encoding GRIB files.
84
+ - **`netcdf`**: The core NetCDF libraries.
85
+
86
+ On HPC systems, these tools are typically made available by loading the appropriate modules (e.g., `module load cdo`). On personal machines, they can be installed using system package managers like `apt-get` (Debian/Ubuntu), `yum` (Red Hat/CentOS), or `brew` (macOS).
87
+
88
+ ---
89
+
59
90
  ## Installation and Configuration
60
91
 
61
92
  ### Standard Installation
62
93
 
63
94
  QLC is installed from PyPI. After the `pip install`, you **must** run `qlc-install` to set up the necessary local directory structure.
64
95
 
96
+ **First-Time Installation**
97
+ ```bash
98
+ pip install rc-qlc
99
+ ```
100
+
101
+ **Upgrading an Existing Installation**
102
+ To ensure you have the latest version, always use the `--upgrade` flag:
103
+ ```bash
104
+ pip install --upgrade rc-qlc
105
+ ```
106
+
107
+ After installing, set up your desired environment:
65
108
  ```bash
66
109
  # For a standalone test environment with example data
67
- pip install rc-qlc && qlc-install --mode test
110
+ qlc-install --mode test
68
111
 
69
112
  # For an operational CAMS environment
70
- pip install rc-qlc && qlc-install --mode cams
113
+ qlc-install --mode cams
71
114
  ```
72
115
 
73
116
  ### Installation in Restricted Environments (HPC/ATOS)
@@ -143,10 +186,95 @@ For advanced development, you can also use `--mode interactive`, which requires
143
186
  qlc-install --mode interactive --config /path/to/your/custom_qlc.conf
144
187
  ```
145
188
 
189
+ ## Advanced Topics
190
+
191
+ ### Installing PyFerret for Global Plots
192
+
193
+ The `qlc_C5.sh` script, which generates global map plots, requires the `pyferret` library. This is an optional dependency.
194
+
195
+ - **To install with `pyferret` support:**
196
+ ```bash
197
+ pip install "rc-qlc[ferret]"
198
+ ```
199
+ - **If you do not need these plots**, you can either skip the `pyferret` installation or, if it's already installed, disable the script by commenting out `"C5"` in the `SUBSCRIPT_NAMES` array in your `$HOME/qlc/config/qlc.conf` file.
200
+ - **For HPC environments**, `pyferret` is often available as a module that can be loaded (e.g., `module load ferret/7.6.3`).
201
+
202
+ ### Manual PyFerret Installation for macOS / Apple Silicon
203
+
204
+ If you are using a Mac with Apple Silicon (M1/M2/M3) or if the standard installation fails, `pyferret` may require a manual setup using a dedicated `conda` environment. `pip` installations are not recommended for this package on macOS as they may not work correctly with the ARM architecture.
205
+
206
+ The most reliable method is to use `conda` with the Rosetta 2 translation layer.
207
+
208
+ **1. (If needed) Install Conda**
209
+ If you do not have `conda` installed, we recommend **Miniforge**, which is a minimal installer that is optimized for Apple Silicon and includes the high-performance `mamba` package manager.
210
+ ```bash
211
+ # Download and run the installer for Apple Silicon
212
+ curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-arm64.sh"
213
+ bash Miniforge3-MacOSX-arm64.sh
214
+ # Follow the prompts and restart your terminal after installation
215
+ ```
216
+
217
+ **2. Create a Dedicated x86_64 Environment for PyFerret**
218
+ This command creates a new `conda` environment named `pyferret_env` and installs the Intel (`x86_64`) version of `pyferret`, which will run seamlessly on Apple Silicon via Rosetta 2. It also pins `numpy` to a version older than 2.0 to ensure compatibility.
219
+
220
+ ```bash
221
+ CONDA_SUBDIR=osx-64 conda create -n pyferret_env -c conda-forge pyferret ferret_datasets "numpy<2" --yes
222
+ ```
223
+
224
+ **3. Configure QLC to Use the New Environment**
225
+ The QLC scripts need to know where to find this new `pyferret` installation. You can achieve this by modifying the `qlc_C5.sh` script to activate the environment.
226
+
227
+ Open the file `$HOME/qlc/sh/qlc_C5.sh` and add the following lines near the top, after `source $FUNCTIONS`:
228
+
229
+ ```bash
230
+ # ... after 'source $FUNCTIONS'
231
+ # Activate the dedicated conda environment for pyferret
232
+ if [ -f "$HOME/miniforge3/bin/activate" ]; then
233
+ . "$HOME/miniforge3/bin/activate"
234
+ conda activate pyferret_env
235
+ fi
236
+ # ... rest of the script
237
+ ```
238
+ *Note: The path to the activate script may differ if you installed Anaconda/Miniforge in a custom location.*
239
+
240
+ ### MARS Data Retrieval
241
+ The `qlc_A1.sh` script is responsible for retrieving data from the ECMWF MARS archive. It uses a mapping system to associate the experiment prefix with a MARS `class`.
242
+
243
+ By default, the script is configured for `nl` (Netherlands), `be` (Belgium), and `rd` (Research Department) experiments. If you are working with data from other classes (e.g., `fr` for France, `de` for Germany), you will need to manually edit `$HOME/qlc/sh/qlc_A1.sh` and uncomment / edit the corresponding `XCLASS` line to ensure data is retrieved correctly.
244
+
245
+ ---
246
+
247
+ ## Troubleshooting
248
+
249
+ ### macOS "Permission Denied" or Quarantine Issues
250
+
251
+ On macOS, the Gatekeeper security feature may "quarantine" files, including shell scripts that have been downloaded or modified. This can prevent them from being executed, sometimes with a "Permission Denied" error, even if the file has the correct execute permissions (`+x`).
252
+
253
+ This is most likely to occur if you manually edit the `qlc` shell scripts (`.sh` files) directly in their `site-packages` installation directory.
254
+
255
+ To resolve this, you can manually remove the quarantine attribute from the script directory using the `xattr` command in your terminal.
256
+
257
+ 1. **First, find the exact location of the `qlc` package:**
258
+ ```bash
259
+ pip show rc-qlc
260
+ ```
261
+ Look for the `Location:` line in the output. This is your `site-packages` path.
262
+
263
+ 2. **Then, use the `xattr` command to remove the quarantine flag:**
264
+ Use the path from the previous step to build the full path to the `qlc/sh` directory.
265
+ ```bash
266
+ # The path will depend on your Python installation. Use the location from 'pip show'.
267
+ xattr -rd com.apple.quarantine /path/to/your/site-packages/qlc/sh/
268
+ ```
269
+
270
+ This should immediately resolve the execution issues.
271
+
146
272
  ---
147
273
 
148
274
  ## License
149
275
 
150
276
  © ResearchConcepts io GmbH
151
277
  Contact: [contact@researchconcepts.io](mailto:contact@researchconcepts.io)
152
- MIT-compatible, source-restricted under private release until publication.
278
+ MIT-compatible, source-restricted under private release until publication.
279
+
280
+ ---
qlc/doc/USAGE.md CHANGED
@@ -95,3 +95,201 @@ You can customize this workflow by editing the variables in your main configurat
95
95
  | `EXP_LABELS` | Comma-separated labels for experiments, used in plot legends. Must match the order of experiments passed to `qlc`. | `"MyExp,MyREF"` |
96
96
  | `PLOTEXTENSION` | The file format for the output plots (e.g., `pdf`, `png`, ...). | `"png"` |
97
97
 
98
+ ---
99
+
100
+ ## Available `qlc-py` Options
101
+
102
+ The Python engine is highly configurable through the `qlc.conf` file or a custom JSON configuration. Below is an overview of the most common options available.
103
+
104
+ ### Plotting Regions (`REGION`)
105
+
106
+ You can set the `REGION` variable to any of the following codes to automatically set the map bounds for plots.
107
+
108
+ | Category | Region Codes |
109
+ | --- | --- |
110
+ | **Continents & Global** | `Globe`, `EU` (Europe), `ASIA`, `AFRICA`, `NA` (North America), `SA` (South America), `OC` (Oceania), `ANT` (Antarctica), `NP` (North Pole) |
111
+ | **Oceans & Water Bodies** | `PAC` (Pacific), `ATLA` (Atlantic), `INDO` (Indian), `ARC` (Arctic), `SOU` (Southern) |
112
+ | **Major Deserts** | `SAH` (Sahara), `ARA` (Arabian), `GOBI`, `OUTBACK` (Australian), `ATACAMA` |
113
+ | **Key Countries** | `GB` (Great Britain), `US` (United States), `CN` (China), `JP` (Japan), `SA` (Saudi Arabia), `IR` (Iran), `EG` (Egypt), `MA` (Morocco), `NG` (Nigeria), `KE` (Kenya), `ZA` (South Africa), `IS` (Iceland) |
114
+ | **European Countries**| `DE` (Germany), `FR` (France), `IT` (Italy), `ES` (Spain), `PL` (Poland), `SE` (Sweden), `FI` (Finland), `NO` (Norway), `NL` (Netherlands), `BE` (Belgium), `AT` (Austria), `CH` (Switzerland), `CZ` (Czech Rep.), `GR` (Greece) |
115
+ | **US States** | `CA-US` (California), `NY-US` (New York), `TX-US` (Texas), `FL-US` (Florida), `IL-US` (Illinois), `WA-US` (Washington), `CO-US` (Colorado), `AZ-US` (Arizona) |
116
+ | **Specific Regions** | `MENA` (Middle East/North Africa), `SSA` (Sub-Saharan Africa) |
117
+ | **Major Cities** | `LA-US`, `NYC-US`, `SHA-CN` (Shanghai), `BEI-CN` (Beijing), `TOK-JP` (Tokyo), `FR-PAR` (Paris), `DE-MUC` (Munich), `DE-FRA` (Frankfurt), `IT-ROM` (Rome), `ES-MAD` (Madrid), `PL-WAW` (Warsaw), `NL-AMS` (Amsterdam), `BE-BRU` (Brussels), `AT-VIE` (Vienna), `CZ-PRG` (Prague), `GR-ATH` (Athens), `CH-ZUR` (Zurich) |
118
+ | **German Regions** | `BW-DE` (Baden-Württemberg), `B-DE` (Berlin), `HH-DE` (Hamburg), `FR-DE` (Freiburg) |
119
+
120
+ ### Time Averaging (`TIME_AVERAGE`)
121
+
122
+ The `TIME_AVERAGE` variable controls the temporal aggregation of the time series data.
123
+
124
+ - **`raw`**: No averaging is applied.
125
+ - **`mean`**: The mean over the entire time period is calculated.
126
+ - **Time Frequencies**: `1min`, `10min`, `30min`, `hourly`, `3hourly`, `6hourly`, `12hourly`, `daily`, `weekly`, `monthly`, `annual`, `seasonal`, `decadal`.
127
+
128
+ ### Observation Datasets (`OBS_DATASET_TYPE`)
129
+
130
+ The `OBS_DATASET_TYPE` variable specifies which observation network data to use. The following datasets are supported:
131
+
132
+ - `ebas` / `ebas_hourly` / `ebas_daily` (EBAS - European Monitoring and Evaluation Programme)
133
+ - `airbase` / `airbase_ineris` (European air quality database)
134
+ - `airnow` (U.S. EPA's AirNow program)
135
+ - `castnet` (Clean Air Status and Trends Network)
136
+ - `AMoN` (Ammonia Monitoring Network)
137
+ - `NNDMN` (National Network of Deposition Monitoring in the Netherlands)
138
+ - `china_gsv` / `china_aq` (Chinese air quality data)
139
+
140
+ ### Supported Variables (`variable`)
141
+
142
+ The `qlc` pipeline automatically discovers variables from your data files. The system supports a wide range of chemical species and physical properties. The list below contains all variables recognized by the EBAS observation dataset mapping, which is the most extensive. Other datasets may support a subset of these.
143
+
144
+ - **Gases**: `NO2`, `SO2`, `SO4`, `HNO3`, `NO3`, `NH3`, `NH4`, `NO`, `NOx`, `O3`, `CO`, `HONO` (Nitrous Acid), `ethanal`, `methanol`, `ethene`, `ethyne`, `propene`, `benzene`, `ethane`, `propane`, `ethylbenzene`, `m-p-xylene`, `o-xylene`, `toluene`.
145
+ - **Mole Fractions**: `SO2_mf`, `NH3_mf`, `NO_mf`, `NO2_mf`, `NOx_mf`, `O3_mf`, `CO_mf`, `ethanal_mf`, `methanol_mf`, `ethene_mf`, `ethyne_mf`, `propene_mf`, `benzene_mf`, `ethane_mf`, `propane_mf`, `ethylbenzene_mf`, `m-p-xylene_mf`, `o-xylene_mf`, `toluene_mf`.
146
+ - **Halocarbons (Mole Fractions)**: `CCl4_mf`, `CH3Cl_mf`, `CH2Br2_mf`, `CH2Cl2_mf`, `CHCl3_mf`.
147
+ - **Greenhouse Gases (Mole Fractions)**: `carbon_dioxide_mf`, `methane_mf`, `hydrogen_mf`, `nitrous_oxide_mf`.
148
+ - **Aerosol Properties**:
149
+ - **Mass Density**: `PM1`, `PM2.5`, `PM10`.
150
+ - **Composition (Dry Aerosol)**: `Dry_Nitrate`, `Dry_Ammonium`, `Dry_Chloride`, `Dry_Calcium`, `Dry_Sodium`, `Dry_Iron`, `Dry_Sulphate_Corrected`.
151
+ - **Composition (PM2.5)**: `PM2.5_Nitrate`, `PM2.5_Sodium`, `PM2.5_Calcium`, `PM2.5_Ammonium`, `PM2.5_Chloride`, `PM2.5_Total_Sulphate`, `PM2.5_Sulphate_Corrected`, `PM2.5_EC` (Elemental Carbon), `PM2.5_OC` (Organic Carbon), `PM2.5_TC` (Total Carbon).
152
+ - **Composition (PM10)**: `PM10_Nitrate`, `PM10_Sodium`, `PM10_Calcium`, `PM10_Ammonium`, `PM10_Chloride`, `PM10_Lead`, `PM10_Iron`, `PM10_Manganese`, `PM10_Total_Sulphate`, `PM10_Sulphate_Corrected`, `PM10_EC`, `PM10_OC`, `PM10_TC`.
153
+ - **Number Concentration**: `Dry_NA_NumConc`.
154
+ - **Optical Properties**:
155
+ - **Aerosol Optical Depth (AOD)**: `AOD_380`, `AOD_500`, `AOD_675` (and many other wavelengths).
156
+ - **Scattering Coefficient**: `Scatt_450`, `Scatt_525`, `Scatt_550`, `Scatt_635`, `Scatt_700`.
157
+ - **Absorption Coefficient**: `Abs_370`, `Abs_470`, `Abs_520`, `Abs_660`, `Abs_880` (and many other wavelengths between 370nm and 950nm).
158
+ - **Backscattering**: `Backscatt_700`.
159
+ - **Meteorology**: `Pressure`, `Temperature`.
160
+
161
+ #### Model-Specific Variables
162
+
163
+ The following variables are specifically mapped for model (`mod`) data types. These often include different aerosol size bins or speciated components.
164
+
165
+ - **Aerosol Mass**: `PM1`, `PM2.5`, `PM10`
166
+ - **Aerosol Number Concentration**: `N`, `N_ks` (nucleation mode), `N_as` (aitken mode), `N_cs` (coarse mode)
167
+ - **Sulphate Species**: `SO4`, `SO4_ks`, `SO4_as`, `SO4_cs`
168
+ - **Ammonium Species**: `NH4`, `NH4_ks`, `NH4_as`, `NH4_cs`
169
+ - **Nitrate Species**: `NO3`, `NO3a`, `NO3b`, `NO3_ks`, `NO3_as`, `NO3_cs`
170
+ - **Gases (Mass Mixing Ratios)**: `NH3`, `HNO3`, `NO2`, `SO2`, `CO`, `O3`
171
+
172
+ *Note: The list of supported variables is actively being expanded. Future releases will include a more comprehensive mapping and direct integration with the GHOST (Globally Harmonised Observations in Space and Time) database [[Bowdalo et al., 2024]](https://essd.copernicus.org/articles/16/4417/2024/).*
173
+
174
+ ---
175
+
176
+ ## Advanced `qlc-py` Configuration
177
+
178
+ The `qlc-py` engine offers several advanced configuration options for more complex analysis workflows.
179
+
180
+ ### Using Custom Station Lists
181
+
182
+ For targeted analysis, you can provide a custom list of stations via the `station_file` parameter in your configuration. This should be a path to a CSV file containing station metadata (e.g., ID, name, latitude, longitude).
183
+
184
+ - This is useful for focusing on specific station types (e.g., urban, rural) or networks.
185
+ - If a station from your list is not found in the observation dataset for a given period, it will still be included in the model-only analysis and plots.
186
+ - In addition to plots showing the average across all stations, you can configure `qlc-py` to generate plots and statistics for each individual station in the list.
187
+
188
+ ### Multi-Entry and Parallel Processing
189
+
190
+ The JSON configuration file passed to `qlc-py` can be a single JSON object or an array of multiple objects. This enables powerful and flexible workflow designs.
191
+
192
+ - **Serial Processing**: If you provide an array of configuration objects, `qlc-py` will process them sequentially. This is useful for workflows with distinct steps, such as:
193
+ 1. An entry for processing observations only.
194
+ 2. An entry for processing model results only.
195
+ 3. A final entry that uses both outputs for a combined collocation analysis.
196
+ - **Parallel Processing**: Within a single configuration entry, you can enable parallel processing for time-consuming tasks (like loading and processing many model files at once) by setting `"multiprocessing": true`.
197
+
198
+ ### Example: Multi-Variable Observation Configuration
199
+
200
+ Below is an example of a single configuration entry for processing daily EBAS observations for two variables (`NH3` and `NH4_as`). It also includes the optional `global_attributes` block, which allows you to embed custom metadata into the output NetCDF files.
201
+
202
+ ```json
203
+ {
204
+ "name": "CAMS",
205
+ "logdir": "./log",
206
+ "workdir": "./run",
207
+ "output_base_name": "$HOME/qlc/Plots/PY",
208
+ "station_file": "$HOME/qlc/obs/data/ebas_station-locations.csv",
209
+ "obs_path": "$HOME/qlc/obs/data/ver0d",
210
+ "obs_dataset_type": "ebas_daily",
211
+ "obs_dataset_version": "latest",
212
+ "start_date": "2018-12-01",
213
+ "end_date": "2018-12-21",
214
+ "variable": "NH3,NH4_as",
215
+ "station_radius_deg": 0.5,
216
+ "plot_type": "",
217
+ "plot_region": "EU",
218
+ "time_average": "daily",
219
+ "station_plot_group_size": 5,
220
+ "show_stations": false,
221
+ "show_min_max": true,
222
+ "log_y_axis": false,
223
+ "fix_y_axis": true,
224
+ "show_station_map": true,
225
+ "load_station_timeseries_obs": true,
226
+ "show_station_timeseries_obs": true,
227
+ "show_station_timeseries_mod": false,
228
+ "show_station_timeseries_com": false,
229
+ "save_plot_format": "pdf",
230
+ "save_data_format": "nc",
231
+ "multiprocessing": false,
232
+ "n_threads": "20",
233
+ "debug": false,
234
+ "global_attributes": {
235
+ "title": "Air pollutants over Europe, SO2,SO4,HNO3,NO3,NH3,NH4",
236
+ "summary": "Custom summary for netCDF output: Ebas daily observations for selected EU stations.",
237
+ "author": "Swen Metzger, sm@researchconcepts.io",
238
+ "history": "Processed for CAMS2_35bis (qlc_v0.3.27)",
239
+ "Conventions": "CF-1.8"
240
+ }
241
+ }
242
+ ```
243
+
244
+ ---
245
+
246
+ ## Advanced Workflow: Data Processing and Configuration
247
+
248
+ For advanced users, it is helpful to understand the underlying data processing pipeline, which is controlled by a series of shell scripts and configured via `qlc.conf`. This allows for significant customization of data retrieval and analysis.
249
+
250
+ ### The Shell Script Pipeline
251
+
252
+ When you run the main `qlc` command, it executes a chain of scripts to process data. The scripts to be run are defined by the `SUBSCRIPT_NAMES` array in `$HOME/qlc/config/qlc.conf`. A typical workflow is:
253
+
254
+ 1. **`qlc_A1.sh`**: Handles data retrieval from the MARS archive. It fetches the required variables in GRIB format. The specific variables are defined by the `MARS_RETRIEVALS` array in `qlc.conf`, which must correspond to entries in the `nml/mars_*.nml` namelist files.
255
+ 2. **`qlc_B1a.sh`**: Converts the retrieved GRIB files into NetCDF format.
256
+ 3. **`qlc_B2.sh`**: Performs post-processing and variable substitution on the NetCDF files. This step is crucial as it renames the variables to the user-friendly names (`myvar_*`) expected by the plotting scripts.
257
+ 4. **`qlc_D1.sh`**: Drives the station time-series analysis by generating a configuration and calling `qlc-py`.
258
+ 5. **`qlc_C5.sh`**: Generates global overview plots, including 3D surface maps, vertical integrals (burden), and zonal/meridional means for selected variables.
259
+
260
+ The raw data retrieved from MARS is stored in the `$HOME/qlc/Results` directory, while the final, post-processed NetCDF files used for analysis are placed in `$HOME/qlc/Analysis`.
261
+
262
+ ### Variable Mapping Explained
263
+
264
+ QLC uses a flexible three-part system defined in `qlc.conf` to map variables from the MARS archive to user-defined names for plotting.
265
+
266
+ - **`param_*`**: This is the official ECMWF parameter ID from the GRIB tables (e.g., `param_A1_sfc="73.210"`). This value is required by MARS for data retrieval and must be correct.
267
+ - **`ncvar_*`**: This is the short name that is automatically assigned to the variable when the GRIB file is converted to NetCDF (e.g., `ncvar_A1_sfc="var73"`). This name can differ depending on the data type (surface, pressure levels, model levels).
268
+ - **`myvar_*`**: This is the final, user-defined name for the variable (e.g., `myvar_A1_sfc="PM25"`). This is the name that will be used in plot labels, titles, and filenames throughout the QLC system.
269
+
270
+ This system allows you to work with consistent, human-readable variable names (`PM25`) while ensuring the underlying retrieval from MARS uses the correct, official parameter codes.
271
+
272
+ ### Automatic Unit Conversion and Collocation
273
+
274
+ During the collocation step (comparing model data to observations), `qlc-py` automatically handles variable mapping and unit conversion. For example, when comparing model output (`mod`) to `castnet` observations:
275
+
276
+ - If a model variable named `SO4` or `SO4_as` (in units of `kg/kg`) is being compared to a `castnet` observation variable also named `SO4` (in units of `ug/m3`), the system will automatically convert the model data to `ug/m3` before calculating statistics. The observational unit is always treated as the target for conversion.
277
+
278
+ ### Using Custom Data with `qlc-py`
279
+
280
+ While the shell script pipeline is designed for a seamless workflow, you can also use `qlc-py` as a standalone tool with your own NetCDF data. Simply provide absolute paths to your data files in the `mod_path` and `obs_path` fields of your JSON configuration. The data must be CF-compliant, but this allows you to bypass the MARS retrieval and processing steps entirely.
281
+
282
+ ### Example Report
283
+
284
+ An example of the final PDF report generated by the `qlc` pipeline can be found in the `$HOME/qlc/doc/` directory. This provides a complete overview of all selected plots and analyses produced. The `$HOME/qlc/Presentations/` directory contains the report of a successful run.
285
+
286
+ ### Accessing Raw Outputs for Custom Analysis
287
+
288
+ The QLC pipeline generates a wide range of outputs that can be used for further analysis outside of the main workflow.
289
+
290
+ - **Comprehensive Plots**: The `$HOME/qlc/Plots` directory contains all of the individual plots created during the run, e.g., in higher resolution or with more detail than what is included in the final summary report.
291
+ - **Exportable Data**: You can configure `qlc-py` to save the intermediate, collocated data in either NetCDF (`.nc`) or CSV (`.csv`) format.
292
+ - **Multiple Plot Formats**: Plots can be saved in various formats, including `.pdf`, `.png`, and `.jpg`.
293
+
294
+ This flexibility allows you to easily import QLC-processed data and graphics into your own analysis scripts, presentations, or reports.
295
+
qlc/install.py CHANGED
@@ -386,23 +386,28 @@ def setup(mode: str, version: str, debug: bool = False, config_file: str = None)
386
386
  generic_config_path = config_dst / "qlc.conf"
387
387
  update_qlc_version(generic_config_path, version)
388
388
 
389
- # --- Setup master symlinks to point to this installation (relative) ---
390
- # Link qlc_latest to the new version-specific root
391
- qlc_latest_link = Path(user_home) / "qlc_latest"
392
- safe_move_and_link(root, qlc_latest_link, relative=True, backup=False)
393
-
394
- # Ensure $HOME/qlc points to qlc_latest
395
- qlc_stable_link = Path(user_home) / "qlc"
396
- if not qlc_stable_link.exists() or not qlc_stable_link.is_symlink():
397
- safe_move_and_link(qlc_latest_link, qlc_stable_link, relative=True, backup=False)
398
- else:
399
- try:
400
- if not qlc_stable_link.resolve() == qlc_latest_link.resolve():
401
- safe_move_and_link(qlc_latest_link, qlc_stable_link, relative=True, backup=False)
402
- else:
403
- print(f"[SKIP] {qlc_stable_link} already links to {qlc_latest_link.name}")
404
- except FileNotFoundError: # Handle broken link
405
- safe_move_and_link(qlc_latest_link, qlc_stable_link, relative=True, backup=False)
389
+ # --- Setup master symlinks to point to this installation ---
390
+
391
+ qlc_latest_link = user_home / "qlc_latest"
392
+ qlc_stable_link = user_home / "qlc"
393
+
394
+ # Forcefully remove existing links to ensure a clean state
395
+ print(f"[LINK] Removing existing master links if they exist: {qlc_stable_link.name}, {qlc_latest_link.name}")
396
+ qlc_stable_link.unlink(missing_ok=True)
397
+ qlc_latest_link.unlink(missing_ok=True)
398
+
399
+ # Create qlc_latest -> qlc_vX.Y.Z/<mode> (relative link)
400
+ # Target path is relative to the link's location ($HOME)
401
+ latest_target = os.path.relpath(root, user_home)
402
+ print(f"[LINK] Creating master link: {qlc_latest_link} -> {latest_target}")
403
+ qlc_latest_link.symlink_to(latest_target, target_is_directory=True)
404
+
405
+ # Create qlc -> qlc_latest (relative link)
406
+ # Target path is relative to the link's location ($HOME)
407
+ stable_target = os.path.relpath(qlc_latest_link, user_home)
408
+ print(f"[LINK] Creating stable link: {qlc_stable_link} -> {stable_target}")
409
+ qlc_stable_link.symlink_to(stable_target, target_is_directory=True)
410
+
406
411
 
407
412
  # Write install info
408
413
  info = {
@@ -418,8 +423,14 @@ def setup(mode: str, version: str, debug: bool = False, config_file: str = None)
418
423
  update_qlc_version(qlc_stable_link / "config" / "qlc.conf", version)
419
424
 
420
425
  print("\n[INFO] QLC installation complete.")
421
- print("[INFO] To get started, you may need to open a new terminal or run 'rehash'.")
422
426
  print("[INFO] The following commands are now available: qlc, qlc-py, sqlc, qlc-install")
427
+ print("\n[ACTION REQUIRED]")
428
+ print("To make these commands available, you may need to add the local bin directory to your PATH.")
429
+ print("For most bash users, you can do this by running the following command:")
430
+ print(" echo 'export PATH=\"$HOME/.local/bin:$PATH\"' >> ~/.bashrc")
431
+ print("\nFor other shells (like zsh), you may need to add this line to '~/.zshrc' instead.")
432
+ print("After running the command, please open a new terminal or run 'source ~/.bashrc' to apply the changes.")
433
+
423
434
 
424
435
  if __name__ == "__main__":
425
436
  parser = argparse.ArgumentParser(description="Install QLC runtime structure")
Binary file
Binary file
Binary file
Binary file
qlc/py/io.cp311-win32.pyd CHANGED
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
qlc/sh/qlc_A1.sh CHANGED
@@ -38,24 +38,25 @@ for exp in $exps ; do
38
38
  # This is required for retrieving data from the MARS archive.
39
39
  EXPCLASS=$(echo "${exp}" | cut -c 1)
40
40
 
41
+ # For experiments other than 'nl', 'be', or 'rd', please uncomment the corresponding XCLASS line.
41
42
  case "${EXPCLASS}" in
42
43
  a) XCLASS="be" ;; # Belgium
43
44
  b) XCLASS="nl" ;; # Netherlands
44
- c) XCLASS="fr" ;; # France
45
- d) XCLASS="de" ;; # Germany
46
- e) XCLASS="es" ;; # Spain
47
- f) XCLASS="fi" ;; # Finland
48
- g) XCLASS="gr" ;; # Greece
49
- h) XCLASS="hu" ;; # Hungary
50
- i) XCLASS="it" ;; # Italy
51
- k) XCLASS="dk" ;; # Denmark
52
- l) XCLASS="pt" ;; # Portugal
53
- m) XCLASS="at" ;; # Austria
54
- n) XCLASS="no" ;; # Norway
55
- s) XCLASS="se" ;; # Sweden
56
- t) XCLASS="tr" ;; # Turkey
57
- u) XCLASS="uk" ;; # United Kingdom
58
- w) XCLASS="ch" ;; # Switzerland
45
+ # c) XCLASS="fr" ;; # France
46
+ # d) XCLASS="de" ;; # Germany
47
+ # e) XCLASS="es" ;; # Spain
48
+ # f) XCLASS="fi" ;; # Finland
49
+ # g) XCLASS="gr" ;; # Greece
50
+ # h) XCLASS="hu" ;; # Hungary
51
+ # i) XCLASS="it" ;; # Italy
52
+ # k) XCLASS="dk" ;; # Denmark
53
+ # l) XCLASS="pt" ;; # Portugal
54
+ # m) XCLASS="at" ;; # Austria
55
+ # n) XCLASS="no" ;; # Norway
56
+ # s) XCLASS="se" ;; # Sweden
57
+ # t) XCLASS="tr" ;; # Turkey
58
+ # u) XCLASS="uk" ;; # United Kingdom
59
+ # w) XCLASS="ch" ;; # Switzerland
59
60
  *) XCLASS="rd" ;; # Default to Research Department
60
61
  esac
61
62
  log "${exp}" "${XCLASS}"
qlc/sh/qlc_C5.sh CHANGED
@@ -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
@@ -612,51 +647,51 @@ EOF
612
647
  if [ -f "$ferret.jnl" ]; then
613
648
  cp -p $ferret.jnl .
614
649
  rm -f ${tfile}_burden.${ext} ${tfile}_burden_log.${ext}
615
- log "pyferret -nodisplay -script $ferret.jnl ${ifile} ${pvar} ${MODEL_RESOLUTION} ${exp} ${tfile}_burden ${ext}"
616
- 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}
617
652
  else
618
653
  # ferret plots for default journal file
619
654
  rm -f ${tfile}_burden.${ext} ${tfile}_burden_log.${ext}
620
- log "pyferret -nodisplay -script ${tfile}_burden_1x1.jnl"
621
- 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
622
657
 
623
658
  rm -f ${tfile}_zonal.${ext} ${tfile}_zonal_log.${ext}
624
- log "pyferret -nodisplay -script ${tfile}_zonal_1x1.jnl"
625
- 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
626
661
 
627
662
  rm -f ${tfile}_meridional.${ext} ${tfile}_meridional_log.${ext}
628
- log "pyferret -nodisplay -script ${tfile}_meridional_1x1.jnl"
629
- 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
630
665
 
631
666
  rm -f ${tfile}_surface.${ext} ${tfile}_surface_log.${ext}
632
- log "pyferret -nodisplay -script ${tfile}_surface_1x1.jnl"
633
- 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
634
669
 
635
670
  rm -f ${tfile}_utls.${ext} ${tfile}_utls_log.${ext}
636
- log "pyferret -nodisplay -script ${tfile}_utls_1x1.jnl"
637
- 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
638
673
  fi
639
674
 
640
675
  if [ "${exp}" == "${exp1}" ]; then
641
676
  rm -f ${tfile}_burden_diff.${ext} ${tfile}_burden_log_diff.${ext}
642
- log "pyferret -nodisplay -script ${tfile}_burden_1x1_diff.jnl"
643
- 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
644
679
 
645
680
  rm -f ${tfile}_zonal_diff.${ext} ${tfile}_zonal_log_diff.${ext}
646
- log "pyferret -nodisplay -script ${tfile}_zonal_1x1_diff.jnl"
647
- 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
648
683
 
649
684
  rm -f ${tfile}_meridional_diff.${ext} ${tfile}_meridional_log_diff.${ext}
650
- log "pyferret -nodisplay -script ${tfile}_meridional_1x1_diff.jnl"
651
- 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
652
687
 
653
688
  rm -f ${tfile}_surface_diff.${ext} ${tfile}_surface_log_diff.${ext}
654
- log "pyferret -nodisplay -script ${tfile}_surface_1x1_diff.jnl"
655
- 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
656
691
 
657
692
  rm -f ${tfile}_utls_diff.${ext} ${tfile}_utls_log_diff.${ext}
658
- log "pyferret -nodisplay -script ${tfile}_utls_1x1_diff.jnl"
659
- 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
660
695
 
661
696
  # files=("${tfile}" "${tfile}_log" "${tfile}_diff" "${tfile}_log_diff")
662
697
  files=("${tfile}_surface" "${tfile}_surface_log" "${tfile}_surface_diff" "${tfile}_surface_log_diff" \
@@ -801,6 +836,7 @@ cat >> ${texFile} <<EOF
801
836
  EOF
802
837
  fi
803
838
  done # plot
839
+
804
840
  log "----------------------------------------------------------------------------------------"
805
841
  log "${texFile}"
806
842
  cat ${texFile}
qlc/sh/qlc_D1.sh CHANGED
@@ -31,15 +31,6 @@ 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
37
- exit 1
38
- else
39
- log "Success: python command found"
40
- which python
41
- fi
42
-
43
34
  # Check if qlc-py exists
44
35
  if ! command_exists qlc-py; then
45
36
  log "Error: qlc-py command not found" >&2
qlc/sh/qlc_batch.sh CHANGED
@@ -40,9 +40,9 @@ cat > $HOME/qlc/run/qlc_batch.sh$$<<EOF
40
40
  #SBATCH --output=log-%J.out
41
41
  #SBATCH --error=err-%J.out
42
42
  #SBATCH --export=ALL
43
- $HOME/qlc/bin/qlc $1 $2 $3 $4 $5
43
+ qlc $1 $2 $3 $4 $5
44
44
  echo "SLURM_JOB_ID = ${jobid}"
45
- sbatch --dependency=afterok:${jobid} --mail-user=$USER@ecmwf.int $HOME/qlc/bin/qlc $1 $2 $3 $4
45
+ sbatch --dependency=afterok:${jobid} --mail-user=$USER@ecmwf.int qlc $1 $2 $3 $4
46
46
  EOF
47
47
  else
48
48
  cat > $HOME/qlc/run/qlc_batch.sh$$<<EOF
@@ -50,7 +50,7 @@ cat > $HOME/qlc/run/qlc_batch.sh$$<<EOF
50
50
  #SBATCH --job-name=$HOME/qlc/run/qlc_batch.sh$$
51
51
  #SBATCH --output=log-%J.out
52
52
  #SBATCH --error=err-%J.out
53
- $HOME/qlc/bin/qlc $1 $2 $3 $4
53
+ qlc $1 $2 $3 $4
54
54
  EOF
55
55
  fi
56
56
  sbatch $HOME/qlc/run/qlc_batch.sh$$
qlc/sh/qlc_main.sh CHANGED
@@ -1,6 +1,23 @@
1
1
  #!/bin/bash -e
2
2
  umask 0022
3
3
 
4
+ # --- Start: Environment Setup ---
5
+ # Find the Python executable that runs this tool.
6
+ # This ensures that any executables installed in the same environment (like pyferret) are found.
7
+ # Fallback to 'python3' if 'qlc' is not in the path (e.g., during development).
8
+ PYTHON_CMD=$(which python3)
9
+ if command -v qlc >/dev/null 2>&1; then
10
+ QLC_PATH=$(which qlc)
11
+ PYTHON_CMD=$(head -n 1 "$QLC_PATH" | sed 's/^#!//')
12
+ fi
13
+
14
+ # Get the directory of the Python executable.
15
+ PYTHON_BIN_DIR=$(dirname "$PYTHON_CMD")
16
+
17
+ # Prepend this directory to the PATH for this script and all subscripts.
18
+ export PATH="$PYTHON_BIN_DIR:$PATH"
19
+ # --- End: Environment Setup ---
20
+
4
21
  ARCH="`uname -m`"
5
22
  myOS="`uname -s`"
6
23
  HOST="`hostname -s`"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rc-qlc
3
- Version: 0.3.26
3
+ Version: 0.3.27
4
4
  Summary: Quick Look Content (QLC): Model–Observation Comparison Suite for Use with CAMS
5
5
  Home-page: https://pypi.org/project/qlc/
6
6
  Author-email: ResearchConcepts io GmbH <contact@researchconcepts.io>
@@ -16,10 +16,13 @@ Requires-Dist: netCDF4
16
16
  Requires-Dist: scipy
17
17
  Requires-Dist: cartopy
18
18
  Requires-Dist: tqdm
19
+ Requires-Dist: adjustText
19
20
  Provides-Extra: build
20
21
  Requires-Dist: tomli; extra == "build"
21
22
  Provides-Extra: test
22
23
  Requires-Dist: pytest; extra == "test"
24
+ Provides-Extra: ferret
25
+ Requires-Dist: pyferret; extra == "ferret"
23
26
  Provides-Extra: cams
24
27
  Dynamic: home-page
25
28
  Dynamic: license-file
@@ -36,6 +39,24 @@ The suite streamlines the entire post-processing workflow, from data retrieval a
36
39
 
37
40
  ---
38
41
 
42
+ ## What's New in v0.3.27
43
+
44
+ This release focuses on improving the out-of-the-box installation experience, especially for HPC environments, and significantly expanding the user documentation.
45
+
46
+ - **Installer Overhaul**: The `qlc-install` script is now more robust.
47
+ - It automatically creates the `qlc` -> `qlc_latest` -> `qlc_vX.Y.Z/<mode>` symlink structure, removing the need for manual setup.
48
+ - It now provides clear, actionable instructions on how to update your `PATH` if needed.
49
+ - **Enhanced HPC & Batch Job Support**:
50
+ - The batch submission script (`sqlc`) is more reliable, no longer using hardcoded paths.
51
+ - Shell scripts are now more compatible with typical HPC environments that may only have a `python3` executable.
52
+ - **Expanded Documentation**:
53
+ - The `USAGE.md` guide now includes comprehensive, exhaustive lists of currently available plotting regions, observation datasets, and supported chemical/meteorological variables.
54
+ - A new "Advanced Workflow" section has been added to `USAGE.md`, explaining the underlying shell script pipeline, the `param/ncvar/myvar` variable mapping system, and how to use your own data with the `qlc-py` engine.
55
+ - Added a note on the future integration with the GHOST database.
56
+ - **Dependency Fix**: The `adjustText` library is now included as a core dependency.
57
+
58
+ ---
59
+
39
60
  ## What's New in v0.3.26
40
61
 
41
62
  This version introduces a completely new, high-performance Python processing engine and a more robust installation system.
@@ -82,18 +103,43 @@ qlc b2ro b2rn 2018-12-01 2018-12-21
82
103
 
83
104
  ---
84
105
 
106
+ ## Prerequisites
107
+
108
+ Before running the QLC suite, please ensure the following system-level software is installed and accessible in your environment's `PATH`:
109
+
110
+ - **`pdflatex`**: Required for generating the final PDF reports. It is part of the **TeX Live** distribution.
111
+ - **`CDO` (Climate Data Operators)**: Used for processing NetCDF data.
112
+ - **`eccodes`**: The ECMWF library for decoding and encoding GRIB files.
113
+ - **`netcdf`**: The core NetCDF libraries.
114
+
115
+ On HPC systems, these tools are typically made available by loading the appropriate modules (e.g., `module load cdo`). On personal machines, they can be installed using system package managers like `apt-get` (Debian/Ubuntu), `yum` (Red Hat/CentOS), or `brew` (macOS).
116
+
117
+ ---
118
+
85
119
  ## Installation and Configuration
86
120
 
87
121
  ### Standard Installation
88
122
 
89
123
  QLC is installed from PyPI. After the `pip install`, you **must** run `qlc-install` to set up the necessary local directory structure.
90
124
 
125
+ **First-Time Installation**
126
+ ```bash
127
+ pip install rc-qlc
128
+ ```
129
+
130
+ **Upgrading an Existing Installation**
131
+ To ensure you have the latest version, always use the `--upgrade` flag:
132
+ ```bash
133
+ pip install --upgrade rc-qlc
134
+ ```
135
+
136
+ After installing, set up your desired environment:
91
137
  ```bash
92
138
  # For a standalone test environment with example data
93
- pip install rc-qlc && qlc-install --mode test
139
+ qlc-install --mode test
94
140
 
95
141
  # For an operational CAMS environment
96
- pip install rc-qlc && qlc-install --mode cams
142
+ qlc-install --mode cams
97
143
  ```
98
144
 
99
145
  ### Installation in Restricted Environments (HPC/ATOS)
@@ -169,6 +215,89 @@ For advanced development, you can also use `--mode interactive`, which requires
169
215
  qlc-install --mode interactive --config /path/to/your/custom_qlc.conf
170
216
  ```
171
217
 
218
+ ## Advanced Topics
219
+
220
+ ### Installing PyFerret for Global Plots
221
+
222
+ The `qlc_C5.sh` script, which generates global map plots, requires the `pyferret` library. This is an optional dependency.
223
+
224
+ - **To install with `pyferret` support:**
225
+ ```bash
226
+ pip install "rc-qlc[ferret]"
227
+ ```
228
+ - **If you do not need these plots**, you can either skip the `pyferret` installation or, if it's already installed, disable the script by commenting out `"C5"` in the `SUBSCRIPT_NAMES` array in your `$HOME/qlc/config/qlc.conf` file.
229
+ - **For HPC environments**, `pyferret` is often available as a module that can be loaded (e.g., `module load ferret/7.6.3`).
230
+
231
+ ### Manual PyFerret Installation for macOS / Apple Silicon
232
+
233
+ If you are using a Mac with Apple Silicon (M1/M2/M3) or if the standard installation fails, `pyferret` may require a manual setup using a dedicated `conda` environment. `pip` installations are not recommended for this package on macOS as they may not work correctly with the ARM architecture.
234
+
235
+ The most reliable method is to use `conda` with the Rosetta 2 translation layer.
236
+
237
+ **1. (If needed) Install Conda**
238
+ If you do not have `conda` installed, we recommend **Miniforge**, which is a minimal installer that is optimized for Apple Silicon and includes the high-performance `mamba` package manager.
239
+ ```bash
240
+ # Download and run the installer for Apple Silicon
241
+ curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-arm64.sh"
242
+ bash Miniforge3-MacOSX-arm64.sh
243
+ # Follow the prompts and restart your terminal after installation
244
+ ```
245
+
246
+ **2. Create a Dedicated x86_64 Environment for PyFerret**
247
+ This command creates a new `conda` environment named `pyferret_env` and installs the Intel (`x86_64`) version of `pyferret`, which will run seamlessly on Apple Silicon via Rosetta 2. It also pins `numpy` to a version older than 2.0 to ensure compatibility.
248
+
249
+ ```bash
250
+ CONDA_SUBDIR=osx-64 conda create -n pyferret_env -c conda-forge pyferret ferret_datasets "numpy<2" --yes
251
+ ```
252
+
253
+ **3. Configure QLC to Use the New Environment**
254
+ The QLC scripts need to know where to find this new `pyferret` installation. You can achieve this by modifying the `qlc_C5.sh` script to activate the environment.
255
+
256
+ Open the file `$HOME/qlc/sh/qlc_C5.sh` and add the following lines near the top, after `source $FUNCTIONS`:
257
+
258
+ ```bash
259
+ # ... after 'source $FUNCTIONS'
260
+ # Activate the dedicated conda environment for pyferret
261
+ if [ -f "$HOME/miniforge3/bin/activate" ]; then
262
+ . "$HOME/miniforge3/bin/activate"
263
+ conda activate pyferret_env
264
+ fi
265
+ # ... rest of the script
266
+ ```
267
+ *Note: The path to the activate script may differ if you installed Anaconda/Miniforge in a custom location.*
268
+
269
+ ### MARS Data Retrieval
270
+ The `qlc_A1.sh` script is responsible for retrieving data from the ECMWF MARS archive. It uses a mapping system to associate the experiment prefix with a MARS `class`.
271
+
272
+ By default, the script is configured for `nl` (Netherlands), `be` (Belgium), and `rd` (Research Department) experiments. If you are working with data from other classes (e.g., `fr` for France, `de` for Germany), you will need to manually edit `$HOME/qlc/sh/qlc_A1.sh` and uncomment / edit the corresponding `XCLASS` line to ensure data is retrieved correctly.
273
+
274
+ ---
275
+
276
+ ## Troubleshooting
277
+
278
+ ### macOS "Permission Denied" or Quarantine Issues
279
+
280
+ On macOS, the Gatekeeper security feature may "quarantine" files, including shell scripts that have been downloaded or modified. This can prevent them from being executed, sometimes with a "Permission Denied" error, even if the file has the correct execute permissions (`+x`).
281
+
282
+ This is most likely to occur if you manually edit the `qlc` shell scripts (`.sh` files) directly in their `site-packages` installation directory.
283
+
284
+ To resolve this, you can manually remove the quarantine attribute from the script directory using the `xattr` command in your terminal.
285
+
286
+ 1. **First, find the exact location of the `qlc` package:**
287
+ ```bash
288
+ pip show rc-qlc
289
+ ```
290
+ Look for the `Location:` line in the output. This is your `site-packages` path.
291
+
292
+ 2. **Then, use the `xattr` command to remove the quarantine flag:**
293
+ Use the path from the previous step to build the full path to the `qlc/sh` directory.
294
+ ```bash
295
+ # The path will depend on your Python installation. Use the location from 'pip show'.
296
+ xattr -rd com.apple.quarantine /path/to/your/site-packages/qlc/sh/
297
+ ```
298
+
299
+ This should immediately resolve the execution issues.
300
+
172
301
  ---
173
302
 
174
303
  ## License
@@ -176,3 +305,5 @@ qlc-install --mode interactive --config /path/to/your/custom_qlc.conf
176
305
  © ResearchConcepts io GmbH
177
306
  Contact: [contact@researchconcepts.io](mailto:contact@researchconcepts.io)
178
307
  MIT-compatible, source-restricted under private release until publication.
308
+
309
+ ---
@@ -1,5 +1,5 @@
1
1
  qlc/__init__.py,sha256=gTHCo506l8Ud5R8eQr1H9ozSlxCNVRSg3TYaiYce9ow,216
2
- qlc/install.py,sha256=nA8QILDConhODeQslWTYS1l8BilXpGD3Ld6WXZ-Yk2Y,18972
2
+ qlc/install.py,sha256=ADhPZyxB8MtDMcttG_qIPzc43hVUTk9vIt_SGIc-oUQ,19508
3
3
  qlc/cli/__init__.py,sha256=EJ-W8SAC6i2Rdire1aYqCiWp_gu3-Ha-d0NekI8ZkSY,4331
4
4
  qlc/cli/installer.py,sha256=DVbRCot5T-LMBmODc-esud9j_WCMg0xpCNJiHxeoNew,1369
5
5
  qlc/cli/qlc_main.py,sha256=4XTxBhMVA1dy7KP4ASNTDM5_TLh5L1IuuQPdotfAvUw,8829
@@ -20,9 +20,10 @@ qlc/config/nml/mars_D.nml,sha256=fCEEpbs_x_KqSDjEPm6Z7lKzURFhpQnSNAPCne6WIvI,584
20
20
  qlc/config/nml/mars_E.nml,sha256=7gEVnnxwhE8VvYHXFgQRaDGiJBgo_L0gYDhUuzIjm98,599
21
21
  qlc/config/nml/mars_F.nml,sha256=UUBJoDwjww62myJXB1rKM5w14r1-PXNB32CWoGTIYDs,554
22
22
  qlc/config/nml/mars_G.nml,sha256=QG68v55LpucmvkKq1Gh2S2_vyrsLTCVGiRRMiRfhoyI,554
23
+ qlc/doc/CAMS_b2ro-b2rn_20181201-20181221_qlc_Z1-png_202509090814.pdf,sha256=kltQSosZRDQ2UvX367OUnZq0_WUvWswt-Rr3_I5Pk4w,11807466
23
24
  qlc/doc/CONTRIBUTING.md,sha256=wQxEfhegvfuruvrXQBfieFkUJJIGEpt5uMco754yRyc,2712
24
- qlc/doc/README.md,sha256=93ciI80dRlnhxJ7WqBt1VV1MSKYKKiyfOFb6qSABHKU,7287
25
- qlc/doc/USAGE.md,sha256=C8Xy53dFE_4BBA_u5AnJK_SzcCiQx4Iixn4ERPCEfHc,4329
25
+ qlc/doc/README.md,sha256=i48c4gO03cRwwzZ_qRZtlcJBrqiO6NHG0fUSXE5I_M4,14192
26
+ qlc/doc/USAGE.md,sha256=M3xy2atKwub_az7hZerQUtAjv3-BRPDSt8gIcH3bOnA,18598
26
27
  qlc/examples/cams_case_1/mod/b2rn/2018/b2rn_20181201-20181221_B1_pl.grb,sha256=amWL5pi5OpxmkcejAleW22n57EK0nVeU_kl671bdASU,41073480
27
28
  qlc/examples/cams_case_1/mod/b2rn/2018/b2rn_20181201-20181221_C1_sfc.grb,sha256=dFfCy3awEGV8_UuOxML22YVrTVQOEPoOIManyuLV64U,2979499
28
29
  qlc/examples/cams_case_1/mod/b2ro/2018/b2ro_20181201-20181221_B1_pl.grb,sha256=WKK2bZf3i9VDj0K1uoZaToXxVZJXPxXEGm52rrLGVSg,41073480
@@ -59,44 +60,44 @@ qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181228.nc,sha25
59
60
  qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181229.nc,sha256=TtdledzM8v9fKWMy07j0m2tXZcFVR2LOJCFhka9Ancg,148217
60
61
  qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181230.nc,sha256=H2EsyIFva38W8K8APOo3nbYOv_5xb0kUcGSNXQGp7RQ,145680
61
62
  qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181231.nc,sha256=aTAAzE3uXeeUIfVwn2Y_yDBM2oUe3HnFMyA7blD_8io,145563
62
- qlc/py/__main__.cp311-win32.pyd,sha256=8JS-kPo2oKwDWr6R4q0kyyh29J7DLzCLALSNtH3tOwI,28160
63
- qlc/py/averaging.cp311-win32.pyd,sha256=5kWeh_toZFvg7nxBmVx0QSXbiRuqGFpOgxNJEOrar40,34304
64
- qlc/py/bias_plots.cp311-win32.pyd,sha256=5V3fXAY-KjdB_tWbAmrfCBbCK9F_gbXJYjdGMillOU8,53248
65
- qlc/py/control.cp311-win32.pyd,sha256=DDZA0bJCbMqLP1qFtbIEhh3XEAdhzv7POyZeGZlBUZE,127488
66
- qlc/py/io.cp311-win32.pyd,sha256=UGiv7AwpT31aBacN94tFPRnzqUnhW0A3bkSO7wSfSwA,80896
67
- qlc/py/loadmod.cp311-win32.pyd,sha256=neGNN6ZRTHVYJ6F7BOcid6W9rojJvESw2eGpzerNB4s,114688
68
- qlc/py/loadobs.cp311-win32.pyd,sha256=ld3ctNMHEdkiolEcWD1QrZuET9WPNumVWgRN-6qefLU,99328
69
- qlc/py/logging_utils.cp311-win32.pyd,sha256=2eozYcusP__a00QzpiDQPbh8QTE9KVyc6GjTtJYHeok,57856
70
- qlc/py/map_plots.cp311-win32.pyd,sha256=7w415cTZaLJp0dbiA5MraMmdgkLD2PxkPNlyrVMEn24,112128
71
- qlc/py/matched.cp311-win32.pyd,sha256=5ce2LYYIMFj-b7_oaMUnSYhKxLAKBf_59sC6nNSPp4s,43008
72
- qlc/py/plot_config.cp311-win32.pyd,sha256=2iB8FYd-TBcB6IgEBZEFNfLP_RHPCjrNlW9scCwbImk,26112
73
- qlc/py/plotting.cp311-win32.pyd,sha256=2-r5QWuTXKk5qM7VHamEWT1dJno7oMTXRPB8hzu3myA,103936
74
- qlc/py/plugin_loader.cp311-win32.pyd,sha256=RnYsWJViVjyHfnrC9JDfy2aFdaGGItRKknb49bCVRPI,38400
75
- qlc/py/processing.cp311-win32.pyd,sha256=1vQXwQ2CvlJKeU6zILvhRa2J1NfGmbHGCqtIt4Dyxo0,64512
76
- qlc/py/scatter_plots.cp311-win32.pyd,sha256=aqkA-4jl6MFzWVuJhrsfKDyWXXlbgiMscuSr2ZAbIg0,49152
77
- qlc/py/stations.cp311-win32.pyd,sha256=aOTsytudbPOFAs-cklexd0raL_A1kaBDVXUbqS6D6s4,474624
78
- qlc/py/statistics.cp311-win32.pyd,sha256=w_r0DrMEGmDkcjYskRlXzg5XlRf-TV3BtqjZ_Wdq5ZQ,160256
79
- qlc/py/style.cp311-win32.pyd,sha256=tzMDBDOiXzetooJ74Gvp0kzEJn4kOGX8viZGm65c71Q,198144
80
- qlc/py/timeseries_plots.cp311-win32.pyd,sha256=1vQEfapLWh6w5X0mU1A-Swt8ZRDt9x8q2wKVDn3sRNA,425472
81
- qlc/py/utils.cp311-win32.pyd,sha256=YELqbDScUnbPkMjrHtKE4k5c5uuLuIHQuwKXAP0_NtE,373760
82
- qlc/py/version.cp311-win32.pyd,sha256=TpOm_ewve0nVAilchli_Rg9B-PCJ4SDO3-kViKyKZQk,13824
83
- qlc/sh/qlc_A1.sh,sha256=eCOtLxZ0Jq1vT5KZeYPVqJNTO-HyeOoLSWlKF36nYPw,5476
63
+ qlc/py/__main__.cp311-win32.pyd,sha256=UfMPzfxoWMg3RizTHQwjLCXw0QgiVoglfo3UcoQKIAk,28160
64
+ qlc/py/averaging.cp311-win32.pyd,sha256=3JnY1HDP6i4EfF_vGaWChNDKxXHqtpuRuVTI_1bXZfA,34304
65
+ qlc/py/bias_plots.cp311-win32.pyd,sha256=7cvCeJDPp46YJU2sJR6rt0Opq4yu6CjBAPfvNneEjDA,53248
66
+ qlc/py/control.cp311-win32.pyd,sha256=BgvSwbbAqTGu23Db5Dh-aUm2ez-l9j-Egpv1D3J6ZdQ,127488
67
+ qlc/py/io.cp311-win32.pyd,sha256=s7nDOr_y3ngfS16fyWXZlXeJf4PA2u6xpZrvaxLd7nM,80896
68
+ qlc/py/loadmod.cp311-win32.pyd,sha256=5tv_8jiptmO5IpuwWXJEfmAZOvOEG_yNffCV7cswh3g,114688
69
+ qlc/py/loadobs.cp311-win32.pyd,sha256=4z0_k1BHZddS-dBBzfjO5Z1D4itQQl5_Dr-NJKgju8Y,99328
70
+ qlc/py/logging_utils.cp311-win32.pyd,sha256=zCF3yRVDCFFvyu9btdxZynfyGDhNm4duZsAAeXNkNik,57856
71
+ qlc/py/map_plots.cp311-win32.pyd,sha256=lokwVt28R2Vc1jNbJ_WIM7V05L4iP-Zg1AY2HHtnYAs,112128
72
+ qlc/py/matched.cp311-win32.pyd,sha256=-qxkKAb9KWKk4PbwJF0aguH0M_NzZBZ-37NF3FXnR6c,43008
73
+ qlc/py/plot_config.cp311-win32.pyd,sha256=itsyGS59_Gx_Jx9GGhuDc3Al771HrVSMpvgdbn9QVF4,26112
74
+ qlc/py/plotting.cp311-win32.pyd,sha256=wcUZRK-sm_CFXyhl-k3ngwBD36MMrOoKcL1Te19csD0,103936
75
+ qlc/py/plugin_loader.cp311-win32.pyd,sha256=0Ccj8wb4-hSqsYCV5QBeQnwBlev5UBgm5QWGJ1M-AcQ,38400
76
+ qlc/py/processing.cp311-win32.pyd,sha256=j9u2F_IRmGBWCqRMVTU94wQaWPqKYcwL2jq2vUWG6g8,64512
77
+ qlc/py/scatter_plots.cp311-win32.pyd,sha256=PXtN-vBA2pvR7sr02R-mWmWM2XkAmj5VtyU2YvFZ8BY,49152
78
+ qlc/py/stations.cp311-win32.pyd,sha256=VBxfvBUAfsEJA4yvkYBktQmXUXCZtmr0Q5BZiewDK7o,474624
79
+ qlc/py/statistics.cp311-win32.pyd,sha256=0ELe0FqSKD5X8YBTwHPwmIU-dxUKTTSrwLOu-jNgwSA,160256
80
+ qlc/py/style.cp311-win32.pyd,sha256=KHxKikNAgKg9Mn0foPTvx9TElvgdyAZ5SWnGalHUw1U,198144
81
+ qlc/py/timeseries_plots.cp311-win32.pyd,sha256=cRzz0PBvRwNHWgkJto44TCyUBwXJL6LzDTSbAgNdDxs,425472
82
+ qlc/py/utils.cp311-win32.pyd,sha256=jmbqJadPcTG1B_nPDRrxjU4QvzdN83u8ytPuzezmXrw,373760
83
+ qlc/py/version.cp311-win32.pyd,sha256=RyKHw9n8JnP14ltTP7TwHY8wxhVFoztGjs9aYQwv3iQ,13824
84
+ qlc/sh/qlc_A1.sh,sha256=2V8Z-htiBKu0Ex70q18UcUembEWzqPUOo5qkQxjTnYw,5607
84
85
  qlc/sh/qlc_B1a.sh,sha256=ZXAPdliYKbORTvd7OxWOynUY4WlIJ0TC10zOe1eWpdU,3216
85
86
  qlc/sh/qlc_B2.sh,sha256=owAoladmxKvoqSoNPBo7OaZfC6VG9r1ML8GoKbpVOes,11438
86
- qlc/sh/qlc_C5.sh,sha256=3iIlrkQl5xXNGdMb77EAKRK6FZD6d6liScUuIFP-uVc,36950
87
- qlc/sh/qlc_D1.sh,sha256=hCLb0CRjqfBt0-SGZgXwDIsPDuplWiJcUt6HWOfe0ro,13953
87
+ qlc/sh/qlc_C5.sh,sha256=Fg7zv0u07rdhQXyzzE-uKrR84ww374EV3QKEc27Ljas,38916
88
+ qlc/sh/qlc_D1.sh,sha256=HichdtKlyBcncX3xWwFwwZovh7gCmerr5uTUwBP9ezY,13769
88
89
  qlc/sh/qlc_Z1.sh,sha256=pFdjSYkkgDC-UQdiA8EWzKwWmKkF1Td-YNSg4eEDX2M,5638
89
- qlc/sh/qlc_batch.sh,sha256=MVCE-7FFZmAqxyQwCA2mQtxdGwvxDB5cTRv9cTmJ9U4,2476
90
+ qlc/sh/qlc_batch.sh,sha256=SbjPopr-XusB6h-oa7tQfxGpBSEuX6HTEjPwZffFnro,2434
90
91
  qlc/sh/qlc_common_functions.sh,sha256=qFiQPUTQV2AejZNOky_yjfsKExopCtj4hFqcjDGIBqg,5500
91
- qlc/sh/qlc_main.sh,sha256=fBchfhBr7E1osl5AqoZV0OpTY63B6z6N60MrWmrQiwI,5018
92
+ qlc/sh/qlc_main.sh,sha256=JX-payvMFpVx1j6joLzkNfnzUDHQCmoTDN0sc2C1zOE,5681
92
93
  qlc/sh/tex_template/beamercolorthemeCAMS2_35.sty,sha256=qt6xI-6fQgUye2nr7NQYyy7yim5xJJwrMzYujzM6AVc,2471
93
94
  qlc/sh/tex_template/beamerfontthemeCAMS2_35.sty,sha256=WgcDWPM0r-zWO58UWvkUcCawN2x_hiOTCOXUJqq87Pw,5565
94
95
  qlc/sh/tex_template/beamerthemeCAMS2_35.sty,sha256=9WnfzBr5lQfQqACO2t6O7jZrX_IrsP5GR7GwPW9kCVE,576
95
96
  qlc/sh/tex_template/subcaption.sty,sha256=wB81gU2MIduCGg4si0lr7JCyyfxhQVjJbGpO2vfLTnY,6107
96
97
  qlc/sh/tex_template/template.tex,sha256=66ipQGTzWh6b7jKp2bGGn1TeYRMCwIAFyqvSkprxO0w,4769
97
- rc_qlc-0.3.26.dist-info/licenses/LICENSE,sha256=nKMnbH9hXXHmwB7c0rkt2Ucf-U_rBqZYb7f0g2nX57c,1102
98
- rc_qlc-0.3.26.dist-info/METADATA,sha256=jsNcormtDwmUWkYIRpS5P41kfHczf-j4tKpWRaS2sV8,8027
99
- rc_qlc-0.3.26.dist-info/WHEEL,sha256=Ri8zddKrjGdgjlj1OpSsvpDnvHfnQhMQWi3E_v2pqng,97
100
- rc_qlc-0.3.26.dist-info/entry_points.txt,sha256=haCqahVrnFhVkfBt0HoOuVpKGV1KJOKpC1v75lOBl_s,191
101
- rc_qlc-0.3.26.dist-info/top_level.txt,sha256=Czv4KZhpli6RXvgvtCB1g87eRNEM2R-8iHplel1Qp5Q,4
102
- rc_qlc-0.3.26.dist-info/RECORD,,
98
+ rc_qlc-0.3.27.dist-info/licenses/LICENSE,sha256=nKMnbH9hXXHmwB7c0rkt2Ucf-U_rBqZYb7f0g2nX57c,1102
99
+ rc_qlc-0.3.27.dist-info/METADATA,sha256=5U9LVIeXwucxAg6mZmlPL7d2xKpwJvXdNXdbHC3AjqY,15025
100
+ rc_qlc-0.3.27.dist-info/WHEEL,sha256=Ri8zddKrjGdgjlj1OpSsvpDnvHfnQhMQWi3E_v2pqng,97
101
+ rc_qlc-0.3.27.dist-info/entry_points.txt,sha256=haCqahVrnFhVkfBt0HoOuVpKGV1KJOKpC1v75lOBl_s,191
102
+ rc_qlc-0.3.27.dist-info/top_level.txt,sha256=Czv4KZhpli6RXvgvtCB1g87eRNEM2R-8iHplel1Qp5Q,4
103
+ rc_qlc-0.3.27.dist-info/RECORD,,