rc-qlc 0.3.24__cp311-cp311-win_amd64.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.
- qlc/__init__.py +8 -0
- qlc/cli/__init__.py +21 -0
- qlc/cli/installer.py +16 -0
- qlc/cli/qlc_main.py +185 -0
- qlc/cli/qlc_py_main.py +74 -0
- qlc/config/json/qlc_config.json +41 -0
- qlc/config/json/qlc_config_example_1a_all-obs.json +237 -0
- qlc/config/json/qlc_config_example_1b_all-mod.json +353 -0
- qlc/config/json/qlc_config_example_1c_all-coll.json +266 -0
- qlc/config/json/qlc_config_example_2a_all-obs.json +237 -0
- qlc/config/json/qlc_config_example_2b_all-mod.json +353 -0
- qlc/config/json/qlc_config_example_2c_all-coll.json +265 -0
- qlc/config/json/qlc_config_example_3a-us_obs.json +82 -0
- qlc/config/json/qlc_config_example_3b-us_mod.json +122 -0
- qlc/config/json/qlc_config_example_3c-us_coll.json +46 -0
- qlc/config/json/qlc_config_example_4a_eu-obs.json +41 -0
- qlc/config/json/qlc_config_example_4b_eu-mod.json +122 -0
- qlc/config/json/qlc_config_example_4c_eu-coll.json +45 -0
- qlc/config/nml/mars_A1_sfc.nml +19 -0
- qlc/config/nml/mars_A2_sfc.nml +19 -0
- qlc/config/nml/mars_A3_sfc.nml +19 -0
- qlc/config/nml/mars_B1_pl.nml +19 -0
- qlc/config/nml/mars_B2_pl.nml +19 -0
- qlc/config/nml/mars_C1_pl.nml +19 -0
- qlc/config/nml/mars_C2_pl.nml +19 -0
- qlc/config/nml/mars_C3_ml.nml +19 -0
- qlc/config/nml/mars_D.nml +19 -0
- qlc/config/nml/mars_E.nml +19 -0
- qlc/config/nml/mars_F.nml +19 -0
- qlc/config/nml/mars_G.nml +19 -0
- qlc/config/qlc_cams.conf +26 -0
- qlc/config/qlc_test.conf +26 -0
- qlc/config/qlc_tex.conf +107 -0
- qlc/doc/CONTRIBUTING.md +105 -0
- qlc/doc/README.md +116 -0
- qlc/doc/USAGE.md +58 -0
- qlc/examples/cams_case_1/config/json/qlc_config.json +41 -0
- qlc/examples/cams_case_1/config/nml/mars_A3_sfc.nml +19 -0
- qlc/examples/cams_case_1/config/nml/mars_B1_pl.nml +19 -0
- qlc/examples/cams_case_1/config/nml/mars_C1_pl.nml +19 -0
- qlc/examples/cams_case_1/config/qlc_cams.conf +122 -0
- qlc/examples/cams_case_1/mod/b2ro/2018/b2ro_20181215-20181231_A3_sfc.grb +0 -0
- qlc/examples/cams_case_1/mod/iqi9/2018/iqi9_20181215-20181231_A3_sfc.grb +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181201.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181202.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181203.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181204.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181205.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181206.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181207.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181208.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181209.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181210.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181211.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181212.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181213.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181214.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181215.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181216.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181217.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181218.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181219.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181220.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181221.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181222.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181223.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181224.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181225.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181226.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181227.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181228.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181229.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181230.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_daily/v_20240216/201812/ebas_20181231.nc +0 -0
- qlc/examples/cams_case_1/obs/ebas_station-locations.csv +50 -0
- qlc/install.py +285 -0
- qlc/py/__main__.cp311-win_amd64.pyd +0 -0
- qlc/py/averaging.cp311-win_amd64.pyd +0 -0
- qlc/py/bias_plots.cp311-win_amd64.pyd +0 -0
- qlc/py/control.cp311-win_amd64.pyd +0 -0
- qlc/py/io.cp311-win_amd64.pyd +0 -0
- qlc/py/loadmod.cp311-win_amd64.pyd +0 -0
- qlc/py/loadobs.cp311-win_amd64.pyd +0 -0
- qlc/py/logging_utils.cp311-win_amd64.pyd +0 -0
- qlc/py/map_plots.cp311-win_amd64.pyd +0 -0
- qlc/py/matched.cp311-win_amd64.pyd +0 -0
- qlc/py/plot_config.cp311-win_amd64.pyd +0 -0
- qlc/py/plotting.cp311-win_amd64.pyd +0 -0
- qlc/py/plugin_loader.cp311-win_amd64.pyd +0 -0
- qlc/py/processing.cp311-win_amd64.pyd +0 -0
- qlc/py/scatter_plots.cp311-win_amd64.pyd +0 -0
- qlc/py/stations.cp311-win_amd64.pyd +0 -0
- qlc/py/statistics.cp311-win_amd64.pyd +0 -0
- qlc/py/style.cp311-win_amd64.pyd +0 -0
- qlc/py/timeseries_plots.cp311-win_amd64.pyd +0 -0
- qlc/py/utils.cp311-win_amd64.pyd +0 -0
- qlc/py/version.cp311-win_amd64.pyd +0 -0
- qlc/sh/qlc_A1.sh +127 -0
- qlc/sh/qlc_B1a.sh +123 -0
- qlc/sh/qlc_B2.sh +258 -0
- qlc/sh/qlc_C5.sh +825 -0
- qlc/sh/qlc_D1.sh +130 -0
- qlc/sh/qlc_Z1.sh +165 -0
- qlc/sh/qlc_common_functions.sh +157 -0
- qlc/sh/qlc_main.sh +127 -0
- qlc/sh/qlc_start.sh +23 -0
- qlc/sh/qlc_start_batch.sh +46 -0
- rc_qlc-0.3.24.dist-info/METADATA +142 -0
- rc_qlc-0.3.24.dist-info/RECORD +113 -0
- rc_qlc-0.3.24.dist-info/WHEEL +5 -0
- rc_qlc-0.3.24.dist-info/entry_points.txt +6 -0
- rc_qlc-0.3.24.dist-info/licenses/LICENSE +21 -0
- rc_qlc-0.3.24.dist-info/top_level.txt +1 -0
qlc/__init__.py
ADDED
qlc/cli/__init__.py
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# QLC module package init
|
2
|
+
import os
|
3
|
+
import subprocess
|
4
|
+
import sys
|
5
|
+
|
6
|
+
def run_shell_driver():
|
7
|
+
# Correctly locate the 'sh' directory relative to the package installation
|
8
|
+
sh_dir = os.path.join(os.path.dirname(__file__), '..', 'sh')
|
9
|
+
script = os.path.join(sh_dir, "qlc_main.sh")
|
10
|
+
subprocess.run(["bash", script] + sys.argv[1:])
|
11
|
+
|
12
|
+
def run_python_driver():
|
13
|
+
# This function seems to be for a different purpose, ensure qlc_main is correct
|
14
|
+
from qlc.cli.qlc_main import main
|
15
|
+
main()
|
16
|
+
|
17
|
+
def run_batch_driver():
|
18
|
+
# Correctly locate the 'sh' directory relative to the package installation
|
19
|
+
sh_dir = os.path.join(os.path.dirname(__file__), '..', 'sh')
|
20
|
+
script = os.path.join(sh_dir, "qlc_start_batch.sh")
|
21
|
+
subprocess.run(["bash", script] + sys.argv[1:])
|
qlc/cli/installer.py
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
import argparse
|
2
|
+
from qlc.install import setup
|
3
|
+
from qlc.py.version import QLC_VERSION
|
4
|
+
|
5
|
+
def main():
|
6
|
+
parser = argparse.ArgumentParser(description="QLC Installer")
|
7
|
+
parser.add_argument(
|
8
|
+
"--mode",
|
9
|
+
choices=["cams", "test", "interactive"],
|
10
|
+
default="test",
|
11
|
+
help="Installation mode: test (for tests), cams (for CAMS), or interactive (development)"
|
12
|
+
)
|
13
|
+
args = parser.parse_args()
|
14
|
+
|
15
|
+
print(f"[QLC-INSTALL] Installing QLC version {QLC_VERSION} in '{args.mode}' mode")
|
16
|
+
setup(mode=args.mode, version=QLC_VERSION)
|
qlc/cli/qlc_main.py
ADDED
@@ -0,0 +1,185 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import json
|
4
|
+
import time
|
5
|
+
import logging
|
6
|
+
import argparse
|
7
|
+
import traceback
|
8
|
+
import multiprocessing
|
9
|
+
import concurrent.futures
|
10
|
+
from datetime import datetime
|
11
|
+
from multiprocessing import current_process
|
12
|
+
from concurrent.futures import ThreadPoolExecutor, as_completed
|
13
|
+
from qlc.py.control import run_main_processing, process_multiple_configs_sp, process_single_config
|
14
|
+
from qlc.py.utils import expand_paths, get_timestamp, setup_logging, validate_paths, merge_global_attributes
|
15
|
+
from qlc.py.version import QLC_VERSION, QLC_RELEASE_DATE, QLC_DISTRIBUTION
|
16
|
+
from qlc.py.plugin_loader import try_import_plugin_module
|
17
|
+
from qlc.py.logging_utils import log_input_availability
|
18
|
+
from qlc.py.logging_utils import log_qlc_banner
|
19
|
+
|
20
|
+
# -----------------------------------------------
|
21
|
+
# QLC main controller (Master Orchestration)
|
22
|
+
# -----------------------------------------------
|
23
|
+
|
24
|
+
def load_config_with_defaults(config):
|
25
|
+
# Set defaults if missing
|
26
|
+
defaults = {
|
27
|
+
"global_attributes": {
|
28
|
+
"title": "QLC Processor application",
|
29
|
+
"subtitle": f"Processing file info (auto replaced)",
|
30
|
+
"summary": "This file contains metadata processed by QLC.",
|
31
|
+
"author": "Plain & Simple, plain.simple@example.com",
|
32
|
+
"source": "Quick Look CAMS (QLC) Processor",
|
33
|
+
"version": f"QLC Version: {QLC_VERSION}",
|
34
|
+
"qlcmode": f"QLC Mode: {QLC_DISTRIBUTION}",
|
35
|
+
"release": f"QLC Release Date: {QLC_RELEASE_DATE}",
|
36
|
+
"contact": "Swen Metzger, ResearchConcepts io GmbH",
|
37
|
+
"rcemail": "contact@researchconcepts.io",
|
38
|
+
"internet": "https://www.researchconcepts.io",
|
39
|
+
"timestamp": f"Created on {datetime.now()}",
|
40
|
+
"history": f"User specific (optional)",
|
41
|
+
"Conventions": "CF-1.8"
|
42
|
+
},
|
43
|
+
"name": "CAMS2_35",
|
44
|
+
"logdir": "./log",
|
45
|
+
"workdir": "./run",
|
46
|
+
"outdir": "./output",
|
47
|
+
"model": "model",
|
48
|
+
"experiments": "",
|
49
|
+
"exp_labels": "",
|
50
|
+
"mod_path": "",
|
51
|
+
"obs_path": "",
|
52
|
+
"obs_dataset_type": "ebas_hourly",
|
53
|
+
"station_file": "",
|
54
|
+
"station_radius_deg": 0.5,
|
55
|
+
"station_network": "",
|
56
|
+
"station_suffix": "",
|
57
|
+
"station_type": "concentration",
|
58
|
+
"start_date": "2018-01-01",
|
59
|
+
"end_date": "2018-01-31",
|
60
|
+
"variable": "",
|
61
|
+
"plot_type": "",
|
62
|
+
"model_level": 0,
|
63
|
+
"plot_region": "Globe",
|
64
|
+
"time_average": "mean",
|
65
|
+
"plot_mode": "grouped",
|
66
|
+
"station_plot_group_size": 10,
|
67
|
+
"show_stations": True,
|
68
|
+
"show_min_max": True,
|
69
|
+
"log_y_axis": False,
|
70
|
+
"fix_y_axis": True,
|
71
|
+
"force_full_year": True,
|
72
|
+
"show_station_map": True,
|
73
|
+
"load_station_timeseries_obs": True,
|
74
|
+
"show_station_timeseries_obs": True,
|
75
|
+
"show_station_timeseries_mod": True,
|
76
|
+
"show_station_timeseries_com": True,
|
77
|
+
"save_plot_format": "pdf,png",
|
78
|
+
"save_data_format": "csv",
|
79
|
+
"read_data_format": "nc",
|
80
|
+
"output_base_name": "./output/QLC",
|
81
|
+
"multiprocessing": False,
|
82
|
+
"lazy_load_nc": True,
|
83
|
+
"n_threads": "1",
|
84
|
+
"debug": False,
|
85
|
+
"debug_extended": False
|
86
|
+
}
|
87
|
+
|
88
|
+
for key, value in defaults.items():
|
89
|
+
if key not in config:
|
90
|
+
config[key] = value
|
91
|
+
|
92
|
+
config = merge_global_attributes(config, defaults)
|
93
|
+
return config
|
94
|
+
|
95
|
+
def run_single_config(config_entry, idx, total_configs):
|
96
|
+
try:
|
97
|
+
# Minimal logging setup for subprocesses only
|
98
|
+
if current_process().name != "MainProcess":
|
99
|
+
if not logging.getLogger().hasHandlers():
|
100
|
+
logging.basicConfig(
|
101
|
+
level=logging.INFO,
|
102
|
+
format='[%(asctime)s] %(levelname)s: [%(processName)s] %(message)s',
|
103
|
+
handlers=[logging.StreamHandler(sys.stdout)]
|
104
|
+
)
|
105
|
+
|
106
|
+
logging.info(f"(Process {idx+1}/{total_configs}) Starting configuration '{config_entry.get('name', f'config_{idx+1}')}'...")
|
107
|
+
|
108
|
+
config = load_config_with_defaults(config_entry)
|
109
|
+
validate_paths(config)
|
110
|
+
log_input_availability(config)
|
111
|
+
if not config.get("use_mod", False) and not config.get("use_obs", False):
|
112
|
+
logging.warning("⚠️ Nothing to process: no model or observation input available. Skipping execution.")
|
113
|
+
return
|
114
|
+
|
115
|
+
run_main_processing(config)
|
116
|
+
|
117
|
+
logging.info(f"(Process {idx+1}/{total_configs}) Finished configuration '{config_entry.get('name', f'config_{idx+1}')}'.")
|
118
|
+
except Exception as e:
|
119
|
+
print(f"[ERROR] Failed in run_single_config for config {idx+1}: {e}")
|
120
|
+
traceback.print_exc()
|
121
|
+
|
122
|
+
def run_with_file(file_path):
|
123
|
+
start_time = time.time()
|
124
|
+
print("************************************************************************************************")
|
125
|
+
print(f"Start execution: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(start_time))}")
|
126
|
+
if not os.path.isfile(file_path):
|
127
|
+
print(f"ERROR: Input file '{file_path}' not found.")
|
128
|
+
sys.exit(1)
|
129
|
+
|
130
|
+
with open(file_path, 'r') as f:
|
131
|
+
try:
|
132
|
+
config_data = expand_paths(json.load(f))
|
133
|
+
validate_paths(config_data if isinstance(config_data, dict) else config_data[0])
|
134
|
+
print(json.dumps(config_data, indent=2))
|
135
|
+
except json.JSONDecodeError as e:
|
136
|
+
print(f"ERROR: Failed to parse JSON: {e}")
|
137
|
+
sys.exit(1)
|
138
|
+
|
139
|
+
if isinstance(config_data, list):
|
140
|
+
first_config = config_data[0]
|
141
|
+
else:
|
142
|
+
first_config = config_data
|
143
|
+
|
144
|
+
log_dir = first_config.get("logdir", "~/qlc/log")
|
145
|
+
log_filename = os.path.join(log_dir, f"qlc_{get_timestamp()}.log")
|
146
|
+
full_log_path = os.path.join(os.path.expanduser(log_dir), log_filename)
|
147
|
+
log_level = logging.DEBUG if first_config.get("debug", False) else logging.INFO
|
148
|
+
# setup_logging(log_dir=os.path.dirname(full_log_path), level=log_level)
|
149
|
+
setup_logging(log_dir=log_dir, level=log_level)
|
150
|
+
|
151
|
+
# If the config is a list, loop over multiple configs
|
152
|
+
if isinstance(config_data, list) and len(config_data) == 1:
|
153
|
+
process_single_config(config_data[0], run_single_config)
|
154
|
+
elif isinstance(config_data, list):
|
155
|
+
mp = config_data[0].get("multiprocessing", False)
|
156
|
+
if mp:
|
157
|
+
plugin_mp = try_import_plugin_module("qlc_multiprocessing_plugin")
|
158
|
+
if plugin_mp and hasattr(plugin_mp, "process_multiple_configs_mp"):
|
159
|
+
plugin_mp.process_multiple_configs_mp(config_data, run_single_config)
|
160
|
+
else:
|
161
|
+
print("WARNING: Multiprocessing requested but plugin plugin not found or invalid. Using single config fallback.")
|
162
|
+
process_multiple_configs_sp(config_data, run_single_config)
|
163
|
+
else:
|
164
|
+
process_multiple_configs_sp(config_data, run_single_config)
|
165
|
+
else:
|
166
|
+
process_single_config(config_data, run_single_config)
|
167
|
+
|
168
|
+
end_time = time.time()
|
169
|
+
duration = end_time - start_time
|
170
|
+
logging.info(f"End execution: {time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(end_time))} - Total execution time: {duration:.2f} seconds")
|
171
|
+
logging.info("************************************************************************************************")
|
172
|
+
|
173
|
+
def main():
|
174
|
+
parser = argparse.ArgumentParser(description="Run QLC Python Processor")
|
175
|
+
parser.add_argument("--config", type=str, help="Path to config JSON", default=os.path.expanduser("~/qlc/config/json/qlc_config.json"))
|
176
|
+
args = parser.parse_args()
|
177
|
+
|
178
|
+
if args.config:
|
179
|
+
run_with_file(args.config)
|
180
|
+
else:
|
181
|
+
print(f"ERROR: Please provide an input JSON file using --config option.")
|
182
|
+
sys.exit(1)
|
183
|
+
|
184
|
+
if __name__ == "__main__":
|
185
|
+
main()
|
qlc/cli/qlc_py_main.py
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
import subprocess
|
4
|
+
from datetime import datetime
|
5
|
+
from pathlib import Path
|
6
|
+
|
7
|
+
def main():
|
8
|
+
"""
|
9
|
+
Python entry point for running the main QLC processing script.
|
10
|
+
"""
|
11
|
+
script_name = sys.argv[0]
|
12
|
+
print("________________________________________________________________________________________")
|
13
|
+
print(f"Start {script_name} at {datetime.now()}")
|
14
|
+
print("----------------------------------------------------------------------------------------")
|
15
|
+
|
16
|
+
# --- Change to QLC home directory ---
|
17
|
+
qlc_home = Path.home() / "qlc"
|
18
|
+
if not qlc_home.is_dir():
|
19
|
+
print(f"[ERROR] QLC home directory not found at: {qlc_home}")
|
20
|
+
print("Please run 'qlc-install' to set up the required structure.")
|
21
|
+
sys.exit(1)
|
22
|
+
|
23
|
+
os.chdir(qlc_home)
|
24
|
+
print(f"Changed working directory to: {os.getcwd()}")
|
25
|
+
# ---
|
26
|
+
|
27
|
+
config_path = sys.argv[1] if len(sys.argv) > 1 else str(Path.home() / "qlc" / "config" / "json" / "qlc_config.json")
|
28
|
+
log_dir = qlc_home / "log"
|
29
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
30
|
+
|
31
|
+
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
32
|
+
log_file = log_dir / f"qlc_run_{timestamp}.log"
|
33
|
+
|
34
|
+
print("************************************************************************************************")
|
35
|
+
print(f"Running {script_name} with output logged to {log_file}")
|
36
|
+
|
37
|
+
# The command will use the same Python interpreter that is running this script
|
38
|
+
python_executable = sys.executable
|
39
|
+
command = [
|
40
|
+
python_executable,
|
41
|
+
"-m",
|
42
|
+
"qlc.cli.qlc_main",
|
43
|
+
"--config",
|
44
|
+
config_path,
|
45
|
+
]
|
46
|
+
|
47
|
+
print(f"Executing command: {' '.join(command)}")
|
48
|
+
|
49
|
+
try:
|
50
|
+
with open(log_file, "w") as lf:
|
51
|
+
process = subprocess.Popen(
|
52
|
+
command,
|
53
|
+
stdout=subprocess.PIPE,
|
54
|
+
stderr=subprocess.STDOUT,
|
55
|
+
text=True,
|
56
|
+
bufsize=1,
|
57
|
+
universal_newlines=True,
|
58
|
+
)
|
59
|
+
if process.stdout:
|
60
|
+
for line in process.stdout:
|
61
|
+
print(line, end="")
|
62
|
+
lf.write(line)
|
63
|
+
process.wait()
|
64
|
+
|
65
|
+
except Exception as e:
|
66
|
+
print(f"An error occurred: {e}")
|
67
|
+
|
68
|
+
print("________________________________________________________________________________________")
|
69
|
+
print(f"End {script_name} at {datetime.now()}")
|
70
|
+
print("________________________________________________________________________________________")
|
71
|
+
|
72
|
+
if __name__ == "__main__":
|
73
|
+
main()
|
74
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"name": "CAMS2_35",
|
4
|
+
"logdir": "./log",
|
5
|
+
"workdir": "./run",
|
6
|
+
"output_base_name": "$HOME/qlc/output/GMD",
|
7
|
+
"station_file": "$HOME/qlc/obs/data/ebas_station-locations.csv",
|
8
|
+
"obs_path": "$HOME/qlc/obs/data/ver0d",
|
9
|
+
"obs_dataset_type": "ebas_daily",
|
10
|
+
"start_date": "2018-01-01",
|
11
|
+
"end_date": "2018-12-31",
|
12
|
+
"variable": "SO2,SO4,HNO3,NO3,NH3,NH4",
|
13
|
+
"station_radius_deg": 10.0,
|
14
|
+
"plot_type": "",
|
15
|
+
"plot_region": "EU",
|
16
|
+
"time_average": "daily, weekly, monthly",
|
17
|
+
"station_plot_group_size": 5,
|
18
|
+
"show_stations": false,
|
19
|
+
"show_min_max": true,
|
20
|
+
"log_y_axis": false,
|
21
|
+
"fix_y_axis": true,
|
22
|
+
"show_station_map": true,
|
23
|
+
"load_station_timeseries_obs": true,
|
24
|
+
"show_station_timeseries_obs": true,
|
25
|
+
"show_station_timeseries_mod": false,
|
26
|
+
"show_station_timeseries_com": false,
|
27
|
+
"save_plot_format": "pdf",
|
28
|
+
"save_data_format": "nc",
|
29
|
+
"multiprocessing": true,
|
30
|
+
"n_threads": "20",
|
31
|
+
"debug": false,
|
32
|
+
|
33
|
+
"global_attributes": {
|
34
|
+
"title": "Air pollutants over Europe, SO2,SO4,HNO3,NO3,NH3,NH4",
|
35
|
+
"summary": "Custom summary for netCDF output: Ebas daily observations for selected EU stations.",
|
36
|
+
"author": "Plain & Simple, plain.simple@example.com",
|
37
|
+
"history": "Processed for CAMS (test 1.1)",
|
38
|
+
"Conventions": "CF-1.8"
|
39
|
+
}
|
40
|
+
}
|
41
|
+
]
|
@@ -0,0 +1,237 @@
|
|
1
|
+
[
|
2
|
+
{
|
3
|
+
"name": "CAMS2_35",
|
4
|
+
"logdir": "./log",
|
5
|
+
"workdir": "./run",
|
6
|
+
"output_base_name": "$HOME/qlc/output/GMD",
|
7
|
+
"station_file": "$HOME/qlc/obs/data/castnet_station-locations.csv",
|
8
|
+
"obs_path": "$HOME/qlc/obs",
|
9
|
+
"obs_dataset_type": "AMoN",
|
10
|
+
"start_date": "2018-01-01",
|
11
|
+
"end_date": "2018-12-31",
|
12
|
+
"variable": "NH3",
|
13
|
+
"station_radius_deg": 10.0,
|
14
|
+
"plot_type": "",
|
15
|
+
"plot_region": "US",
|
16
|
+
"time_average": "weekly, monthly",
|
17
|
+
"station_plot_group_size": 5,
|
18
|
+
"show_stations": false,
|
19
|
+
"show_min_max": true,
|
20
|
+
"log_y_axis": false,
|
21
|
+
"fix_y_axis": true,
|
22
|
+
"show_station_map": true,
|
23
|
+
"load_station_timeseries_obs": true,
|
24
|
+
"show_station_timeseries_obs": true,
|
25
|
+
"show_station_timeseries_mod": false,
|
26
|
+
"show_station_timeseries_com": false,
|
27
|
+
"save_plot_format": "pdf",
|
28
|
+
"save_data_format": "nc",
|
29
|
+
"multiprocessing": true,
|
30
|
+
"n_threads": "20",
|
31
|
+
"debug": false,
|
32
|
+
|
33
|
+
"global_attributes": {
|
34
|
+
"title": "Air pollutants over US, NH3",
|
35
|
+
"summary": "AMoN bi-weekly observations for selected US stations.",
|
36
|
+
"author": "Swen Metzger, sm@researchconcepts.io",
|
37
|
+
"history": "Processed for CAMS2_35bis (dev 1.2)",
|
38
|
+
"Conventions": "CF-1.8"
|
39
|
+
}
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"name": "CAMS2_35",
|
43
|
+
"logdir": "./log",
|
44
|
+
"workdir": "./run",
|
45
|
+
"output_base_name": "$HOME/qlc/output/GMD",
|
46
|
+
"station_file": "$HOME/qlc/obs/data/castnet_station-locations.csv",
|
47
|
+
"obs_path": "$HOME/qlc/obs/data/ver0d",
|
48
|
+
"obs_dataset_type": "airnow",
|
49
|
+
"start_date": "2018-01-01",
|
50
|
+
"end_date": "2018-12-31",
|
51
|
+
"variable": "SO2",
|
52
|
+
"station_radius_deg": 10.0,
|
53
|
+
"plot_type": "",
|
54
|
+
"plot_region": "US",
|
55
|
+
"time_average": "weekly, monthly",
|
56
|
+
"station_plot_group_size": 5,
|
57
|
+
"show_stations": false,
|
58
|
+
"show_min_max": true,
|
59
|
+
"log_y_axis": false,
|
60
|
+
"fix_y_axis": true,
|
61
|
+
"show_station_map": true,
|
62
|
+
"load_station_timeseries_obs": true,
|
63
|
+
"show_station_timeseries_obs": true,
|
64
|
+
"show_station_timeseries_mod": false,
|
65
|
+
"show_station_timeseries_com": false,
|
66
|
+
"save_plot_format": "pdf",
|
67
|
+
"save_data_format": "nc",
|
68
|
+
"multiprocessing": true,
|
69
|
+
"n_threads": "20",
|
70
|
+
"debug": false,
|
71
|
+
|
72
|
+
"global_attributes": {
|
73
|
+
"title": "Air pollutants over US, SO2",
|
74
|
+
"summary": "Airnow bi-weekly observations for selected US stations.",
|
75
|
+
"author": "Swen Metzger, sm@researchconcepts.io",
|
76
|
+
"history": "Processed for CAMS2_35bis (dev 1.2)",
|
77
|
+
"Conventions": "CF-1.8"
|
78
|
+
}
|
79
|
+
},
|
80
|
+
{
|
81
|
+
"name": "CAMS2_35",
|
82
|
+
"logdir": "./log",
|
83
|
+
"workdir": "./run",
|
84
|
+
"output_base_name": "$HOME/qlc/output/GMD",
|
85
|
+
"station_file": "$HOME/qlc/obs/data/Asia_station_list.csv",
|
86
|
+
"obs_path": "$HOME/qlc/obs/data/ver0d",
|
87
|
+
"obs_dataset_type": "china_aq",
|
88
|
+
"start_date": "2018-01-01",
|
89
|
+
"end_date": "2018-12-31",
|
90
|
+
"variable": "SO2",
|
91
|
+
"station_radius_deg": 20.0,
|
92
|
+
"plot_type": "",
|
93
|
+
"plot_region": "Asia",
|
94
|
+
"time_average": "weekly, monthly",
|
95
|
+
"station_plot_group_size": 5,
|
96
|
+
"show_stations": false,
|
97
|
+
"show_min_max": true,
|
98
|
+
"log_y_axis": false,
|
99
|
+
"fix_y_axis": true,
|
100
|
+
"show_station_map": true,
|
101
|
+
"load_station_timeseries_obs": true,
|
102
|
+
"show_station_timeseries_obs": true,
|
103
|
+
"show_station_timeseries_mod": false,
|
104
|
+
"show_station_timeseries_com": false,
|
105
|
+
"save_plot_format": "pdf",
|
106
|
+
"save_data_format": "nc",
|
107
|
+
"multiprocessing": true,
|
108
|
+
"n_threads": "20",
|
109
|
+
"debug": false,
|
110
|
+
"debug_extended": false,
|
111
|
+
|
112
|
+
"global_attributes": {
|
113
|
+
"title": "Air pollutants over Asia, SO2",
|
114
|
+
"summary": "China AQ monthly observations for selected Asia stations.",
|
115
|
+
"author": "Swen Metzger, sm@researchconcepts.io",
|
116
|
+
"history": "Processed for CAMS2_35bis (dev 1.2)",
|
117
|
+
"Conventions": "CF-1.8"
|
118
|
+
}
|
119
|
+
},
|
120
|
+
{
|
121
|
+
"name": "CAMS2_35",
|
122
|
+
"logdir": "./log",
|
123
|
+
"workdir": "./run",
|
124
|
+
"output_base_name": "$HOME/qlc/output/GMD",
|
125
|
+
"station_file": "$HOME/qlc/obs/data/ebas_station-locations.csv",
|
126
|
+
"obs_path": "$HOME/qlc/obs/data/ver0d",
|
127
|
+
"obs_dataset_type": "ebas_daily",
|
128
|
+
"start_date": "2018-01-01",
|
129
|
+
"end_date": "2018-12-31",
|
130
|
+
"variable": "SO2,SO4,HNO3,NO3,NH3,NH4",
|
131
|
+
"station_radius_deg": 10.0,
|
132
|
+
"plot_type": "",
|
133
|
+
"plot_region": "EU",
|
134
|
+
"time_average": "weekly, monthly",
|
135
|
+
"station_plot_group_size": 5,
|
136
|
+
"show_stations": false,
|
137
|
+
"show_min_max": true,
|
138
|
+
"log_y_axis": false,
|
139
|
+
"fix_y_axis": true,
|
140
|
+
"show_station_map": true,
|
141
|
+
"load_station_timeseries_obs": true,
|
142
|
+
"show_station_timeseries_obs": true,
|
143
|
+
"show_station_timeseries_mod": false,
|
144
|
+
"show_station_timeseries_com": false,
|
145
|
+
"save_plot_format": "pdf",
|
146
|
+
"save_data_format": "nc",
|
147
|
+
"multiprocessing": true,
|
148
|
+
"n_threads": "20",
|
149
|
+
"debug": false,
|
150
|
+
|
151
|
+
"global_attributes": {
|
152
|
+
"title": "Air pollutants over Europe, SO2,SO4,HNO3,NO3,NH3,NH4",
|
153
|
+
"summary": "Ebas daily observations for selected EU stations.",
|
154
|
+
"author": "Swen Metzger, sm@researchconcepts.io",
|
155
|
+
"history": "Processed for CAMS (dev 1.2)",
|
156
|
+
"Conventions": "CF-1.8"
|
157
|
+
}
|
158
|
+
},
|
159
|
+
{
|
160
|
+
"name": "CAMS2_35",
|
161
|
+
"logdir": "./log",
|
162
|
+
"workdir": "./run",
|
163
|
+
"output_base_name": "$HOME/qlc/output/GMD",
|
164
|
+
"station_file": "$HOME/qlc/obs/data/castnet_station-locations.csv",
|
165
|
+
"obs_path": "$HOME/qlc/obs",
|
166
|
+
"obs_dataset_type": "castnet",
|
167
|
+
"start_date": "2018-01-01",
|
168
|
+
"end_date": "2018-12-31",
|
169
|
+
"variable": "SO2,SO4,HNO3,NO3,NH4,NH3",
|
170
|
+
"station_radius_deg": 10.0,
|
171
|
+
"plot_type": "",
|
172
|
+
"plot_region": "US",
|
173
|
+
"time_average": "weekly, monthly",
|
174
|
+
"station_plot_group_size": 5,
|
175
|
+
"show_stations": false,
|
176
|
+
"show_min_max": true,
|
177
|
+
"log_y_axis": false,
|
178
|
+
"fix_y_axis": true,
|
179
|
+
"show_station_map": true,
|
180
|
+
"load_station_timeseries_obs": true,
|
181
|
+
"show_station_timeseries_obs": true,
|
182
|
+
"show_station_timeseries_mod": false,
|
183
|
+
"show_station_timeseries_com": false,
|
184
|
+
"save_plot_format": "pdf",
|
185
|
+
"save_data_format": "nc",
|
186
|
+
"multiprocessing": true,
|
187
|
+
"n_threads": "20",
|
188
|
+
"debug": false,
|
189
|
+
|
190
|
+
"global_attributes": {
|
191
|
+
"title": "Air pollutants over US, SO2,SO4,HNO3,NO3,NH4,NH3",
|
192
|
+
"summary": "CASTNET weekly observations for selected US stations.",
|
193
|
+
"author": "Swen Metzger, sm@researchconcepts.io",
|
194
|
+
"history": "Processed for CAMS2_35bis (dev 1.2)",
|
195
|
+
"Conventions": "CF-1.8"
|
196
|
+
}
|
197
|
+
},
|
198
|
+
{
|
199
|
+
"name": "CAMS2_35",
|
200
|
+
"logdir": "./log",
|
201
|
+
"workdir": "./run",
|
202
|
+
"output_base_name": "$HOME/qlc/output/GMD",
|
203
|
+
"station_file": "$HOME/qlc/obs/data/Asia_station_list.csv",
|
204
|
+
"obs_path": "$HOME/qlc/obs",
|
205
|
+
"obs_dataset_type": "NNDMN",
|
206
|
+
"start_date": "2018-01-01",
|
207
|
+
"end_date": "2018-12-31",
|
208
|
+
"variable": "HNO3,NO3,NH4,NH3",
|
209
|
+
"station_radius_deg": 50.0,
|
210
|
+
"plot_type": "",
|
211
|
+
"plot_region": "Asia",
|
212
|
+
"time_average": "weekly, monthly",
|
213
|
+
"station_plot_group_size": 5,
|
214
|
+
"show_stations": false,
|
215
|
+
"show_min_max": true,
|
216
|
+
"log_y_axis": false,
|
217
|
+
"fix_y_axis": true,
|
218
|
+
"show_station_map": true,
|
219
|
+
"load_station_timeseries_obs": true,
|
220
|
+
"show_station_timeseries_obs": true,
|
221
|
+
"show_station_timeseries_mod": false,
|
222
|
+
"show_station_timeseries_com": false,
|
223
|
+
"save_plot_format": "pdf",
|
224
|
+
"save_data_format": "nc",
|
225
|
+
"multiprocessing": true,
|
226
|
+
"n_threads": "20",
|
227
|
+
"debug": false,
|
228
|
+
|
229
|
+
"global_attributes": {
|
230
|
+
"title": "Air pollutants over Asia, HNO3,NO3,NH4,NH3",
|
231
|
+
"summary": "NNDMN monthly observations for selected Asia stations.",
|
232
|
+
"author": "Swen Metzger, sm@researchconcepts.io",
|
233
|
+
"history": "Processed for CAMS2_35bis (dev 1.2)",
|
234
|
+
"Conventions": "CF-1.8"
|
235
|
+
}
|
236
|
+
}
|
237
|
+
]
|