lstosa 0.10.14__py3-none-any.whl → 0.10.16__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.14.dist-info → lstosa-0.10.16.dist-info}/METADATA +1 -1
- {lstosa-0.10.14.dist-info → lstosa-0.10.16.dist-info}/RECORD +17 -16
- {lstosa-0.10.14.dist-info → lstosa-0.10.16.dist-info}/WHEEL +1 -1
- {lstosa-0.10.14.dist-info → lstosa-0.10.16.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 +367 -186
- osa/scripts/gainsel_webmaker.py +157 -0
- osa/scripts/sequencer.py +71 -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
- osa/workflow/stages.py +13 -6
- {lstosa-0.10.14.dist-info → lstosa-0.10.16.dist-info}/LICENSE +0 -0
- {lstosa-0.10.14.dist-info → lstosa-0.10.16.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from argparse import ArgumentParser
|
|
3
|
+
from datetime import datetime, timedelta
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
from astropy.table import Table
|
|
8
|
+
|
|
9
|
+
from osa.configs import options
|
|
10
|
+
from osa.configs.config import cfg
|
|
11
|
+
from osa.nightsummary.nightsummary import run_summary_table
|
|
12
|
+
from osa.paths import DEFAULT_CFG
|
|
13
|
+
from osa.scripts.sequencer_webmaker import html_content
|
|
14
|
+
from osa.utils.utils import date_to_dir, date_to_iso
|
|
15
|
+
|
|
16
|
+
log = logging.getLogger(__name__)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def valid_date(string):
|
|
20
|
+
"""Check if the string is a valid date and return a datetime object."""
|
|
21
|
+
return datetime.strptime(string, "%Y-%m-%d")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
common_parser = ArgumentParser(add_help=False)
|
|
25
|
+
common_parser.add_argument(
|
|
26
|
+
"-c",
|
|
27
|
+
"--config",
|
|
28
|
+
type=Path,
|
|
29
|
+
default=DEFAULT_CFG,
|
|
30
|
+
help="Use specific config file [default configs/sequencer.cfg]",
|
|
31
|
+
)
|
|
32
|
+
common_parser.add_argument(
|
|
33
|
+
"-d",
|
|
34
|
+
"--date",
|
|
35
|
+
help="Date of the start of the night in ISO format (YYYY-MM-DD). Defaults to yesterday",
|
|
36
|
+
type=valid_date,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def check_gainsel_jobs_runwise(date: datetime, run_id: int) -> bool:
|
|
41
|
+
"""Search for failed jobs in the log directory."""
|
|
42
|
+
base_dir = Path(cfg.get("LST1", "BASE"))
|
|
43
|
+
flat_date = date_to_dir(date)
|
|
44
|
+
log_dir = base_dir / f"R0G/log/{flat_date}"
|
|
45
|
+
history_files = log_dir.glob(f"gain_selection_{run_id:05d}.????.history")
|
|
46
|
+
|
|
47
|
+
success_subruns = 0
|
|
48
|
+
failed_subruns = 0
|
|
49
|
+
pending_subruns = 0
|
|
50
|
+
|
|
51
|
+
for file in history_files:
|
|
52
|
+
if file.read_text() != "":
|
|
53
|
+
gainsel_rc = file.read_text().splitlines()[-1][-1]
|
|
54
|
+
|
|
55
|
+
if gainsel_rc == "1":
|
|
56
|
+
failed_subruns += 1
|
|
57
|
+
|
|
58
|
+
elif gainsel_rc == "0":
|
|
59
|
+
success_subruns += 1
|
|
60
|
+
|
|
61
|
+
else:
|
|
62
|
+
pending_subruns += 1
|
|
63
|
+
|
|
64
|
+
return {"pending": pending_subruns, "success": success_subruns, "failed": failed_subruns}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def check_failed_jobs(date: datetime) -> pd.DataFrame:
|
|
68
|
+
"""Search for failed jobs in the log directory."""
|
|
69
|
+
summary_table = run_summary_table(date)
|
|
70
|
+
data_runs = summary_table[summary_table["run_type"] == "DATA"]
|
|
71
|
+
|
|
72
|
+
gainsel_status_dict = {}
|
|
73
|
+
for run in data_runs:
|
|
74
|
+
run_id = run["run_id"]
|
|
75
|
+
gainsel_job_status = check_gainsel_jobs_runwise(date, run_id)
|
|
76
|
+
gainsel_status_dict[run_id] = gainsel_job_status
|
|
77
|
+
|
|
78
|
+
gainsel_df = pd.DataFrame(gainsel_status_dict.values(), index=gainsel_status_dict.keys())
|
|
79
|
+
gainsel_df.reset_index(inplace=True)
|
|
80
|
+
gainsel_df.rename(columns={"index": "run_id"}, inplace=True)
|
|
81
|
+
summary_table = summary_table.to_pandas()
|
|
82
|
+
|
|
83
|
+
final_table = pd.merge(summary_table, gainsel_df, on="run_id")[
|
|
84
|
+
[
|
|
85
|
+
"run_id",
|
|
86
|
+
"n_subruns",
|
|
87
|
+
"pending",
|
|
88
|
+
"success",
|
|
89
|
+
"failed",
|
|
90
|
+
]
|
|
91
|
+
]
|
|
92
|
+
|
|
93
|
+
def determine_status(row):
|
|
94
|
+
if row["failed"] > 0:
|
|
95
|
+
return "FAILED"
|
|
96
|
+
elif row["pending"] == row["n_subruns"]:
|
|
97
|
+
return "PENDING"
|
|
98
|
+
elif row["success"] == row["n_subruns"]:
|
|
99
|
+
return "COMPLETED"
|
|
100
|
+
elif row["pending"] > 0:
|
|
101
|
+
return "RUNNING"
|
|
102
|
+
else:
|
|
103
|
+
return "NOT STARTED"
|
|
104
|
+
|
|
105
|
+
final_table["GainSel%"] = round(final_table["success"] * 100 / final_table["n_subruns"])
|
|
106
|
+
final_table["GainSelStatus"] = final_table.apply(determine_status, axis=1)
|
|
107
|
+
|
|
108
|
+
return final_table
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def main():
|
|
112
|
+
"""Produce the html file with the processing OSA Gain Selection status.
|
|
113
|
+
|
|
114
|
+
It creates an HTML file osa_gainsel_status_YYYY-MM-DD.html
|
|
115
|
+
"""
|
|
116
|
+
args = ArgumentParser(
|
|
117
|
+
description=(
|
|
118
|
+
"Script to create an HTML file with the gain selection status "
|
|
119
|
+
"(osa_gainsel_status_YYYY-MM-DD.html)"
|
|
120
|
+
),
|
|
121
|
+
parents=[common_parser],
|
|
122
|
+
).parse_args()
|
|
123
|
+
|
|
124
|
+
if args.date:
|
|
125
|
+
flat_date = date_to_dir(args.date)
|
|
126
|
+
options.date = args.date
|
|
127
|
+
|
|
128
|
+
else:
|
|
129
|
+
# yesterday by default
|
|
130
|
+
yesterday = datetime.now() - timedelta(days=1)
|
|
131
|
+
options.date = yesterday
|
|
132
|
+
flat_date = date_to_dir(yesterday)
|
|
133
|
+
|
|
134
|
+
date = date_to_iso(options.date)
|
|
135
|
+
run_summary_directory = Path(cfg.get("LST1", "RUN_SUMMARY_DIR"))
|
|
136
|
+
run_summary_file = run_summary_directory / f"RunSummary_{flat_date}.ecsv"
|
|
137
|
+
|
|
138
|
+
gain_selection_web_directory = Path(cfg.get("LST1", "GAIN_SELECTION_WEB_DIR"))
|
|
139
|
+
gain_selection_web_directory.mkdir(parents=True, exist_ok=True)
|
|
140
|
+
html_file = gain_selection_web_directory / f"osa_gainsel_status_{date}.html"
|
|
141
|
+
|
|
142
|
+
# Create and save the HTML file
|
|
143
|
+
if not run_summary_file.is_file() or len(Table.read(run_summary_file)["run_id"]) == 0:
|
|
144
|
+
content = "<p>No data found</p>"
|
|
145
|
+
log.warning(f"No data found for date {date}, creating an empty HTML file.")
|
|
146
|
+
|
|
147
|
+
else:
|
|
148
|
+
# Get the table with the gain selection check report in HTML format:
|
|
149
|
+
table_gain_selection_jobs = check_failed_jobs(options.date)
|
|
150
|
+
content = table_gain_selection_jobs.to_html(justify="left")
|
|
151
|
+
|
|
152
|
+
html_file.write_text(html_content(content, date, "OSA Gain Selection"))
|
|
153
|
+
log.info(f"Created HTML file {html_file}")
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
if __name__ == "__main__":
|
|
157
|
+
main()
|
osa/scripts/sequencer.py
CHANGED
|
@@ -9,6 +9,7 @@ import logging
|
|
|
9
9
|
import os
|
|
10
10
|
import sys
|
|
11
11
|
from decimal import Decimal
|
|
12
|
+
import datetime
|
|
12
13
|
|
|
13
14
|
from osa import osadb
|
|
14
15
|
from osa.configs import options
|
|
@@ -28,7 +29,7 @@ from osa.paths import analysis_path
|
|
|
28
29
|
from osa.report import start
|
|
29
30
|
from osa.utils.cliopts import sequencer_cli_parsing
|
|
30
31
|
from osa.utils.logging import myLogger
|
|
31
|
-
from osa.utils.utils import is_day_closed, gettag, date_to_iso
|
|
32
|
+
from osa.utils.utils import is_day_closed, gettag, date_to_iso
|
|
32
33
|
from osa.veto import get_closed_list, get_veto_list
|
|
33
34
|
from osa.scripts.gain_selection import GainSel_finished
|
|
34
35
|
|
|
@@ -98,9 +99,9 @@ def single_process(telescope):
|
|
|
98
99
|
log.warning("No runs found for this date. Nothing to do. Exiting.")
|
|
99
100
|
sys.exit(0)
|
|
100
101
|
|
|
101
|
-
if not options.no_gainsel and not GainSel_finished(
|
|
102
|
+
if not options.no_gainsel and not GainSel_finished(options.date):
|
|
102
103
|
log.info(
|
|
103
|
-
f"Gain selection did not finish successfully for date {options.date}."
|
|
104
|
+
f"Gain selection did not finish successfully for date {date_to_iso(options.date)}. "
|
|
104
105
|
"Try again later, once gain selection has finished."
|
|
105
106
|
)
|
|
106
107
|
sys.exit()
|
|
@@ -109,6 +110,20 @@ def single_process(telescope):
|
|
|
109
110
|
log.info(f"Date {date_to_iso(options.date)} is already closed for {options.tel_id}")
|
|
110
111
|
return sequence_list
|
|
111
112
|
|
|
113
|
+
if not options.test and not options.simulate:
|
|
114
|
+
if is_sequencer_running(options.date):
|
|
115
|
+
log.info(f"Sequencer is still running for date {date_to_iso(options.date)}. Try again later.")
|
|
116
|
+
sys.exit(0)
|
|
117
|
+
|
|
118
|
+
elif is_sequencer_completed(options.date) and not options.force_submit:
|
|
119
|
+
log.info(f"Sequencer already finished for date {date_to_iso(options.date)}. Exiting")
|
|
120
|
+
sys.exit(0)
|
|
121
|
+
|
|
122
|
+
elif timeout_in_sequencer(options.date) and not options.force_submit:
|
|
123
|
+
log.info(f"Some jobs of sequencer finished in TIMEOUT for date {date_to_iso(options.date)}."
|
|
124
|
+
" Please relaunch the affected sequences manually.")
|
|
125
|
+
sys.exit(0)
|
|
126
|
+
|
|
112
127
|
# Build the sequences
|
|
113
128
|
sequence_list = build_sequences(options.date)
|
|
114
129
|
|
|
@@ -306,5 +321,58 @@ def output_matrix(matrix: list, padding_space: int):
|
|
|
306
321
|
log.info(stringrow)
|
|
307
322
|
|
|
308
323
|
|
|
324
|
+
def is_sequencer_running(date: datetime.datetime) -> bool:
|
|
325
|
+
"""Check if the jobs launched by sequencer are running or pending for the given date."""
|
|
326
|
+
summary_table = run_summary_table(date)
|
|
327
|
+
sacct_output = run_sacct()
|
|
328
|
+
sacct_info = get_sacct_output(sacct_output)
|
|
329
|
+
|
|
330
|
+
for run in summary_table["run_id"]:
|
|
331
|
+
jobs_run = sacct_info[sacct_info["JobName"]==f"LST1_{run:05d}"]
|
|
332
|
+
queued_jobs = jobs_run[(jobs_run["State"] == "RUNNING") | (jobs_run["State"] == "PENDING")]
|
|
333
|
+
if len(queued_jobs) != 0:
|
|
334
|
+
return True
|
|
335
|
+
|
|
336
|
+
return False
|
|
337
|
+
|
|
338
|
+
|
|
339
|
+
def is_sequencer_completed(date: datetime.datetime) -> bool:
|
|
340
|
+
"""Check if the jobs launched by sequencer are already completed."""
|
|
341
|
+
summary_table = run_summary_table(date)
|
|
342
|
+
data_runs = summary_table[summary_table["run_type"] == "DATA"]
|
|
343
|
+
sacct_output = run_sacct()
|
|
344
|
+
sacct_info = get_sacct_output(sacct_output)
|
|
345
|
+
|
|
346
|
+
for run in data_runs["run_id"]:
|
|
347
|
+
jobs_run = sacct_info[sacct_info["JobName"]==f"LST1_{run:05d}"]
|
|
348
|
+
if len(jobs_run["JobID"].unique())>1:
|
|
349
|
+
last_job_id = sorted(jobs_run["JobID"].unique())[-1]
|
|
350
|
+
jobs_run = sacct_info[sacct_info["JobID"]==last_job_id]
|
|
351
|
+
incomplete_jobs = jobs_run[(jobs_run["State"] != "COMPLETED")]
|
|
352
|
+
if len(jobs_run) == 0 or len(incomplete_jobs) != 0:
|
|
353
|
+
return False
|
|
354
|
+
|
|
355
|
+
return True
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def timeout_in_sequencer(date: datetime.datetime) -> bool:
|
|
359
|
+
"""Check if any of the jobs launched by sequencer finished in timeout."""
|
|
360
|
+
summary_table = run_summary_table(date)
|
|
361
|
+
data_runs = summary_table[summary_table["run_type"] == "DATA"]
|
|
362
|
+
sacct_output = run_sacct()
|
|
363
|
+
sacct_info = get_sacct_output(sacct_output)
|
|
364
|
+
|
|
365
|
+
for run in data_runs["run_id"]:
|
|
366
|
+
jobs_run = sacct_info[sacct_info["JobName"]==f"LST1_{run:05d}"]
|
|
367
|
+
if len(jobs_run["JobID"].unique())>1:
|
|
368
|
+
last_job_id = sorted(jobs_run["JobID"].unique())[-1]
|
|
369
|
+
jobs_run = sacct_info[sacct_info["JobID"]==last_job_id]
|
|
370
|
+
timeout_jobs = jobs_run[(jobs_run["State"] == "TIMEOUT")]
|
|
371
|
+
if len(timeout_jobs) != 0:
|
|
372
|
+
return True
|
|
373
|
+
|
|
374
|
+
return False
|
|
375
|
+
|
|
376
|
+
|
|
309
377
|
if __name__ == "__main__":
|
|
310
378
|
main()
|
|
@@ -20,7 +20,7 @@ from osa.utils.utils import is_day_closed, date_to_iso, date_to_dir
|
|
|
20
20
|
log = myLogger(logging.getLogger())
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
def html_content(body: str, date: str) -> str:
|
|
23
|
+
def html_content(body: str, date: str, title: str) -> str:
|
|
24
24
|
"""Build the HTML content.
|
|
25
25
|
|
|
26
26
|
Parameters
|
|
@@ -43,11 +43,11 @@ def html_content(body: str, date: str) -> str:
|
|
|
43
43
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
44
44
|
<head>
|
|
45
45
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
46
|
-
<title>
|
|
46
|
+
<title>{title} status</title><link href="osa.css" rel="stylesheet"
|
|
47
47
|
type="text/css" /><style>table{{width:152ex;}}</style>
|
|
48
48
|
</head>
|
|
49
49
|
<body>
|
|
50
|
-
<h1>
|
|
50
|
+
<h1>{title} processing status</h1>
|
|
51
51
|
<p>Processing data from: {date}. Last updated: {time_update} UTC</p>
|
|
52
52
|
{body}
|
|
53
53
|
</body>
|
|
@@ -159,7 +159,7 @@ def main():
|
|
|
159
159
|
directory.mkdir(parents=True, exist_ok=True)
|
|
160
160
|
|
|
161
161
|
html_file = directory / Path(f"osa_status_{flat_date}.html")
|
|
162
|
-
html_file.write_text(html_content(html_table, date), encoding="utf-8")
|
|
162
|
+
html_file.write_text(html_content(html_table, date, "OSA Sequencer"), encoding="utf-8")
|
|
163
163
|
|
|
164
164
|
log.info("Done")
|
|
165
165
|
|
|
@@ -23,6 +23,7 @@ ALL_SCRIPTS = [
|
|
|
23
23
|
"theta2_significance",
|
|
24
24
|
"source_coordinates",
|
|
25
25
|
"sequencer_webmaker",
|
|
26
|
+
"gainsel_webmaker",
|
|
26
27
|
]
|
|
27
28
|
|
|
28
29
|
options.date = datetime.datetime.fromisoformat("2020-01-17")
|
|
@@ -397,3 +398,29 @@ def test_sequencer_webmaker(
|
|
|
397
398
|
# Running without test option will make the script fail
|
|
398
399
|
output = sp.run(["sequencer_webmaker", "-d", "2020-01-17"])
|
|
399
400
|
assert output.returncode != 0
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def test_gainsel_webmaker(
|
|
404
|
+
base_test_dir,
|
|
405
|
+
):
|
|
406
|
+
|
|
407
|
+
output = sp.run(["gainsel_webmaker", "-d", "2020-01-17"])
|
|
408
|
+
assert output.returncode == 0
|
|
409
|
+
directory = base_test_dir / "OSA" / "GainSelWeb"
|
|
410
|
+
expected_file = directory / "osa_gainsel_status_2020-01-17.html"
|
|
411
|
+
assert expected_file.exists()
|
|
412
|
+
|
|
413
|
+
# Test a date with non-existing run summary
|
|
414
|
+
output = sp.run(["gainsel_webmaker", "-d", "2024-01-12"])
|
|
415
|
+
assert output.returncode == 0
|
|
416
|
+
directory = base_test_dir / "OSA" / "GainSelWeb"
|
|
417
|
+
expected_file = directory / "osa_gainsel_status_2024-01-12.html"
|
|
418
|
+
assert expected_file.exists()
|
|
419
|
+
|
|
420
|
+
|
|
421
|
+
def test_gainsel_web_content():
|
|
422
|
+
from osa.scripts.gainsel_webmaker import check_failed_jobs
|
|
423
|
+
|
|
424
|
+
table = check_failed_jobs(options.date)
|
|
425
|
+
assert table["GainSelStatus"][0] == "NOT STARTED"
|
|
426
|
+
assert table["GainSel%"][0] == 0.0
|
osa/tests/test_jobs.py
CHANGED
|
@@ -71,6 +71,7 @@ def test_scheduler_env_variables(sequence_list, running_analysis_dir):
|
|
|
71
71
|
"#SBATCH --error=log/Run01809.%4a_jobid_%A.err",
|
|
72
72
|
f'#SBATCH --partition={cfg.get("SLURM", "PARTITION_PEDCALIB")}',
|
|
73
73
|
"#SBATCH --mem-per-cpu=3GB",
|
|
74
|
+
"#SBATCH --account=dpps",
|
|
74
75
|
]
|
|
75
76
|
# Extract the second sequence
|
|
76
77
|
second_sequence = sequence_list[1]
|
|
@@ -83,7 +84,8 @@ def test_scheduler_env_variables(sequence_list, running_analysis_dir):
|
|
|
83
84
|
"#SBATCH --error=log/Run01807.%4a_jobid_%A.err",
|
|
84
85
|
"#SBATCH --array=0-10",
|
|
85
86
|
f'#SBATCH --partition={cfg.get("SLURM", "PARTITION_DATA")}',
|
|
86
|
-
"#SBATCH --mem-per-cpu=
|
|
87
|
+
"#SBATCH --mem-per-cpu=6GB",
|
|
88
|
+
"#SBATCH --account=dpps",
|
|
87
89
|
]
|
|
88
90
|
|
|
89
91
|
|
|
@@ -104,7 +106,8 @@ def test_job_header_template(sequence_list, running_analysis_dir):
|
|
|
104
106
|
#SBATCH --output=log/Run01809.%4a_jobid_%A.out
|
|
105
107
|
#SBATCH --error=log/Run01809.%4a_jobid_%A.err
|
|
106
108
|
#SBATCH --partition={cfg.get('SLURM', 'PARTITION_PEDCALIB')}
|
|
107
|
-
#SBATCH --mem-per-cpu=3GB
|
|
109
|
+
#SBATCH --mem-per-cpu=3GB
|
|
110
|
+
#SBATCH --account=dpps"""
|
|
108
111
|
)
|
|
109
112
|
assert header == output_string1
|
|
110
113
|
|
|
@@ -122,7 +125,8 @@ def test_job_header_template(sequence_list, running_analysis_dir):
|
|
|
122
125
|
#SBATCH --error=log/Run01807.%4a_jobid_%A.err
|
|
123
126
|
#SBATCH --array=0-10
|
|
124
127
|
#SBATCH --partition={cfg.get('SLURM', 'PARTITION_DATA')}
|
|
125
|
-
#SBATCH --mem-per-cpu=
|
|
128
|
+
#SBATCH --mem-per-cpu=6GB
|
|
129
|
+
#SBATCH --account=dpps"""
|
|
126
130
|
)
|
|
127
131
|
assert header == output_string2
|
|
128
132
|
|
|
@@ -154,6 +158,7 @@ def test_create_job_template_scheduler(
|
|
|
154
158
|
#SBATCH --array=0-10
|
|
155
159
|
#SBATCH --partition={cfg.get('SLURM', 'PARTITION_DATA')}
|
|
156
160
|
#SBATCH --mem-per-cpu={cfg.get('SLURM', 'MEMSIZE_DATA')}
|
|
161
|
+
#SBATCH --account={cfg.get('SLURM', 'ACCOUNT')}
|
|
157
162
|
|
|
158
163
|
import os
|
|
159
164
|
import subprocess
|
|
@@ -199,6 +204,7 @@ def test_create_job_template_scheduler(
|
|
|
199
204
|
#SBATCH --array=0-8
|
|
200
205
|
#SBATCH --partition={cfg.get('SLURM', 'PARTITION_DATA')}
|
|
201
206
|
#SBATCH --mem-per-cpu={cfg.get('SLURM', 'MEMSIZE_DATA')}
|
|
207
|
+
#SBATCH --account={cfg.get('SLURM', 'ACCOUNT')}
|
|
202
208
|
|
|
203
209
|
import os
|
|
204
210
|
import subprocess
|
osa/utils/cliopts.py
CHANGED
|
@@ -280,6 +280,13 @@ def sequencer_argparser():
|
|
|
280
280
|
default=False,
|
|
281
281
|
help="Do not check if the gain selection finished correctly (default False)",
|
|
282
282
|
)
|
|
283
|
+
parser.add_argument(
|
|
284
|
+
"-f",
|
|
285
|
+
"--force-submit",
|
|
286
|
+
action="store_true",
|
|
287
|
+
default=False,
|
|
288
|
+
help="Force sequencer to submit jobs"
|
|
289
|
+
)
|
|
283
290
|
parser.add_argument(
|
|
284
291
|
"tel_id",
|
|
285
292
|
choices=["ST", "LST1", "LST2", "all"],
|
|
@@ -299,6 +306,7 @@ def sequencer_cli_parsing():
|
|
|
299
306
|
options.no_calib = opts.no_calib
|
|
300
307
|
options.no_dl2 = opts.no_dl2
|
|
301
308
|
options.no_gainsel = opts.no_gainsel
|
|
309
|
+
options.force_submit = opts.force_submit
|
|
302
310
|
|
|
303
311
|
log.debug(f"the options are {opts}")
|
|
304
312
|
|
osa/workflow/stages.py
CHANGED
|
@@ -75,15 +75,15 @@ class AnalysisStage:
|
|
|
75
75
|
reproduced in subsequent trials.
|
|
76
76
|
"""
|
|
77
77
|
|
|
78
|
-
if self.command == "
|
|
78
|
+
if self.command == cfg.get("lstchain", "r0_to_dl1"):
|
|
79
79
|
self._remove_dl1a_output()
|
|
80
|
-
elif self.command == "
|
|
80
|
+
elif self.command == cfg.get("lstchain", "dl1ab"):
|
|
81
81
|
self._remove_dl1b_output('dl1_LST-1.Run')
|
|
82
|
-
elif self.command == "
|
|
82
|
+
elif self.command == cfg.get("lstchain", "check_dl1"):
|
|
83
83
|
self._remove_dl1b_output('datacheck_dl1_LST-1.Run')
|
|
84
|
-
elif self.command == "
|
|
84
|
+
elif self.command == cfg.get("lstchain", "charge_calibration"):
|
|
85
85
|
self._remove_calibration()
|
|
86
|
-
elif self.command == "
|
|
86
|
+
elif self.command == cfg.get("lstchain", "drs4_baseline"):
|
|
87
87
|
self._remove_drs4_baseline()
|
|
88
88
|
|
|
89
89
|
def _remove_drs4_baseline(self):
|
|
@@ -121,9 +121,16 @@ class AnalysisStage:
|
|
|
121
121
|
|
|
122
122
|
def _write_checkpoint(self):
|
|
123
123
|
"""Write the checkpoint in the history file."""
|
|
124
|
+
command_to_prod_id = {
|
|
125
|
+
cfg.get("lstchain", "r0_to_dl1"): options.prod_id,
|
|
126
|
+
cfg.get("lstchain", "dl1ab"): options.dl1_prod_id,
|
|
127
|
+
cfg.get("lstchain", "check_dl1"): options.dl1_prod_id,
|
|
128
|
+
cfg.get("lstchain", "dl1_to_dl2"): options.dl2_prod_id
|
|
129
|
+
}
|
|
130
|
+
prod_id = command_to_prod_id.get(self.command)
|
|
124
131
|
history(
|
|
125
132
|
run=self.run,
|
|
126
|
-
prod_id=
|
|
133
|
+
prod_id=prod_id,
|
|
127
134
|
stage=self.command,
|
|
128
135
|
return_code=self.rc,
|
|
129
136
|
history_file=self.history_file,
|
|
File without changes
|
|
File without changes
|