1
1
"""Handle the paths of the analysis products."""
2
2
3
3
import logging
4
+ import re
5
+ from datetime import datetime
4
6
from pathlib import Path
5
7
from typing import List
6
- from datetime import datetime
7
8
9
+ import lstchain
8
10
from astropy .table import Table
9
- from lstchain .onsite import find_systematics_correction_file , find_time_calibration_file
10
- from lstchain .scripts .onsite .onsite_create_calibration_file import search_filter
11
+ from lstchain .onsite import (find_systematics_correction_file ,
12
+ find_time_calibration_file )
13
+ from lstchain .scripts .onsite .onsite_create_calibration_file import \
14
+ search_filter
11
15
12
16
from osa .configs import options
13
- from osa .configs .config import DEFAULT_CFG
14
- from osa .configs .config import cfg
17
+ from osa .configs .config import DEFAULT_CFG , cfg
15
18
from osa .configs .datamodel import Sequence
16
19
from osa .utils import utils
17
20
from osa .utils .logging import myLogger
18
21
19
22
log = myLogger (logging .getLogger (__name__ ))
20
23
21
24
__all__ = [
22
- "get_calibration_file " ,
23
- "get_drs4_pedestal_file " ,
25
+ "get_calibration_filename " ,
26
+ "get_drs4_pedestal_filename " ,
24
27
"pedestal_ids_file_exists" ,
25
28
"get_run_date" ,
26
29
"drs4_pedestal_exists" ,
40
43
41
44
42
45
DATACHECK_WEB_BASEDIR = Path (cfg .get ("WEBSERVER" , "DATACHECK" ))
46
+ CALIB_BASEDIR = Path (cfg .get ("LST1" , "CALIB_DIR" ))
47
+ DRS4_PEDESTAL_BASEDIR = Path (cfg .get ("LST1" , "PEDESTAL_DIR" ))
43
48
44
49
45
50
def analysis_path (tel ) -> Path :
@@ -86,18 +91,25 @@ def get_run_date(run_id: int) -> datetime:
86
91
return datetime .strptime (date_string , "%Y-%m-%d" )
87
92
88
93
89
- def get_drs4_pedestal_file (run_id : int ) -> Path :
94
+ def get_drs4_pedestal_filename (run_id : int , prod_id : str ) -> Path :
90
95
"""
91
96
Return the drs4 pedestal file corresponding to a given run id
92
97
regardless of the date when the run was taken.
93
98
"""
94
- drs4_pedestal_dir = Path (cfg .get ("LST1" , "PEDESTAL_DIR" ))
99
+ if drs4_pedestal_exists (run_id , prod_id ):
100
+ files = search_drs4_files (run_id , prod_id )
101
+ return files [- 1 ] # Get the latest production among the major lstchain version
102
+
95
103
date = utils .date_to_dir (get_run_date (run_id ))
96
- file = drs4_pedestal_dir / date / f"pro/drs4_pedestal.Run{ run_id :05d} .0000.h5"
97
- return file .resolve ()
104
+ return (
105
+ DRS4_PEDESTAL_BASEDIR
106
+ / date
107
+ / f"v{ lstchain .__version__ } /drs4_pedestal.Run{ run_id :05d} .0000.h5"
108
+ ).resolve ()
98
109
99
110
100
- def get_calibration_file (run_id : int ) -> Path :
111
+ def get_calibration_filename (run_id : int , prod_id : str ) -> Path :
112
+ # sourcery skip: remove-unnecessary-cast
101
113
"""
102
114
Return the calibration file corresponding to a given run_id.
103
115
@@ -109,14 +121,18 @@ def get_calibration_file(run_id: int) -> Path:
109
121
Notes
110
122
-----
111
123
The file path will be built regardless of the date when the run was taken.
112
- We follow the naming convention of the calibration files produced by the lstchain script
113
- which depends on the filter wheels position. Therefore, we need to try to fetch the filter
114
- position from the CaCo database. If the filter position is not found, we assume the default
115
- filter position 5-2. Filter information is not available in the database for runs taken before
124
+ We follow the naming convention of the calibration files produced by the
125
+ lstchain script which depends on the filter wheels position. Therefore, we
126
+ need to try to fetch the filter position from the CaCo database. If the
127
+ filter position is not found, we assume the default filter position 5-2.
128
+ Filter information is not available in the database for runs taken before
116
129
mid 2021 approx.
117
130
"""
118
131
119
- calib_dir = Path (cfg .get ("LST1" , "CALIB_DIR" ))
132
+ if calibration_file_exists (run_id , prod_id ):
133
+ files = search_calibration_files (run_id , prod_id )
134
+ return files [- 1 ] # Get the latest production among the major lstchain version
135
+
120
136
date = utils .date_to_dir (get_run_date (run_id ))
121
137
122
138
if options .test : # Run tests avoiding the access to the database
@@ -131,8 +147,11 @@ def get_calibration_file(run_id: int) -> Path:
131
147
log .warning ("No filter information found in database. Assuming positions 52." )
132
148
options .filters = 52
133
149
134
- file = calib_dir / date / f"pro/calibration_filters_{ options .filters } .Run{ run_id :05d} .0000.h5"
135
- return file .resolve ()
150
+ return (
151
+ CALIB_BASEDIR
152
+ / date
153
+ / f"v{ lstchain .__version__ } /calibration_filters_{ options .filters } .Run{ run_id :05d} .0000.h5"
154
+ ).resolve ()
136
155
137
156
138
157
def pedestal_ids_file_exists (run_id : int ) -> bool :
@@ -142,16 +161,51 @@ def pedestal_ids_file_exists(run_id: int) -> bool:
142
161
return bool (file_list )
143
162
144
163
145
- def drs4_pedestal_exists (run_id : int ) -> bool :
164
+ def drs4_pedestal_exists (run_id : int , prod_id : str ) -> bool :
146
165
"""Return true if drs4 pedestal file was already produced."""
147
- file = get_drs4_pedestal_file (run_id )
148
- return file .exists ()
166
+ files = search_drs4_files (run_id , prod_id )
167
+
168
+ return len (files ) != 0
149
169
150
170
151
- def calibration_file_exists (run_id : int ) -> bool :
171
+ def calibration_file_exists (run_id : int , prod_id : str ) -> bool :
152
172
"""Return true if calibration file was already produced."""
153
- file = get_calibration_file (run_id )
154
- return file .exists ()
173
+ files = search_calibration_files (run_id , prod_id )
174
+
175
+ return len (files ) != 0
176
+
177
+
178
+ def search_drs4_files (run_id : int , prod_id : str ) -> list :
179
+ """
180
+ Find DRS4 baseline correction files corresponding to a run ID
181
+ and major lstchain production version
182
+ """
183
+ date = utils .date_to_dir (get_run_date (run_id ))
184
+ version = get_major_version (prod_id )
185
+ drs4_dir = DRS4_PEDESTAL_BASEDIR / date
186
+ return sorted (
187
+ drs4_dir .glob (f"{ version } */drs4_pedestal.Run{ run_id :05d} .0000.h5" )
188
+ )
189
+
190
+
191
+ def get_major_version (prod_id ):
192
+ """Given a version as vX.Y.Z return vX.Y"""
193
+ # First check that the given version is in the correct format
194
+ if prod_id .startswith ("v" ) and len (prod_id .split ("." )) >= 2 :
195
+ return re .search (r"\D\d+\.\d+" , prod_id )[0 ]
196
+
197
+ raise ValueError ("Format of the version is not in the form vW.X.Y.Z" )
198
+
199
+
200
+ def search_calibration_files (run_id : int , prod_id : str ) -> list :
201
+ """
202
+ Search charge calibration files corresponding to a run ID and major lstchain production version
203
+ """
204
+ date = utils .date_to_dir (get_run_date (run_id ))
205
+ version = get_major_version (prod_id )
206
+ return sorted (
207
+ (CALIB_BASEDIR / date ).glob (f"{ version } */calibration_filters_*.Run{ run_id :05d} .0000.h5" )
208
+ )
155
209
156
210
157
211
def get_drive_file (date : str ) -> Path :
@@ -180,11 +234,16 @@ def sequence_calibration_files(sequence_list: List[Sequence]) -> None:
180
234
"""Build names of the calibration files for each sequence in the list."""
181
235
flat_date = utils .date_to_dir (options .date )
182
236
base_dir = Path (cfg .get ("LST1" , "BASE" ))
237
+ prod_id = options .prod_id
183
238
184
239
for sequence in sequence_list :
185
240
# Assign the calibration files to the sequence object
186
- sequence .drs4_file = get_drs4_pedestal_file (sequence .drs4_run )
187
- sequence .calibration_file = get_calibration_file (sequence .pedcal_run )
241
+ sequence .drs4_file = get_drs4_pedestal_filename (
242
+ sequence .drs4_run , prod_id
243
+ )
244
+ sequence .calibration_file = get_calibration_filename (
245
+ sequence .pedcal_run , prod_id
246
+ )
188
247
sequence .time_calibration_file = find_time_calibration_file (
189
248
"pro" , sequence .pedcal_run , base_dir = base_dir
190
249
)
@@ -235,10 +294,7 @@ def destination_dir(concept: str, create_dir: bool = True) -> Path:
235
294
directory = Path (cfg .get (options .tel_id , "DL1_DIR" )) / nightdir / options .prod_id / "muons"
236
295
elif concept == "INTERLEAVED" :
237
296
directory = (
238
- Path (cfg .get (options .tel_id , "DL1_DIR" ))
239
- / nightdir
240
- / options .prod_id
241
- / "interleaved"
297
+ Path (cfg .get (options .tel_id , "DL1_DIR" )) / nightdir / options .prod_id / "interleaved"
242
298
)
243
299
elif concept == "DATACHECK" :
244
300
directory = (
@@ -257,17 +313,21 @@ def destination_dir(concept: str, create_dir: bool = True) -> Path:
257
313
)
258
314
elif concept in {"DL2" , "DL3" }:
259
315
directory = (
260
- Path (cfg .get (options .tel_id , concept + "_DIR" ))
261
- / nightdir
316
+ (Path (cfg .get (options .tel_id , f"{ concept } _DIR" )) / nightdir )
262
317
/ options .prod_id
263
- / options .dl2_prod_id
264
- )
318
+ ) / options .dl2_prod_id
265
319
elif concept in {"PEDESTAL" , "CALIB" , "TIMECALIB" }:
266
320
directory = (
267
- Path (cfg .get (options .tel_id , concept + "_DIR" )) / nightdir / options .calib_prod_id
321
+ Path (cfg .get (options .tel_id , f"{ concept } _DIR" ))
322
+ / nightdir
323
+ / options .prod_id
268
324
)
269
325
elif concept == "HIGH_LEVEL" :
270
- directory = Path (cfg .get (options .tel_id , concept + "_DIR" )) / nightdir / options .prod_id
326
+ directory = (
327
+ Path (cfg .get (options .tel_id , f"{ concept } _DIR" ))
328
+ / nightdir
329
+ / options .prod_id
330
+ )
271
331
else :
272
332
log .warning (f"Concept { concept } not known" )
273
333
directory = None
0 commit comments