lstosa 0.10.13__py3-none-any.whl → 0.10.15__py3-none-any.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.
- {lstosa-0.10.13.dist-info → lstosa-0.10.15.dist-info}/METADATA +1 -1
- {lstosa-0.10.13.dist-info → lstosa-0.10.15.dist-info}/RECORD +17 -16
- {lstosa-0.10.13.dist-info → lstosa-0.10.15.dist-info}/WHEEL +1 -1
- {lstosa-0.10.13.dist-info → lstosa-0.10.15.dist-info}/entry_points.txt +1 -0
- osa/_version.py +2 -2
- osa/configs/sequencer.cfg +5 -1
- osa/job.py +17 -2
- osa/scripts/gain_selection.py +386 -188
- osa/scripts/gainsel_webmaker.py +157 -0
- osa/scripts/reprocessing.py +7 -2
- osa/scripts/sequencer.py +47 -3
- osa/scripts/sequencer_webmaker.py +4 -4
- osa/scripts/tests/test_osa_scripts.py +27 -0
- osa/tests/test_jobs.py +9 -3
- osa/utils/cliopts.py +8 -0
- {lstosa-0.10.13.dist-info → lstosa-0.10.15.dist-info}/LICENSE +0 -0
- {lstosa-0.10.13.dist-info → lstosa-0.10.15.dist-info}/top_level.txt +0 -0
osa/scripts/gain_selection.py
CHANGED
|
@@ -1,30 +1,34 @@
|
|
|
1
1
|
"""Script to run the gain selection over a list of dates."""
|
|
2
2
|
import logging
|
|
3
3
|
import re
|
|
4
|
-
import shutil
|
|
5
4
|
import glob
|
|
6
5
|
import pandas as pd
|
|
7
6
|
import subprocess as sp
|
|
8
7
|
from pathlib import Path
|
|
9
8
|
from textwrap import dedent
|
|
10
|
-
from io import StringIO
|
|
11
9
|
import argparse
|
|
10
|
+
import sys
|
|
12
11
|
|
|
13
12
|
from astropy.table import Table
|
|
14
|
-
from lstchain.paths import
|
|
13
|
+
from lstchain.paths import parse_r0_filename
|
|
14
|
+
from datetime import datetime
|
|
15
15
|
|
|
16
16
|
from osa.scripts.reprocessing import get_list_of_dates, check_job_status_and_wait
|
|
17
|
-
from osa.utils.utils import wait_for_daytime
|
|
17
|
+
from osa.utils.utils import wait_for_daytime, date_to_dir, date_to_iso
|
|
18
18
|
from osa.utils.logging import myLogger
|
|
19
|
-
from osa.
|
|
19
|
+
from osa.utils.iofile import append_to_file
|
|
20
|
+
from osa.utils.cliopts import valid_date
|
|
21
|
+
from osa.job import get_sacct_output, run_sacct, job_finished_in_timeout
|
|
20
22
|
from osa.configs.config import cfg
|
|
21
23
|
from osa.paths import DEFAULT_CFG
|
|
24
|
+
from osa.nightsummary.nightsummary import run_summary_table
|
|
25
|
+
|
|
22
26
|
|
|
23
27
|
log = myLogger(logging.getLogger(__name__))
|
|
24
28
|
|
|
25
29
|
PATH = "PATH=/fefs/aswg/software/offline_dvr/bin:$PATH"
|
|
26
30
|
|
|
27
|
-
parser = argparse.ArgumentParser(
|
|
31
|
+
parser = argparse.ArgumentParser()
|
|
28
32
|
parser.add_argument(
|
|
29
33
|
"--check",
|
|
30
34
|
action="store_true",
|
|
@@ -49,22 +53,16 @@ parser.add_argument(
|
|
|
49
53
|
"-d",
|
|
50
54
|
"--date",
|
|
51
55
|
default=None,
|
|
52
|
-
type=
|
|
53
|
-
help="Night to apply the gain selection",
|
|
56
|
+
type=valid_date,
|
|
57
|
+
help="Night to apply the gain selection in YYYY-MM-DD format",
|
|
54
58
|
)
|
|
55
59
|
parser.add_argument(
|
|
56
60
|
"-l",
|
|
57
61
|
"--dates-file",
|
|
58
62
|
default=None,
|
|
59
|
-
help="List of dates to apply the gain selection"
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"-o",
|
|
63
|
-
"--output-basedir",
|
|
64
|
-
type=Path,
|
|
65
|
-
default=Path("/fefs/aswg/data/real/R0G"),
|
|
66
|
-
help="Output directory of the gain selected files. Default is /fefs/aswg/data/real/R0G."
|
|
67
|
-
)
|
|
63
|
+
help="List of dates to apply the gain selection. The input file should list"
|
|
64
|
+
"the dates in the format YYYY-MM-DD, one date per line.",
|
|
65
|
+
)
|
|
68
66
|
parser.add_argument(
|
|
69
67
|
"-s",
|
|
70
68
|
"--start-time",
|
|
@@ -79,64 +77,211 @@ parser.add_argument(
|
|
|
79
77
|
default=18,
|
|
80
78
|
help="Time to stop gain selection in HH format. Default is 18.",
|
|
81
79
|
)
|
|
80
|
+
parser.add_argument(
|
|
81
|
+
"-t",
|
|
82
|
+
"--tool",
|
|
83
|
+
type=str,
|
|
84
|
+
default=None,
|
|
85
|
+
help="Choose tool to apply the gain selection regardless the date. Possible options are: lst_dvr (by default used for dates "
|
|
86
|
+
"previous to 2023-12-05) and lstchain_r0_to_r0g (by default used for dates later than 2023-12-05).",
|
|
87
|
+
)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"--simulate",
|
|
90
|
+
action="store_true",
|
|
91
|
+
default=False,
|
|
92
|
+
help="Simulate launching of the gain selection script. Dry run.",
|
|
93
|
+
)
|
|
94
|
+
parser.add_argument(
|
|
95
|
+
"-v",
|
|
96
|
+
"--verbose",
|
|
97
|
+
action="store_true",
|
|
98
|
+
default=False,
|
|
99
|
+
help="Activate debugging mode.",
|
|
100
|
+
)
|
|
82
101
|
|
|
83
102
|
def get_sbatch_script(
|
|
84
|
-
run_id
|
|
103
|
+
run_id: str,
|
|
104
|
+
subrun: str,
|
|
105
|
+
input_file: Path,
|
|
106
|
+
output_dir: Path,
|
|
107
|
+
log_dir: Path,
|
|
108
|
+
log_file: Path,
|
|
109
|
+
ref_time: int,
|
|
110
|
+
ref_counter: int,
|
|
111
|
+
module: int,
|
|
112
|
+
ref_source: str,
|
|
113
|
+
tool: str
|
|
85
114
|
):
|
|
86
115
|
"""Build the sbatch job pilot script for running the gain selection."""
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
mem_per_job = cfg.get("SLURM", "MEMSIZE_GAINSEL")
|
|
117
|
+
sbatch_script = dedent(
|
|
89
118
|
f"""\
|
|
90
119
|
#!/bin/bash
|
|
91
120
|
|
|
92
121
|
#SBATCH -D {log_dir}
|
|
93
122
|
#SBATCH -o "gain_selection_{run_id:05d}_{subrun:04d}_%j.log"
|
|
94
123
|
#SBATCH --job-name "gain_selection_{run_id:05d}"
|
|
95
|
-
#SBATCH --export {PATH}
|
|
96
124
|
#SBATCH --partition=short,long
|
|
125
|
+
#SBATCH --mem={mem_per_job}
|
|
126
|
+
"""
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
if tool == "lst_dvr":
|
|
130
|
+
sbatch_script += dedent(
|
|
131
|
+
f"""
|
|
132
|
+
#SBATCH --export {PATH}
|
|
97
133
|
|
|
98
134
|
lst_dvr {input_file} {output_dir} {ref_time} {ref_counter} {module} {ref_source}
|
|
99
135
|
"""
|
|
100
136
|
)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
137
|
+
|
|
138
|
+
elif tool == "lstchain_r0_to_r0g":
|
|
139
|
+
cmd = f"lstchain_r0_to_r0g --R0-file={input_file} --output-dir={output_dir} --log={log_file}"
|
|
140
|
+
if not cfg.getboolean("lstchain", "use_ff_heuristic_gain_selection"):
|
|
141
|
+
cmd += " --no-flatfield-heuristic"
|
|
142
|
+
sbatch_script += dedent(cmd)
|
|
105
143
|
|
|
106
|
-
|
|
107
|
-
#SBATCH -o "gain_selection_{run_id:05d}_{subrun:04d}_%j.log"
|
|
108
|
-
#SBATCH --job-name "gain_selection_{run_id:05d}"
|
|
109
|
-
#SBATCH --mem=40GB
|
|
110
|
-
#SBATCH --partition=short,long
|
|
144
|
+
return sbatch_script
|
|
111
145
|
|
|
112
|
-
lstchain_r0_to_r0g --R0-file={input_file} --output-dir={output_dir} --log={log_file} --no-flatfield-heuristic
|
|
113
|
-
"""
|
|
114
|
-
)
|
|
115
146
|
|
|
116
|
-
def
|
|
147
|
+
def launch_gainsel_for_data_run(
|
|
148
|
+
date: datetime, run: Table, output_dir: Path, r0_dir: Path, log_dir: Path, tool: str, simulate: bool = False
|
|
149
|
+
):
|
|
150
|
+
"""
|
|
151
|
+
Create the gain selection sbatch script and launch it for a given run.
|
|
152
|
+
|
|
153
|
+
Runs from before 20231205 without UCTS or TIB info are directly copied to the final directory.
|
|
154
|
+
Subruns that do not have four streams are also directly copied.
|
|
155
|
+
"""
|
|
156
|
+
run_id = run["run_id"]
|
|
157
|
+
ref_time = run["dragon_reference_time"]
|
|
158
|
+
ref_counter = run["dragon_reference_counter"]
|
|
159
|
+
module = run["dragon_reference_module_index"]
|
|
160
|
+
ref_source = run["dragon_reference_source"].upper()
|
|
161
|
+
|
|
162
|
+
files = glob.glob(f"{r0_dir}/LST-1.?.Run{run_id:05d}.????.fits.fz")
|
|
163
|
+
subrun_numbers = [int(file[-12:-8]) for file in files]
|
|
164
|
+
|
|
165
|
+
if tool == "lst_dvr" and ref_source not in ["UCTS", "TIB"]:
|
|
166
|
+
input_files = r0_dir.glob(f"LST-1.?.Run{run_id:05d}.????.fits.fz")
|
|
167
|
+
|
|
168
|
+
if is_run_already_copied(date, run_id):
|
|
169
|
+
log.info(f"The R0 files corresponding to run {run_id} have already been copied to the R0G directory.")
|
|
170
|
+
else:
|
|
171
|
+
if not simulate:
|
|
172
|
+
for file in input_files:
|
|
173
|
+
log.debug(
|
|
174
|
+
f"Run {run_id} does not have UCTS or TIB info, so gain selection cannot"
|
|
175
|
+
f"be applied. Copying directly the R0 files to {output_dir}."
|
|
176
|
+
)
|
|
177
|
+
sp.run(["cp", file, output_dir])
|
|
178
|
+
|
|
179
|
+
else:
|
|
180
|
+
log.info(
|
|
181
|
+
f"Run {run_id} does not have UCTS or TIB info, so gain selection cannot"
|
|
182
|
+
f"be applied. Simulate copy of the R0 files directly to {output_dir}."
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
else:
|
|
186
|
+
n_subruns = max(subrun_numbers)
|
|
187
|
+
|
|
188
|
+
for subrun in range(n_subruns + 1):
|
|
189
|
+
|
|
190
|
+
r0_files = glob.glob(f"{r0_dir}/LST-1.?.Run{run_id:05d}.{subrun:04d}.fits.fz")
|
|
191
|
+
|
|
192
|
+
if len(r0_files) != 4:
|
|
193
|
+
if not simulate and not is_run_already_copied(date, run_id):
|
|
194
|
+
log.debug(f"Run {run_id:05d}.{subrun:04d} does not have 4 streams of R0 files, so gain"
|
|
195
|
+
f"selection cannot be applied. Copying directly the R0 files to {output_dir}.")
|
|
196
|
+
for file in r0_files:
|
|
197
|
+
sp.run(["cp", file, output_dir])
|
|
198
|
+
elif is_run_already_copied(date, run_id):
|
|
199
|
+
log.debug(f"Run {run_id:05d}.{subrun:04d} does not have 4 streams of R0 files. The R0 files"
|
|
200
|
+
f"have already been copied to {output_dir}.")
|
|
201
|
+
elif simulate:
|
|
202
|
+
log.debug(f"Run {run_id:05d}.{subrun:04d} does not have 4 streams of R0 files, so gain"
|
|
203
|
+
f"selection cannot be applied. Simulate copy of the R0 files directly to {output_dir}.")
|
|
204
|
+
|
|
205
|
+
else:
|
|
206
|
+
history_file = log_dir / f"gain_selection_{run_id:05d}.{subrun:04d}.history"
|
|
207
|
+
if history_file.exists():
|
|
208
|
+
if not simulate:
|
|
209
|
+
update_history_file(run_id, subrun, log_dir, history_file)
|
|
210
|
+
|
|
211
|
+
if history_file.read_text() == "": # history_file is empty
|
|
212
|
+
log.debug(f"Gain selection is still running for run {run_id:05d}.{subrun:04d}")
|
|
213
|
+
continue
|
|
214
|
+
else:
|
|
215
|
+
gainsel_rc = history_file.read_text().splitlines()[-1][-1]
|
|
216
|
+
if gainsel_rc == "1":
|
|
217
|
+
job_id = get_last_job_id(run_id, subrun, log_dir)
|
|
218
|
+
if job_finished_in_timeout(job_id) and not simulate:
|
|
219
|
+
# Relaunch the job that finished in TIMEOUT
|
|
220
|
+
job_file = log_dir / f"gain_selection_{run_id:05d}.{subrun:04d}.sh"
|
|
221
|
+
sp.run(["sbatch", job_file], stdout=sp.PIPE, stderr=sp.STDOUT, check=True)
|
|
222
|
+
else:
|
|
223
|
+
log.warning(f"Gain selection failed for run {run_id:05d}.{subrun:04d}")
|
|
224
|
+
elif gainsel_rc == "0":
|
|
225
|
+
log.debug(f"Gain selection finished successfully for run {run_id:05d}.{subrun:04d},"
|
|
226
|
+
"no additional jobs will be submitted for this subrun.")
|
|
227
|
+
else:
|
|
228
|
+
log.debug("Creating and launching the gain selection sbatch script for subrun {run_id:05d}.{subrun:04d}")
|
|
229
|
+
if not simulate:
|
|
230
|
+
log_file = log_dir / f"r0_to_r0g_{run_id:05d}.{subrun:04d}.log"
|
|
231
|
+
job_file = log_dir / f"gain_selection_{run_id:05d}.{subrun:04d}.sh"
|
|
232
|
+
r0_files.sort()
|
|
233
|
+
with open(job_file, "w") as f:
|
|
234
|
+
f.write(
|
|
235
|
+
get_sbatch_script(
|
|
236
|
+
run_id,
|
|
237
|
+
subrun,
|
|
238
|
+
r0_files[0],
|
|
239
|
+
output_dir,
|
|
240
|
+
log_dir,
|
|
241
|
+
log_file,
|
|
242
|
+
ref_time,
|
|
243
|
+
ref_counter,
|
|
244
|
+
module,
|
|
245
|
+
ref_source,
|
|
246
|
+
tool,
|
|
247
|
+
)
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
#submit job
|
|
251
|
+
history_file.touch()
|
|
252
|
+
sp.run(["sbatch", job_file], stdout=sp.PIPE, stderr=sp.STDOUT, check=True)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def apply_gain_selection(date: datetime, start: int, end: int, tool: str = None, no_queue_check: bool = False, simulate: bool = False):
|
|
117
256
|
"""
|
|
118
257
|
Submit the jobs to apply the gain selection to the data for a given date
|
|
119
258
|
on a subrun-by-subrun basis.
|
|
120
259
|
"""
|
|
121
260
|
|
|
122
|
-
if
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
261
|
+
if not tool:
|
|
262
|
+
if date_to_dir(date) < "20231205":
|
|
263
|
+
tool = "lst_dvr"
|
|
264
|
+
else:
|
|
265
|
+
tool = "lstchain_r0_to_r0g"
|
|
266
|
+
|
|
267
|
+
summary_table = run_summary_table(date)
|
|
268
|
+
|
|
269
|
+
if len(summary_table) == 0:
|
|
270
|
+
log.warning(f"No runs are found in the run summary of {date_to_iso(date)}. Nothing to do. Exiting.")
|
|
271
|
+
sys.exit(0)
|
|
126
272
|
|
|
127
|
-
run_summary_dir = Path("/fefs/aswg/data/real/monitoring/RunSummary")
|
|
128
|
-
run_summary_file = run_summary_dir / f"RunSummary_{date}.ecsv"
|
|
129
|
-
summary_table = Table.read(run_summary_file)
|
|
130
273
|
# Apply gain selection only to DATA runs
|
|
131
274
|
data_runs = summary_table[summary_table["run_type"] == "DATA"]
|
|
132
275
|
log.info(f"Found {len(data_runs)} DATA runs to which apply the gain selection")
|
|
133
276
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
277
|
+
base_dir = Path(cfg.get("LST1", "BASE"))
|
|
278
|
+
date_str = date_to_dir(date)
|
|
279
|
+
r0_dir = base_dir / "R0" / date_str
|
|
280
|
+
output_dir = base_dir / f"R0G/{date_str}"
|
|
281
|
+
log_dir = base_dir / f"R0G/log/{date_str}"
|
|
282
|
+
if not simulate:
|
|
283
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
284
|
+
log_dir.mkdir(parents=True, exist_ok=True)
|
|
140
285
|
|
|
141
286
|
for run in data_runs:
|
|
142
287
|
if not no_queue_check:
|
|
@@ -146,171 +291,203 @@ def apply_gain_selection(date: str, start: int, end: int, output_basedir: Path =
|
|
|
146
291
|
# Avoid running jobs while it is still night time
|
|
147
292
|
wait_for_daytime(start, end)
|
|
148
293
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
files = glob.glob(f"{r0_dir}/LST-1.?.Run{run_id:05d}.????.fits.fz")
|
|
156
|
-
subrun_numbers = [int(file[-12:-8]) for file in files]
|
|
157
|
-
input_files = []
|
|
158
|
-
|
|
159
|
-
if date < "20231205" and ref_source not in ["UCTS", "TIB"]:
|
|
160
|
-
input_files = r0_dir.glob(f"LST-1.?.Run{run_id:05d}.????.fits.fz")
|
|
161
|
-
log.info(
|
|
162
|
-
f"Run {run_id} does not have UCTS or TIB info, so gain selection cannot"
|
|
163
|
-
f"be applied. Copying directly the R0 files to {output_dir}."
|
|
164
|
-
)
|
|
165
|
-
for file in input_files:
|
|
166
|
-
sp.run(["cp", file, output_dir])
|
|
294
|
+
if not is_closed(date, run["run_id"]):
|
|
295
|
+
launch_gainsel_for_data_run(date, run, output_dir, r0_dir, log_dir, tool, simulate)
|
|
296
|
+
|
|
297
|
+
calib_runs = summary_table[summary_table["run_type"] != "DATA"]
|
|
298
|
+
log.info(f"Found {len(calib_runs)} NO-DATA runs")
|
|
167
299
|
|
|
300
|
+
for run in calib_runs:
|
|
301
|
+
run_id = run["run_id"]
|
|
302
|
+
|
|
303
|
+
if is_run_already_copied(date, run_id):
|
|
304
|
+
log.info(f"The R0 files corresponding to run {run_id:05d} have already been copied, nothing to do.")
|
|
168
305
|
else:
|
|
169
|
-
|
|
306
|
+
log.info(f"Copying R0 files corresponding to run {run_id} directly to {output_dir}")
|
|
307
|
+
if not simulate:
|
|
308
|
+
# Avoid copying files while it is still night time
|
|
309
|
+
wait_for_daytime(start, end)
|
|
170
310
|
|
|
171
|
-
|
|
172
|
-
new_files = glob.glob(f"{r0_dir}/LST-1.?.Run{run_id:05d}.{subrun:04d}.fits.fz")
|
|
311
|
+
r0_files = r0_dir.glob(f"LST-1.?.Run{run_id:05d}.????.fits.fz")
|
|
173
312
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
f"selection cannot be applied. Copying directly the R0 files to {output_dir}."
|
|
177
|
-
)
|
|
178
|
-
for file in new_files:
|
|
179
|
-
sp.run(["cp", file, output_dir])
|
|
313
|
+
for file in r0_files:
|
|
314
|
+
sp.run(["cp", file, output_dir])
|
|
180
315
|
|
|
181
|
-
else:
|
|
182
|
-
new_files.sort()
|
|
183
|
-
input_files.append(new_files[0])
|
|
184
|
-
|
|
185
|
-
log.info("Creating and launching the sbatch scripts for the rest of the runs to apply gain selection")
|
|
186
|
-
for file in input_files:
|
|
187
|
-
run_info = run_info_from_filename(file)
|
|
188
|
-
job_file = log_dir / f"gain_selection_{run_info.run:05d}.{run_info.subrun:04d}.sh"
|
|
189
|
-
with open(job_file, "w") as f:
|
|
190
|
-
f.write(
|
|
191
|
-
get_sbatch_script(
|
|
192
|
-
run_id,
|
|
193
|
-
run_info.subrun,
|
|
194
|
-
file,
|
|
195
|
-
output_dir,
|
|
196
|
-
log_dir,
|
|
197
|
-
log_file,
|
|
198
|
-
ref_time,
|
|
199
|
-
ref_counter,
|
|
200
|
-
module,
|
|
201
|
-
ref_source,
|
|
202
|
-
script,
|
|
203
|
-
)
|
|
204
|
-
)
|
|
205
|
-
sp.run(["sbatch", job_file], check=True)
|
|
206
316
|
|
|
207
|
-
|
|
208
|
-
|
|
317
|
+
def get_last_job_id(run_id: str, subrun: str, log_dir: Path) -> int:
|
|
318
|
+
"""Get job id of the last gain selection job that was launched for a given subrun."""
|
|
319
|
+
filenames = glob.glob(f"{log_dir}/gain_selection_{run_id:05d}_{subrun:04d}_*.log")
|
|
320
|
+
if filenames:
|
|
321
|
+
match = re.search(f'gain_selection_{run_id:05d}_{subrun:04d}_(\d+).log', sorted(filenames)[-1])
|
|
322
|
+
job_id = match.group(1)
|
|
323
|
+
return job_id
|
|
209
324
|
|
|
210
|
-
for run in calib_runs:
|
|
211
|
-
run_id = run["run_id"]
|
|
212
|
-
log.info(f"Copying R0 files corresponding to run {run_id} directly to {output_dir}")
|
|
213
|
-
# Avoid copying files while it is still night time
|
|
214
|
-
wait_for_daytime(start, end)
|
|
215
325
|
|
|
216
|
-
|
|
217
|
-
|
|
326
|
+
def update_history_file(run_id: str, subrun: str, log_dir: Path, history_file: Path):
|
|
327
|
+
"""
|
|
328
|
+
Update the gain selection history file with the result
|
|
329
|
+
of the last job launched for a given subrun.
|
|
330
|
+
"""
|
|
331
|
+
job_id = get_last_job_id(run_id, subrun, log_dir)
|
|
332
|
+
if not job_id:
|
|
333
|
+
log.debug(f"Cannot find a job_id for the run {run_id:05d}.{subrun:04d}")
|
|
334
|
+
else:
|
|
335
|
+
job_status = get_sacct_output(run_sacct(job_id=job_id))["State"]
|
|
336
|
+
if job_status.item() in ["RUNNING", "PENDING"]:
|
|
337
|
+
log.info(f"Job {job_id} is still running.")
|
|
338
|
+
return
|
|
339
|
+
|
|
340
|
+
elif job_status.item() == "COMPLETED":
|
|
341
|
+
log.debug(f"Job {job_id} finished successfully, updating history file.")
|
|
342
|
+
string_to_write = (
|
|
343
|
+
f"{run_id:05d}.{subrun:04d} gain_selection 0\n"
|
|
344
|
+
)
|
|
345
|
+
append_to_file(history_file, string_to_write)
|
|
346
|
+
|
|
347
|
+
else:
|
|
348
|
+
log.info(f"Job {job_id} failed, updating history file.")
|
|
349
|
+
string_to_write = (
|
|
350
|
+
f"{run_id:05d}.{subrun:04d} gain_selection 1\n"
|
|
351
|
+
)
|
|
352
|
+
append_to_file(history_file, string_to_write)
|
|
218
353
|
|
|
219
|
-
for file in r0_files:
|
|
220
|
-
sp.run(["cp", file, output_dir])
|
|
221
354
|
|
|
222
|
-
def
|
|
223
|
-
"""
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
355
|
+
def is_run_already_copied(date: datetime, run_id: int) -> bool:
|
|
356
|
+
"""Check if the R0 files of a given run have already been copied to the R0G directory."""
|
|
357
|
+
base_dir = Path(cfg.get("LST1", "BASE"))
|
|
358
|
+
r0_files = glob.glob(f"{base_dir}/R0/{date_to_dir(date)}/LST-1.?.Run{run_id:05d}.????.fits.fz")
|
|
359
|
+
r0g_files = glob.glob(f"{base_dir}/R0G/{date_to_dir(date)}/LST-1.?.Run{run_id:05d}.????.fits.fz")
|
|
360
|
+
return len(r0_files)==len(r0g_files)
|
|
227
361
|
|
|
228
|
-
sacct_cmd = [
|
|
229
|
-
"sacct",
|
|
230
|
-
"-n",
|
|
231
|
-
"--parsable2",
|
|
232
|
-
"--delimiter=,",
|
|
233
|
-
"--units=G",
|
|
234
|
-
"-o",
|
|
235
|
-
",".join(FORMAT_SLURM),
|
|
236
|
-
"-j",
|
|
237
|
-
job,
|
|
238
|
-
]
|
|
239
362
|
|
|
240
|
-
|
|
363
|
+
def is_closed(date: datetime, run_id: str) -> bool:
|
|
364
|
+
"""Check if run is already closed."""
|
|
365
|
+
base_dir = Path(cfg.get("LST1", "BASE"))
|
|
366
|
+
log_dir = base_dir / f"R0G/log/{date_to_dir(date)}"
|
|
367
|
+
closed_run_file = log_dir / f"gain_selection_{run_id:05d}.closed"
|
|
368
|
+
return closed_run_file.exists()
|
|
241
369
|
|
|
242
370
|
|
|
243
|
-
def GainSel_flag_file(date:
|
|
371
|
+
def GainSel_flag_file(date: datetime) -> Path:
|
|
372
|
+
"""Return the path to the file indicating the completion of the gain selection stage."""
|
|
244
373
|
filename = cfg.get("LSTOSA", "gain_selection_check")
|
|
245
374
|
GainSel_dir = Path(cfg.get("LST1", "GAIN_SELECTION_FLAG_DIR"))
|
|
246
|
-
flagfile = GainSel_dir / date / filename
|
|
375
|
+
flagfile = GainSel_dir / date_to_dir(date) / filename
|
|
247
376
|
return flagfile.resolve()
|
|
248
377
|
|
|
249
378
|
|
|
250
|
-
def GainSel_finished(date:
|
|
379
|
+
def GainSel_finished(date: datetime) -> bool:
|
|
251
380
|
"""Check if gain selection finished successfully."""
|
|
252
381
|
flagfile = GainSel_flag_file(date)
|
|
253
382
|
return flagfile.exists()
|
|
254
383
|
|
|
255
384
|
|
|
256
|
-
def
|
|
385
|
+
def check_gainsel_jobs_runwise(date: datetime, run_id: int) -> bool:
|
|
257
386
|
"""Search for failed jobs in the log directory."""
|
|
258
|
-
|
|
259
|
-
log_dir =
|
|
260
|
-
|
|
261
|
-
|
|
387
|
+
base_dir = Path(cfg.get("LST1", "BASE"))
|
|
388
|
+
log_dir = base_dir / f"R0G/log/{date_to_dir(date)}"
|
|
389
|
+
history_files = log_dir.glob(f"gain_selection_{run_id:05d}.????.history")
|
|
390
|
+
failed_subruns = []
|
|
391
|
+
log.info(f"Checking all history files of run {run_id}")
|
|
392
|
+
|
|
393
|
+
for file in history_files:
|
|
394
|
+
match = re.search(f"gain_selection_{run_id:05d}.(\d+).history", str(file))
|
|
395
|
+
subrun = match.group(1)
|
|
396
|
+
if file.read_text() != "":
|
|
397
|
+
gainsel_rc = file.read_text().splitlines()[-1][-1]
|
|
398
|
+
|
|
399
|
+
if gainsel_rc == "1":
|
|
400
|
+
log.warning(f"Gain selection failed for run {run_id}.{subrun}")
|
|
401
|
+
failed_subruns.append(file)
|
|
402
|
+
|
|
403
|
+
elif gainsel_rc == "0":
|
|
404
|
+
log.debug(f"Gain selection finished successfully for run {run_id}.{subrun}")
|
|
405
|
+
else:
|
|
406
|
+
log.info(f"Gain selection is still running for run {run_id}.{subrun}")
|
|
407
|
+
return False
|
|
408
|
+
|
|
409
|
+
if failed_subruns:
|
|
410
|
+
log.warning(f"{date_to_iso(date)}: Some gain selection jobs did not finish successfully for run {run_id}")
|
|
411
|
+
return False
|
|
412
|
+
else:
|
|
413
|
+
log.info(f"{date_to_iso(date)}: All jobs finished successfully for run {run_id}, creating the corresponding .closed file")
|
|
414
|
+
closed_run_file = log_dir / f"gain_selection_{run_id:05d}.closed"
|
|
415
|
+
closed_run_file.touch()
|
|
416
|
+
return True
|
|
262
417
|
|
|
263
|
-
for job in jobs:
|
|
264
|
-
output = run_sacct_j(job)
|
|
265
|
-
df = get_sacct_output(output)
|
|
266
418
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
419
|
+
def check_warnings_in_logs(date: datetime, run_id: int):
|
|
420
|
+
"""Look for warnings in the log files created by lstchain_r0_to_r0g."""
|
|
421
|
+
base_dir = Path(cfg.get("LST1", "BASE"))
|
|
422
|
+
log_dir = base_dir / f"R0G/log/{date_to_dir(date)}"
|
|
423
|
+
log_files = log_dir.glob(f"r0_to_r0g_{run_id:05d}.*.log")
|
|
424
|
+
for file in log_files:
|
|
425
|
+
content = file.read_text().splitlines()
|
|
426
|
+
for line in content:
|
|
427
|
+
if "FlatField(FF)-like events are not tagged as FF" in line:
|
|
428
|
+
log.warning(f"Warning for run {run_id}: {line}")
|
|
270
429
|
|
|
271
|
-
if failed_jobs:
|
|
272
|
-
log.warning(f"{date}: some jobs did not finish successfully")
|
|
273
430
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
run_summary_dir = Path("/fefs/aswg/data/real/monitoring/RunSummary")
|
|
279
|
-
run_summary_file = run_summary_dir / f"RunSummary_{date}.ecsv"
|
|
280
|
-
summary_table = Table.read(run_summary_file)
|
|
281
|
-
runs = summary_table["run_id"]
|
|
282
|
-
missing_runs = []
|
|
283
|
-
|
|
284
|
-
r0_files = glob.glob(f"/fefs/aswg/data/real/R0/{date}/LST-1.?.Run?????.????.fits.fz")
|
|
285
|
-
r0g_files = glob.glob(f"/fefs/aswg/data/real/R0G/{date}/LST-1.?.Run?????.????.fits.fz")
|
|
286
|
-
all_r0_runs = [parse_r0_filename(i).run for i in r0_files]
|
|
287
|
-
all_r0g_runs = [parse_r0_filename(i).run for i in r0g_files]
|
|
288
|
-
|
|
289
|
-
for run in all_r0_runs:
|
|
290
|
-
if run not in runs:
|
|
291
|
-
if run not in all_r0g_runs:
|
|
292
|
-
missing_runs.append(run)
|
|
293
|
-
|
|
294
|
-
missing_runs.sort()
|
|
295
|
-
if missing_runs:
|
|
296
|
-
log.info(
|
|
297
|
-
f"Some runs are missing. Copying R0 files of runs {pd.Series(missing_runs).unique()} "
|
|
298
|
-
f"directly to /fefs/aswg/data/real/R0G/{date}"
|
|
299
|
-
)
|
|
431
|
+
def check_failed_jobs(date: datetime):
|
|
432
|
+
"""Search for failed jobs in the log directory."""
|
|
300
433
|
|
|
301
|
-
|
|
302
|
-
output_dir = Path(f"/fefs/aswg/data/real/R0G/{date}/")
|
|
303
|
-
files = glob.glob(f"/fefs/aswg/data/real/R0/{date}/LST-1.?.Run{run:05d}.????.fits.fz")
|
|
304
|
-
for file in files:
|
|
305
|
-
sp.run(["cp", file, output_dir])
|
|
434
|
+
summary_table = run_summary_table(date)
|
|
306
435
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
436
|
+
if len(summary_table) == 0:
|
|
437
|
+
log.warning(f"No runs are found in the run summary of {date_to_iso(date)}. Nothing to do. Exiting.")
|
|
438
|
+
sys.exit(0)
|
|
310
439
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
440
|
+
data_runs = summary_table[summary_table["run_type"] == "DATA"]
|
|
441
|
+
failed_runs = []
|
|
442
|
+
|
|
443
|
+
for run in data_runs:
|
|
444
|
+
run_id = run["run_id"]
|
|
445
|
+
check_warnings_in_logs(date, run_id)
|
|
446
|
+
if not is_closed(date, run_id):
|
|
447
|
+
if not check_gainsel_jobs_runwise(date, run_id):
|
|
448
|
+
log.warning(f"Gain selection did not finish successfully for run {run_id}.")
|
|
449
|
+
failed_runs.append(run)
|
|
450
|
+
|
|
451
|
+
if failed_runs:
|
|
452
|
+
log.warning(f"Gain selection did not finish successfully for {date_to_iso(date)}, cannot create the flag file.")
|
|
453
|
+
return
|
|
454
|
+
|
|
455
|
+
runs = summary_table["run_id"]
|
|
456
|
+
missing_runs = []
|
|
457
|
+
|
|
458
|
+
date_str = date_to_dir(date)
|
|
459
|
+
base_dir = Path(cfg.get("LST1", "BASE"))
|
|
460
|
+
r0_files = glob.glob(f"{base_dir}/R0/{date_str}/LST-1.?.Run?????.????.fits.fz")
|
|
461
|
+
r0g_files = glob.glob(f"{base_dir}/R0G/{date_str}/LST-1.?.Run?????.????.fits.fz")
|
|
462
|
+
all_r0_runs = [parse_r0_filename(i).run for i in r0_files]
|
|
463
|
+
all_r0g_runs = [parse_r0_filename(i).run for i in r0g_files]
|
|
464
|
+
|
|
465
|
+
for run in all_r0_runs:
|
|
466
|
+
if run not in runs:
|
|
467
|
+
if run not in all_r0g_runs:
|
|
468
|
+
missing_runs.append(run)
|
|
469
|
+
|
|
470
|
+
missing_runs.sort()
|
|
471
|
+
if missing_runs:
|
|
472
|
+
output_dir = base_dir / f"R0G/{date_str}/"
|
|
473
|
+
log.info(
|
|
474
|
+
f"Some runs are missing. Copying R0 files of runs {pd.Series(missing_runs).unique()} "
|
|
475
|
+
f"directly to {output_dir}"
|
|
476
|
+
)
|
|
477
|
+
|
|
478
|
+
for run in missing_runs:
|
|
479
|
+
|
|
480
|
+
files = base_dir.glob(f"R0/{date_str}/LST-1.?.Run{run:05d}.????.fits.fz")
|
|
481
|
+
for file in files:
|
|
482
|
+
sp.run(["cp", file, output_dir])
|
|
483
|
+
|
|
484
|
+
GainSel_dir = Path(cfg.get("LST1", "GAIN_SELECTION_FLAG_DIR"))
|
|
485
|
+
flagfile_dir = GainSel_dir / date_str
|
|
486
|
+
flagfile_dir.mkdir(parents=True, exist_ok=True)
|
|
487
|
+
|
|
488
|
+
flagfile = GainSel_flag_file(date)
|
|
489
|
+
log.info(f"Gain selection finished successfully, creating flag file for date {date_to_iso(date)} ({flagfile})")
|
|
490
|
+
flagfile.touch()
|
|
314
491
|
|
|
315
492
|
|
|
316
493
|
def main():
|
|
@@ -319,16 +496,30 @@ def main():
|
|
|
319
496
|
script for each of them. The input file should list the dates in the format
|
|
320
497
|
YYYYMMDD one date per line.
|
|
321
498
|
"""
|
|
322
|
-
log.setLevel(logging.INFO)
|
|
323
499
|
args = parser.parse_args()
|
|
500
|
+
|
|
501
|
+
if args.verbose:
|
|
502
|
+
log.setLevel(logging.DEBUG)
|
|
503
|
+
else:
|
|
504
|
+
log.setLevel(logging.INFO)
|
|
324
505
|
|
|
325
506
|
if args.date:
|
|
326
|
-
if args.
|
|
327
|
-
log.
|
|
328
|
-
|
|
507
|
+
if GainSel_finished(args.date):
|
|
508
|
+
log.warning(f"Gain selection already done for date {date_to_iso(args.date)}. Exiting.")
|
|
509
|
+
sys.exit(0)
|
|
510
|
+
elif args.check:
|
|
511
|
+
log.info(f"Checking gain selection status for date {date_to_iso(args.date)}")
|
|
512
|
+
check_failed_jobs(args.date)
|
|
329
513
|
else:
|
|
330
|
-
log.info(f"
|
|
331
|
-
apply_gain_selection(
|
|
514
|
+
log.info(f"\nApplying gain selection to date {date_to_iso(args.date)}")
|
|
515
|
+
apply_gain_selection(
|
|
516
|
+
args.date,
|
|
517
|
+
args.start_time,
|
|
518
|
+
args.end_time,
|
|
519
|
+
args.tool,
|
|
520
|
+
no_queue_check=args.no_queue_check,
|
|
521
|
+
simulate=args.simulate,
|
|
522
|
+
)
|
|
332
523
|
|
|
333
524
|
|
|
334
525
|
elif args.dates_file:
|
|
@@ -338,11 +529,18 @@ def main():
|
|
|
338
529
|
if args.check:
|
|
339
530
|
for date in list_of_dates:
|
|
340
531
|
log.info(f"Checking gain selection status for date {date}")
|
|
341
|
-
check_failed_jobs(date
|
|
532
|
+
check_failed_jobs(date)
|
|
342
533
|
else:
|
|
343
534
|
for date in list_of_dates:
|
|
344
535
|
log.info(f"Applying gain selection to date {date}")
|
|
345
|
-
apply_gain_selection(
|
|
536
|
+
apply_gain_selection(
|
|
537
|
+
date,
|
|
538
|
+
args.start_time,
|
|
539
|
+
args.end_time,
|
|
540
|
+
args.tool,
|
|
541
|
+
no_queue_check=args.no_queue_check,
|
|
542
|
+
simulate=args.simulate,
|
|
543
|
+
)
|
|
346
544
|
log.info("Done! No more dates to process.")
|
|
347
545
|
|
|
348
546
|
|