lstosa 0.10.4__py3-none-any.whl → 0.10.6__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lstosa
3
- Version: 0.10.4
3
+ Version: 0.10.6
4
4
  Summary: Onsite analysis pipeline for the CTA LST-1
5
5
  Author: María Láinez, José Enrique Ruiz, Lab Saha, Andrés Baquero, José Luis Contreras, Maximilian Linhoff
6
6
  Author-email: Daniel Morcuende <dmorcuen@ucm.es>
@@ -54,20 +54,20 @@ Requires-Dist: freezegun ; extra == 'test'
54
54
  [![ci](https://github.com/cta-observatory/lstosa/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/cta-observatory/lstosa/actions/workflows/ci.yml)
55
55
  [![Documentation Status](https://readthedocs.org/projects/lstosa/badge/?version=latest)](https://lstosa.readthedocs.io/en/latest/?badge=latest)
56
56
  [![coverage](https://codecov.io/gh/cta-observatory/lstosa/branch/main/graph/badge.svg?token=Zjk1U1ytaG)](https://codecov.io/gh/cta-observatory/lstosa)
57
- [![quality](https://app.codacy.com/project/badge/Grade/a8743a706e7c45fc989d5ebc4d61d54f)](https://www.codacy.com/gh/cta-observatory/lstosa/dashboard?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=cta-observatory/lstosa&amp;utm_campaign=Badge_Grade)
57
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/a8743a706e7c45fc989d5ebc4d61d54f)](https://app.codacy.com/gh/cta-observatory/lstosa/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade)
58
58
  [![pypi](https://img.shields.io/pypi/v/lstosa)](https://pypi.org/project/lstosa/)
59
59
  [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6567234.svg)](https://doi.org/10.5281/zenodo.6567234)
60
60
 
61
61
 
62
- Prototype onsite processing pipeline for the Large Size Telescope prototype (LST-1) of [CTA](https://www.cta-observatory.org/) (Cherenkov Telescope Array) based on [cta-lstchain](https://github.com/cta-observatory/cta-lstchain) running on the LST-1 IT onsite center at ORM (La Palma, Spain). It automatically carries out the next-day analysis of observed data using cron jobs, parallelizing the processing using the job scheduler SLURM. It provides data quality monitoring and tracking of analysis products' provenance.
63
- Moreover, it also massively reprocesses the entire LST-1 dataset with each cta-lstchain major release:
62
+ Onsite processing pipeline for the Large-Sized Telescope prototype (LST-1) of [CTAO](https://www.cta-observatory.org/) (Cherenkov Telescope Array Observatory) based on [cta-lstchain](https://github.com/cta-observatory/cta-lstchain) running on the LST-1 IT onsite data center at Observatorio Roque de los Muchachos (La Palma, Spain). It automatically carries out the next-day analysis of observed data using cron jobs, parallelizing the processing using the job scheduler SLURM. It provides data quality monitoring and tracking of analysis products' provenance. Moreover, it also massively reprocesses the entire LST-1 dataset with each cta-lstchain major release.
63
+
64
64
  - Code: <https://github.com/cta-observatory/lstosa>
65
65
  - Docs: <https://lstosa.readthedocs.io/>
66
66
  - License: [BSD-3-Clause](https://github.com/cta-observatory/lstosa/blob/main/LICENSE)
67
67
 
68
68
  ## Install
69
69
  We recommend using an isolated conda environment.
70
- - Install miniconda first.
70
+ - Install mamba/miniconda first.
71
71
  - Clone the repository, create and activate the conda environment using the `environment.yml` file:
72
72
 
73
73
  ```bash
@@ -77,7 +77,7 @@ We recommend using an isolated conda environment.
77
77
  conda activate osa
78
78
  ```
79
79
 
80
- Then install `lstosa` as a **user** with: `pip install lstosa`, or as a **developer** with: `pip install -e .`.
80
+ Then install `lstosa` as a **user** with: `pip install lstosa`, or as a **developer** with: `pip install -e .`. To install test, docs dependencies use `pip install -e .[test]`, `pip install -e .[doc]` or simply `pip install -e .[all]`
81
81
 
82
82
  In case you want to install the lstchain development version instead of a fixed tag, you can run inside the `osa` environment:
83
83
 
@@ -1,9 +1,9 @@
1
1
  osa/__init__.py,sha256=crotf1NMTfNdZuCua_5T_jk3kvZrAAwVw4FPrfxv994,193
2
- osa/_version.py,sha256=HXKqJR44DhKjW27JxX9-utoVrog1s0wcE7R-Ggh4Ats,413
3
- osa/conftest.py,sha256=7U1hVv-sCPfAQ27UR__Ij--F-AU51hMOe7rsT1-7CJE,19026
2
+ osa/_version.py,sha256=0ek8_w_jF04UB6FpW1K7d1RgH0zQMd77H5TbKzdthjI,413
3
+ osa/conftest.py,sha256=b_26FciV8NZAdHj2S10E8cE4bettinLJY83Roe1a5L4,19358
4
4
  osa/job.py,sha256=acdiaRlHsc2GLyz2Oz_RBiawJo9QKK-tsajYdM7X0_Q,25393
5
5
  osa/osadb.py,sha256=pkCuYbEG-moHG0uQHxwB7giQAv2XTld4HJ5gdn1F1hA,2422
6
- osa/paths.py,sha256=P8ArRxdOghiGufYrcuJJmla0OP5YQjseNxpbOig1Qpg,9998
6
+ osa/paths.py,sha256=nkXPUdQAzIlvB71lOERiPjgET58fj5DEbWazWqKbIJw,11869
7
7
  osa/raw.py,sha256=ZNIsuqfx5ljoz_hwhSuafdKf-wr8-cxRJmel-A2endg,1337
8
8
  osa/report.py,sha256=sL2V7n8Y_UUaSDbWJY2o4UxDb4FU5AaFIRR8R25DB8o,4634
9
9
  osa/version.py,sha256=9T2TtuGBQeOy5PJDxMCeGlqx5baxLaq47VmFTDc09z8,796
@@ -11,8 +11,8 @@ osa/veto.py,sha256=HMaojHSRT0HG0FBGG38su3xz2_ejsVKU1QktAzx28aA,3090
11
11
  osa/configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
12
  osa/configs/config.py,sha256=cX0Vr4sorBVQ2KRqPIRSEGENKH_uC5lrgVHx1hp6YTk,1148
13
13
  osa/configs/datamodel.py,sha256=L_WRM91PBlMrtuE30akh7YR-56P0g9D994qzKSfhNJc,1950
14
- osa/configs/options.py,sha256=q8NGEZiLkwulogp35vhK8mHcYN1AZBVUY8CwnOrrOF4,545
15
- osa/configs/sequencer.cfg,sha256=BY5GqemJsg1CJUynRWnJQjwEU2ktIWQIAcSx0plBoM8,4803
14
+ osa/configs/options.py,sha256=CyL7WnHiC_pvB3mnjRF7Wg43uPzQgmwlbvIqkRzlDLA,524
15
+ osa/configs/sequencer.cfg,sha256=cysPy6q8vShh0V0LiEBfip-rUmwyNlNVDKhGPMiKH5g,4784
16
16
  osa/high_level/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  osa/high_level/selection_cuts.toml,sha256=ReSmcKtOPZY5JsZ9ExnxYdz7OrJEB8gghCbzHmeOyFg,128
18
18
  osa/high_level/significance.py,sha256=Y1jokkHCo-D_qSqxKiQzc6KJSmivznaJRS2xY-txNIo,9039
@@ -29,18 +29,18 @@ osa/nightsummary/tests/test_source_coordinates.py,sha256=doyF2e93RnFScPbG79aUmtH
29
29
  osa/provenance/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
30
  osa/provenance/capture.py,sha256=PFN1SDU1HN4yW5Y7V5PshuS_IdoioktXCpKYWXzjH18,22348
31
31
  osa/provenance/io.py,sha256=8VAVKmE2S3YHcxwDC8PJ4hO6ogfz08EflAeprLGkp3Y,9471
32
- osa/provenance/utils.py,sha256=3LZ1dcdMShXBdhJTT1-nt27XKediYXHKQwh_XsyqLFc,8884
32
+ osa/provenance/utils.py,sha256=yohpB1XHMY9iZQGxw8rEVk_yzv77UeYWEit5GgRvUjU,8738
33
33
  osa/provenance/config/definition.yaml,sha256=DSwqNln1jEXV8aUh7ca2r7ArMkpaMJi1xbHEz0hUcao,20538
34
34
  osa/provenance/config/environment.yaml,sha256=kPM6ucPyLZLDFzkwFWoY0C6vmAArG98U-P1UAl89bgE,246
35
35
  osa/provenance/config/logger.yaml,sha256=hy_lH3DfbRFh2VM_iawI-c-3wE0cjTRHy465C2eFfnQ,510
36
36
  osa/scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
37
37
  osa/scripts/autocloser.py,sha256=j7nRvglIv_Ol_GJzbcfqPHquBIWwQU515GkDRfc6_ho,14540
38
- osa/scripts/calibration_pipeline.py,sha256=PySKtspCATdykaXclzeTkdwwvKm1CpWGlaVz44vyiCY,5625
39
- osa/scripts/closer.py,sha256=n0GRxQ6DHYykyL4FvT24Qar80-FbX6b0ymJOEez-r3c,15091
38
+ osa/scripts/calibration_pipeline.py,sha256=g9o1chqCRRSo7GNuQZRABjGnJYjZyfhkPgRLPmuV994,5703
39
+ osa/scripts/closer.py,sha256=eZLUlqot4EXwL9IlU21tKRZ2GvZ4i8ill0c2QdEkoDY,15219
40
40
  osa/scripts/copy_datacheck.py,sha256=tfDs6oTdPbii4BOXp6bTHuED0xNJeqaPFrv6Ed7ZnWc,3104
41
41
  osa/scripts/datasequence.py,sha256=gXAp8arbLPEK-sca9VnME6-2XfUzBFIoEFchlUZYrXI,9260
42
- osa/scripts/gain_selection.py,sha256=rHPqJEk9rvKRe13whOPOZEKCSF54OG0BvYyqlcBPqNQ,7776
43
- osa/scripts/provprocess.py,sha256=02vJmQvl7W3e4oAzzzSwOVo9okXLCwYPNqe6jKeaoLA,18480
42
+ osa/scripts/gain_selection.py,sha256=BmNjtfeCFw5OGymaLG1PFPDcn8-yDOG6fWaifOCOHLM,8095
43
+ osa/scripts/provprocess.py,sha256=pKR3wf3krAGmeHen_au2RmqJJtNBcX29J3XPQYKrHRE,18536
44
44
  osa/scripts/reprocess_longterm.py,sha256=wMfc3UVwickkGFiviIhOlB9ebMIqQPWoUrgg8hQ78Lg,2138
45
45
  osa/scripts/reprocessing.py,sha256=D-J8Rl3GrkWpxYkk6ci79oJOMewgGdxLkQgaHCAZuqs,3417
46
46
  osa/scripts/sequencer.py,sha256=6Cg-eIExk0eN8-HXkO6DBeFEWOI-FznDueqJEpbEzos,8163
@@ -50,34 +50,34 @@ osa/scripts/show_run_summary_tcu.py,sha256=SoDLVKdQHOJkfenFguBOfXf10Gyv7heXSQAFn
50
50
  osa/scripts/simulate_processing.py,sha256=NiRVYiwZENt_mnKncytgJT23_-tJMb1B5PswM12nnX4,6941
51
51
  osa/scripts/update_source_catalog.py,sha256=lJXYWI92YB0SrafsND4do0kjPOV_mP2MzuyMfBJbY-0,6265
52
52
  osa/scripts/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
53
- osa/scripts/tests/test_osa_scripts.py,sha256=NwUo6l4V_srnfDHJEn5hO57te0Xa47G7tF7UDw42KY4,12488
53
+ osa/scripts/tests/test_osa_scripts.py,sha256=UiUTXw5uK2iMZt7thRS1UfqoAY5b9s8k8TB143BnXcw,12587
54
54
  osa/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
55
  osa/tests/test_jobs.py,sha256=F0jsHZ9BYB_cCHHxlXyO9v1E5_-mBJhuFtshtsAtnXo,15260
56
56
  osa/tests/test_osa.py,sha256=QCOsjUgPuNMHoef3Ym2sDXVjun2LaBrfKyroAIH-os8,415
57
57
  osa/tests/test_osadb.py,sha256=pJHV1dxxblGH2sjS-JPDPTkMn-ew1MzbioCFyg7wbB8,1599
58
- osa/tests/test_paths.py,sha256=fH169s05DJTYPvOfzuHwx-37Z65TRueoyCSzssuBllc,3161
58
+ osa/tests/test_paths.py,sha256=sFCxG5uPGLcto76E7X1I26-kRx5faxgHGh9z8LvHz2M,3173
59
59
  osa/tests/test_raw.py,sha256=WkgwEc_vY0D6nREo-BSm6F-5xDpqidMC0DkS86pXlRU,1058
60
60
  osa/tests/test_report.py,sha256=OY-EsrXytoS6esfjUeLnIAmCMIw9EzoGD-elySafyhE,1365
61
61
  osa/tests/test_veto.py,sha256=UIsooji_5Z8TtAhc0UlD2VqheVd9DBufuMxinJ3e0w8,1066
62
62
  osa/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
- osa/utils/cliopts.py,sha256=9IAEhFK-RO11C3EvJ-2gch9RYBZKj5zQQRfPepY4fng,13716
63
+ osa/utils/cliopts.py,sha256=Xqh-9w2o1iSHfwO0jHEW0AXQ9VeEw6X6IGLNAPKoNyc,13699
64
64
  osa/utils/iofile.py,sha256=kJ7KB1suynhS2cTf7EeHwhMXq3delC_ls2HFpCzvsZo,2021
65
65
  osa/utils/logging.py,sha256=1WcNPjjslo3y25jcEY_fe0yXOeJ6frZrGLAy1GJpu_k,1491
66
66
  osa/utils/mail.py,sha256=uQfqPQdiOVHTvEAXr9H15a7-g9DtYVNKjMEb9GnI0oY,554
67
67
  osa/utils/register.py,sha256=bQdZeawUSoe1xdaWQ2rp7itZSlzLMuilQiRTywbcdBc,6202
68
- osa/utils/utils.py,sha256=5Yxe4LLt042-63IyPliMEZxCV_73qv0XNUZWYYuLGcI,7959
68
+ osa/utils/utils.py,sha256=KYNOln6t3J8DzZ31YjmK6TnGhHI9n3doptQTvERrUpI,7341
69
69
  osa/utils/tests/test_iofile.py,sha256=e35_EqJerp-dEOrOqwXEUZCc5P_9llf2QfveltagfIk,399
70
- osa/utils/tests/test_utils.py,sha256=ekD1p_lN85iqSZSFt6JVAlqDPI0-G5RoX7pA76qmmfE,2139
70
+ osa/utils/tests/test_utils.py,sha256=4S4OESdF3wHPOMA5A_B6Zp_O4FZKizL581SmlMUVm2I,1959
71
71
  osa/webserver/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
72
72
  osa/webserver/utils.py,sha256=ymB2wTzsFkPH4ebUcz_zK_zyolpnBzEbWGYwCvbaHf0,2155
73
73
  osa/workflow/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
74
  osa/workflow/dl3.py,sha256=kz7L5jcKHFJ--UdQ8HQKLzWO6nxc2LLOTz42ExcqzTk,9921
75
- osa/workflow/stages.py,sha256=CqyBSt3sre7dd5izKvcW4Bi9AD7GQTJS8jKHKW6SQZM,6244
75
+ osa/workflow/stages.py,sha256=WYgUM2XDIaUjCc4_Zs_VSGW6gk73EaKcHk6ZMnPds74,6692
76
76
  osa/workflow/tests/test_dl3.py,sha256=aY5bb-8OcZGAXG3JPCZihChzkA_GsWjRIa31BHZn3Dg,299
77
77
  osa/workflow/tests/test_stages.py,sha256=TmC00XFACWZp740TQeFaokWi3C50ovj_XGiySWrrdZk,3944
78
- lstosa-0.10.4.dist-info/LICENSE,sha256=h6iWot11EtMvaDaS_AvCHKLTNByO5wEbMyNj1c90y1c,1519
79
- lstosa-0.10.4.dist-info/METADATA,sha256=9XiE_4H5kKI4-1GDzgUocaCQ5i8c8EtfdfcetCiz9Mk,7220
80
- lstosa-0.10.4.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
81
- lstosa-0.10.4.dist-info/entry_points.txt,sha256=e5x7xddaqZhfdZPsErhHInqR4UGHsxXIlylEbTie0_8,928
82
- lstosa-0.10.4.dist-info/top_level.txt,sha256=_Tj8zVHdrOoWZuuWTHbDpNofxW0imUmKdlXhnxsXJek,4
83
- lstosa-0.10.4.dist-info/RECORD,,
78
+ lstosa-0.10.6.dist-info/LICENSE,sha256=h6iWot11EtMvaDaS_AvCHKLTNByO5wEbMyNj1c90y1c,1519
79
+ lstosa-0.10.6.dist-info/METADATA,sha256=Z1GxQGKizr5McPZEq-mhPLuYRmNjzLV8teV87W62kdA,7354
80
+ lstosa-0.10.6.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
81
+ lstosa-0.10.6.dist-info/entry_points.txt,sha256=e5x7xddaqZhfdZPsErhHInqR4UGHsxXIlylEbTie0_8,928
82
+ lstosa-0.10.6.dist-info/top_level.txt,sha256=_Tj8zVHdrOoWZuuWTHbDpNofxW0imUmKdlXhnxsXJek,4
83
+ lstosa-0.10.6.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: bdist_wheel (0.42.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
osa/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.10.4'
16
- __version_tuple__ = version_tuple = (0, 10, 4)
15
+ __version__ = version = '0.10.6'
16
+ __version_tuple__ = version_tuple = (0, 10, 6)
osa/configs/options.py CHANGED
@@ -16,7 +16,6 @@ warning = None
16
16
  nocheck = None
17
17
  no_dl2 = None
18
18
  prod_id = None
19
- calib_prod_id = None
20
19
  dl1_prod_id = None
21
20
  dl2_prod_id = None
22
21
  append = None
osa/configs/sequencer.cfg CHANGED
@@ -32,7 +32,6 @@ SEQUENCER_WEB_DIR: %(OSA_DIR)s/SequencerWeb
32
32
  # To be set by the user. Using PROD-ID will overcome the automatic
33
33
  # fetching of lstchain version. Otherwise leave it empty (and without the colon symbol).
34
34
  PROD_ID: v0.1.0
35
- CALIB_PROD_ID: v01
36
35
  # Change this to produce a different DL1b or DL2 sub-productions.
37
36
  # Otherwise, keep it empty to use the common PROD-ID
38
37
  DL1_PROD_ID: tailcut84
osa/conftest.py CHANGED
@@ -26,6 +26,7 @@ from osa.nightsummary.nightsummary import run_summary_table
26
26
  from osa.scripts.tests.test_osa_scripts import run_program
27
27
  from osa.utils.utils import date_to_dir
28
28
  from datetime import datetime
29
+ import lstchain
29
30
 
30
31
  date = datetime.fromisoformat("2020-01-17")
31
32
  nightdir = date_to_dir(date)
@@ -68,16 +69,25 @@ def calibration_base_dir(monitoring_dir):
68
69
  return base_dir
69
70
 
70
71
 
72
+ @pytest.fixture(scope="session")
73
+ def drive_log(monitoring_dir):
74
+ drive_dir = monitoring_dir / "DrivePositioning"
75
+ drive_file = drive_dir / "DrivePosition_log_20200117.txt"
76
+ drive_dir.mkdir(parents=True, exist_ok=True)
77
+ drive_file.touch()
78
+ return drive_file
79
+
80
+
71
81
  @pytest.fixture(scope="session")
72
82
  def calibration_dir(calibration_base_dir):
73
- directory = calibration_base_dir / "calibration" / nightdir / "pro"
83
+ directory = calibration_base_dir / "calibration" / nightdir / f"v{lstchain.__version__}"
74
84
  directory.mkdir(parents=True, exist_ok=True)
75
85
  return directory
76
86
 
77
87
 
78
88
  @pytest.fixture(scope="session")
79
89
  def drs4_baseline_dir(calibration_base_dir):
80
- directory = calibration_base_dir / "drs4_baseline" / nightdir / "pro"
90
+ directory = calibration_base_dir / "drs4_baseline" / nightdir / f"v{lstchain.__version__}"
81
91
  directory.mkdir(parents=True, exist_ok=True)
82
92
  return directory
83
93
 
osa/paths.py CHANGED
@@ -1,17 +1,19 @@
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
+ find_filter_wheels)
11
14
 
12
15
  from osa.configs import options
13
- from osa.configs.config import DEFAULT_CFG
14
- from osa.configs.config import cfg
16
+ from osa.configs.config import DEFAULT_CFG, cfg
15
17
  from osa.configs.datamodel import Sequence
16
18
  from osa.utils import utils
17
19
  from osa.utils.logging import myLogger
@@ -19,8 +21,8 @@ from osa.utils.logging import myLogger
19
21
  log = myLogger(logging.getLogger(__name__))
20
22
 
21
23
  __all__ = [
22
- "get_calibration_file",
23
- "get_drs4_pedestal_file",
24
+ "get_calibration_filename",
25
+ "get_drs4_pedestal_filename",
24
26
  "pedestal_ids_file_exists",
25
27
  "get_run_date",
26
28
  "drs4_pedestal_exists",
@@ -40,6 +42,8 @@ __all__ = [
40
42
 
41
43
 
42
44
  DATACHECK_WEB_BASEDIR = Path(cfg.get("WEBSERVER", "DATACHECK"))
45
+ CALIB_BASEDIR = Path(cfg.get("LST1", "CALIB_DIR"))
46
+ DRS4_PEDESTAL_BASEDIR = Path(cfg.get("LST1", "PEDESTAL_DIR"))
43
47
 
44
48
 
45
49
  def analysis_path(tel) -> Path:
@@ -86,18 +90,25 @@ def get_run_date(run_id: int) -> datetime:
86
90
  return datetime.strptime(date_string, "%Y-%m-%d")
87
91
 
88
92
 
89
- def get_drs4_pedestal_file(run_id: int) -> Path:
93
+ def get_drs4_pedestal_filename(run_id: int, prod_id: str) -> Path:
90
94
  """
91
95
  Return the drs4 pedestal file corresponding to a given run id
92
96
  regardless of the date when the run was taken.
93
97
  """
94
- drs4_pedestal_dir = Path(cfg.get("LST1", "PEDESTAL_DIR"))
98
+ if drs4_pedestal_exists(run_id, prod_id):
99
+ files = search_drs4_files(run_id, prod_id)
100
+ return files[-1] # Get the latest production among the major lstchain version
101
+
95
102
  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()
103
+ return (
104
+ DRS4_PEDESTAL_BASEDIR
105
+ / date
106
+ / f"v{lstchain.__version__}/drs4_pedestal.Run{run_id:05d}.0000.h5"
107
+ ).resolve()
98
108
 
99
109
 
100
- def get_calibration_file(run_id: int) -> Path:
110
+ def get_calibration_filename(run_id: int, prod_id: str) -> Path:
111
+ # sourcery skip: remove-unnecessary-cast
101
112
  """
102
113
  Return the calibration file corresponding to a given run_id.
103
114
 
@@ -109,14 +120,18 @@ def get_calibration_file(run_id: int) -> Path:
109
120
  Notes
110
121
  -----
111
122
  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
123
+ We follow the naming convention of the calibration files produced by the
124
+ lstchain script which depends on the filter wheels position. Therefore, we
125
+ need to try to fetch the filter position from the CaCo database. If the
126
+ filter position is not found, we assume the default filter position 5-2.
127
+ Filter information is not available in the database for runs taken before
116
128
  mid 2021 approx.
117
129
  """
118
130
 
119
- calib_dir = Path(cfg.get("LST1", "CALIB_DIR"))
131
+ if calibration_file_exists(run_id, prod_id):
132
+ files = search_calibration_files(run_id, prod_id)
133
+ return files[-1] # Get the latest production among the major lstchain version
134
+
120
135
  date = utils.date_to_dir(get_run_date(run_id))
121
136
 
122
137
  if options.test: # Run tests avoiding the access to the database
@@ -126,13 +141,16 @@ def get_calibration_file(run_id: int) -> Path:
126
141
  mongodb = cfg.get("database", "caco_db")
127
142
  try:
128
143
  # Cast run_id to int to avoid problems with numpy int64 encoding in MongoDB
129
- options.filters = search_filter(int(run_id), mongodb)
144
+ options.filters = find_filter_wheels(int(run_id), mongodb)
130
145
  except IOError:
131
146
  log.warning("No filter information found in database. Assuming positions 52.")
132
147
  options.filters = 52
133
148
 
134
- file = calib_dir / date / f"pro/calibration_filters_{options.filters}.Run{run_id:05d}.0000.h5"
135
- return file.resolve()
149
+ return (
150
+ CALIB_BASEDIR
151
+ / date
152
+ / f"v{lstchain.__version__}/calibration_filters_{options.filters}.Run{run_id:05d}.0000.h5"
153
+ ).resolve()
136
154
 
137
155
 
138
156
  def pedestal_ids_file_exists(run_id: int) -> bool:
@@ -142,16 +160,51 @@ def pedestal_ids_file_exists(run_id: int) -> bool:
142
160
  return bool(file_list)
143
161
 
144
162
 
145
- def drs4_pedestal_exists(run_id: int) -> bool:
163
+ def drs4_pedestal_exists(run_id: int, prod_id: str) -> bool:
146
164
  """Return true if drs4 pedestal file was already produced."""
147
- file = get_drs4_pedestal_file(run_id)
148
- return file.exists()
165
+ files = search_drs4_files(run_id, prod_id)
166
+
167
+ return len(files) != 0
149
168
 
150
169
 
151
- def calibration_file_exists(run_id: int) -> bool:
170
+ def calibration_file_exists(run_id: int, prod_id: str) -> bool:
152
171
  """Return true if calibration file was already produced."""
153
- file = get_calibration_file(run_id)
154
- return file.exists()
172
+ files = search_calibration_files(run_id, prod_id)
173
+
174
+ return len(files) != 0
175
+
176
+
177
+ def search_drs4_files(run_id: int, prod_id: str) -> list:
178
+ """
179
+ Find DRS4 baseline correction files corresponding to a run ID
180
+ and major lstchain production version
181
+ """
182
+ date = utils.date_to_dir(get_run_date(run_id))
183
+ version = get_major_version(prod_id)
184
+ drs4_dir = DRS4_PEDESTAL_BASEDIR / date
185
+ return sorted(
186
+ drs4_dir.glob(f"{version}*/drs4_pedestal.Run{run_id:05d}.0000.h5")
187
+ )
188
+
189
+
190
+ def get_major_version(prod_id):
191
+ """Given a version as vX.Y.Z return vX.Y"""
192
+ # First check that the given version is in the correct format
193
+ if prod_id.startswith("v") and len(prod_id.split(".")) >= 2:
194
+ return re.search(r"\D\d+\.\d+", prod_id)[0]
195
+
196
+ raise ValueError("Format of the version is not in the form vW.X.Y.Z")
197
+
198
+
199
+ def search_calibration_files(run_id: int, prod_id: str) -> list:
200
+ """
201
+ Search charge calibration files corresponding to a run ID and major lstchain production version
202
+ """
203
+ date = utils.date_to_dir(get_run_date(run_id))
204
+ version = get_major_version(prod_id)
205
+ return sorted(
206
+ (CALIB_BASEDIR / date).glob(f"{version}*/calibration_filters_*.Run{run_id:05d}.0000.h5")
207
+ )
155
208
 
156
209
 
157
210
  def get_drive_file(date: str) -> Path:
@@ -180,11 +233,16 @@ def sequence_calibration_files(sequence_list: List[Sequence]) -> None:
180
233
  """Build names of the calibration files for each sequence in the list."""
181
234
  flat_date = utils.date_to_dir(options.date)
182
235
  base_dir = Path(cfg.get("LST1", "BASE"))
236
+ prod_id = options.prod_id
183
237
 
184
238
  for sequence in sequence_list:
185
239
  # 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)
240
+ sequence.drs4_file = get_drs4_pedestal_filename(
241
+ sequence.drs4_run, prod_id
242
+ )
243
+ sequence.calibration_file = get_calibration_filename(
244
+ sequence.pedcal_run, prod_id
245
+ )
188
246
  sequence.time_calibration_file = find_time_calibration_file(
189
247
  "pro", sequence.pedcal_run, base_dir=base_dir
190
248
  )
@@ -235,10 +293,7 @@ def destination_dir(concept: str, create_dir: bool = True) -> Path:
235
293
  directory = Path(cfg.get(options.tel_id, "DL1_DIR")) / nightdir / options.prod_id / "muons"
236
294
  elif concept == "INTERLEAVED":
237
295
  directory = (
238
- Path(cfg.get(options.tel_id, "DL1_DIR"))
239
- / nightdir
240
- / options.prod_id
241
- / "interleaved"
296
+ Path(cfg.get(options.tel_id, "DL1_DIR")) / nightdir / options.prod_id / "interleaved"
242
297
  )
243
298
  elif concept == "DATACHECK":
244
299
  directory = (
@@ -257,17 +312,21 @@ def destination_dir(concept: str, create_dir: bool = True) -> Path:
257
312
  )
258
313
  elif concept in {"DL2", "DL3"}:
259
314
  directory = (
260
- Path(cfg.get(options.tel_id, concept + "_DIR"))
261
- / nightdir
315
+ (Path(cfg.get(options.tel_id, f"{concept}_DIR")) / nightdir)
262
316
  / options.prod_id
263
- / options.dl2_prod_id
264
- )
317
+ ) / options.dl2_prod_id
265
318
  elif concept in {"PEDESTAL", "CALIB", "TIMECALIB"}:
266
319
  directory = (
267
- Path(cfg.get(options.tel_id, concept + "_DIR")) / nightdir / options.calib_prod_id
320
+ Path(cfg.get(options.tel_id, f"{concept}_DIR"))
321
+ / nightdir
322
+ / options.prod_id
268
323
  )
269
324
  elif concept == "HIGH_LEVEL":
270
- directory = Path(cfg.get(options.tel_id, concept + "_DIR")) / nightdir / options.prod_id
325
+ directory = (
326
+ Path(cfg.get(options.tel_id, f"{concept}_DIR"))
327
+ / nightdir
328
+ / options.prod_id
329
+ )
271
330
  else:
272
331
  log.warning(f"Concept {concept} not known")
273
332
  directory = None
osa/provenance/utils.py CHANGED
@@ -1,7 +1,6 @@
1
1
  """Utility functions for OSA pipeline provenance."""
2
2
 
3
3
 
4
- import os
5
4
  from importlib.resources import files
6
5
  from pathlib import Path
7
6
 
@@ -27,10 +26,11 @@ def parse_variables(class_instance):
27
26
  # datasequence.py
28
27
  # -c sequencer.cfg
29
28
  # -d 2020_02_18
30
- # --prod-id v0.4.3_v00
31
- # --pedcal-file .../20200218/pro/calibration_filters_52.Run02006.0000.h5
32
- # --drs4-pedestal-file .../20200218/pro/drs4_pedestal.Run02005.0000.h5
29
+ # --prod-id v0.4
30
+ # --pedcal-file .../20200218/v0.4.3/calibration_filters_52.Run02006.0000.h5
31
+ # --drs4-pedestal-file .../20200218/v0.4.3/drs4_pedestal.Run02005.0000.h5
33
32
  # --time-calib-file .../20191124/pro/time_calibration.Run01625.0000.h5
33
+ # --systematic_correction_file .../20200725/pro/ffactor_systematics_20200725.h5
34
34
  # --drive-file .../DrivePositioning/DrivePosition_20200218.txt
35
35
  # --run-summary .../monitoring/RunSummary/RunSummary_20200101.ecsv
36
36
  # 02006.0000
@@ -39,22 +39,20 @@ def parse_variables(class_instance):
39
39
  flat_date = date_to_dir(options.date)
40
40
  configfile_dl1b = cfg.get("lstchain", "dl1b_config")
41
41
  configfile_dl2 = cfg.get("lstchain", "dl2_config")
42
- raw_dir = cfg.get("LST1", "R0_DIR")
43
- rf_models_directory = cfg.get("lstchain", "RF_MODELS")
44
- dl1_dir = cfg.get("LST1", "DL1_DIR")
45
- dl2_dir = cfg.get("LST1", "DL2_DIR")
46
- calib_dir = cfg.get("LST1", "CALIB_DIR")
47
- pedestal_dir = cfg.get("LST1", "PEDESTAL_DIR")
48
- # summary_dir = cfg.get("LST1", "RUN_SUMMARY_DIR")
49
- # calib_base_dir = cfg.get("LST1", "CALIB_BASE_DIR")
50
- # sys_dir = calib_base_dir / "ffactor_systematics"
42
+ raw_dir = Path(cfg.get("LST1", "R0_DIR"))
43
+ rf_models_directory = Path(cfg.get("lstchain", "RF_MODELS"))
44
+ dl1_dir = Path(cfg.get("LST1", "DL1_DIR"))
45
+ dl2_dir = Path(cfg.get("LST1", "DL2_DIR"))
46
+ calib_dir = Path(cfg.get("LST1", "CALIB_DIR"))
47
+ pedestal_dir = Path(cfg.get("LST1", "PEDESTAL_DIR"))
48
+
51
49
  class_instance.SoftwareVersion = get_lstchain_version()
52
- class_instance.ProcessingConfigFile = options.configfile
50
+ class_instance.ProcessingConfigFile = str(options.configfile)
53
51
  class_instance.ObservationDate = flat_date
54
52
  if class_instance.__name__ in REDUCTION_TASKS:
55
- muon_dir = Path(dl1_dir) / flat_date / options.prod_id
56
- outdir_dl1 = Path(dl1_dir) / flat_date / options.prod_id / options.dl1_prod_id
57
- outdir_dl2 = Path(dl2_dir) / flat_date / options.prod_id / options.dl2_prod_id
53
+ muon_dir = dl1_dir / flat_date / options.prod_id / "muons"
54
+ outdir_dl1 = dl1_dir / flat_date / options.prod_id / options.dl1_prod_id
55
+ outdir_dl2 = dl2_dir / flat_date / options.prod_id / options.dl2_prod_id
58
56
 
59
57
  if class_instance.__name__ in ["drs4_pedestal", "calibrate_charge"]:
60
58
  # drs4_pedestal_run_id [0] 1804
@@ -63,123 +61,133 @@ def parse_variables(class_instance):
63
61
  class_instance.PedestalRun = f"{class_instance.args[0]:05d}"
64
62
  class_instance.CalibrationRun = f"{class_instance.args[1]:05d}"
65
63
 
66
- pro = "pro"
67
- # TODO - massive reprocessing vs. next day processing
64
+ version = get_lstchain_version()
68
65
 
69
66
  # according to code in onsite scripts in lstchain
70
- class_instance.RawObservationFilePedestal = os.path.realpath(
71
- f"{raw_dir}/{flat_date}/LST-1.1.Run{class_instance.args[0]:05d}.fits.fz"
72
- )
73
- class_instance.RawObservationFileCalibration = os.path.realpath(
74
- f"{raw_dir}/{flat_date}/LST-1.1.Run{class_instance.args[1]:05d}.fits.fz"
75
- )
76
- class_instance.PedestalCheckPlot = os.path.realpath(
77
- f"{pedestal_dir}/{flat_date}/{pro}/"
78
- f"log/drs4_pedestal.Run{class_instance.args[0]:05d}.0000.pdf"
79
- )
80
- class_instance.CalibrationCheckPlot = os.path.realpath(
81
- f"{calib_dir}/{flat_date}/{pro}/"
82
- f"log/calibration_filters_52.Run{class_instance.args[1]:05d}.0000.pdf"
83
- )
67
+ class_instance.RawObservationFilePedestal = str((
68
+ raw_dir / flat_date / f"LST-1.1.Run{class_instance.args[0]:05d}.fits.fz"
69
+ ).resolve())
70
+ class_instance.RawObservationFileCalibration = str((
71
+ raw_dir / flat_date / f"LST-1.1.Run{class_instance.args[1]:05d}.fits.fz"
72
+ ).resolve())
73
+ class_instance.PedestalCheckPlot = str((
74
+ pedestal_dir
75
+ / flat_date
76
+ / version
77
+ / f"log/drs4_pedestal.Run{class_instance.args[0]:05d}.0000.pdf"
78
+ ).resolve())
79
+ class_instance.CalibrationCheckPlot = str((
80
+ calib_dir
81
+ / flat_date
82
+ / version
83
+ / f"log/calibration_filters_52.Run{class_instance.args[1]:05d}.0000.pdf"
84
+ ).resolve())
84
85
 
85
86
  # according to code in sequence_calibration_files from paths.py
86
- class_instance.PedestalFile = os.path.realpath(
87
- f"{pedestal_dir}/{flat_date}/{pro}/"
88
- f"drs4_pedestal.Run{class_instance.args[0]:05d}.0000.h5"
89
- )
90
- class_instance.CoefficientsCalibrationFile = os.path.realpath(
91
- f"{calib_dir}/{flat_date}/{pro}/"
92
- f"calibration_filters_52.Run{class_instance.args[1]:05d}.0000.h5"
93
- )
87
+ class_instance.PedestalFile = str((
88
+ pedestal_dir
89
+ / flat_date
90
+ / version
91
+ / f"drs4_pedestal.Run{class_instance.args[0]:05d}.0000.h5"
92
+ ).resolve())
93
+ class_instance.CoefficientsCalibrationFile = str((
94
+ calib_dir
95
+ / flat_date
96
+ / version
97
+ / f"calibration_filters_52.Run{class_instance.args[1]:05d}.0000.h5"
98
+ ).resolve())
94
99
 
95
100
  if class_instance.__name__ == "r0_to_dl1":
96
- # calibration_file [0] .../20200218/pro/calibration_filters_52.Run02006.0000.h5
97
- # drs4_pedestal_file [1] .../20200218/pro/drs4_pedestal.Run02005.0000.h5
98
- # time_calib_file [2] .../20191124/pro/time_calibration.Run01625.0000.h5
99
- # systematic_corr [3] .../20200101/pro/no_sys_corrected_calib_20210514.0000.h5
101
+ # calibration_file [0] .../20200218/v0.4.3/calibration_filters_52.Run02006.0000.h5
102
+ # drs4_pedestal_file [1] .../20200218/v0.4.3/drs4_pedestal.Run02005.0000.h5
103
+ # time_calib_file [2] .../20191124/v0.4.3/time_calibration.Run01625.0000.h5
104
+ # systematic_corr [3] .../20200101/v0.4.3/no_sys_corrected_calib_20210514.0000.h5
100
105
  # drive_file [4] .../DrivePositioning/DrivePosition_20200218.txt
101
106
  # run_summary_file [5] .../RunSummary/RunSummary_20200101.ecsv
102
107
  # pedestal_ids_file [6] .../path/to/interleaved/pedestal/events.h5
103
108
  # run_str [7] 02006.0000
104
109
 
105
- run_subrun_id = class_instance.args[7]
106
- class_instance.ObservationRun = run_subrun_id.split(".")[0]
107
- # use realpath to resolve symbolic links and return abspath
108
- calibration_file = os.path.realpath(class_instance.args[0])
109
- pedestal_file = os.path.realpath(class_instance.args[1])
110
- timecalibration_file = os.path.realpath(class_instance.args[2])
111
- systematic_correction_file = os.path.realpath(class_instance.args[3])
112
- class_instance.R0SubrunDataset = os.path.realpath(
113
- f"{raw_dir}/{flat_date}/LST-1.1.Run{run_subrun_id}.fits.fz"
114
- )
115
- class_instance.CoefficientsCalibrationFile = calibration_file
116
- class_instance.PedestalFile = pedestal_file
117
- class_instance.TimeCalibrationFile = timecalibration_file
118
- class_instance.SystematicCorrectionFile = systematic_correction_file
119
- class_instance.PointingFile = os.path.realpath(class_instance.args[4])
120
- class_instance.RunSummaryFile = os.path.realpath(class_instance.args[5])
121
- class_instance.DL1SubrunDataset = os.path.realpath(
122
- f"{outdir_dl1}/dl1_LST-1.Run{run_subrun_id}.h5"
123
- )
124
- class_instance.MuonsSubrunDataset = os.path.realpath(
125
- f"{muon_dir}/muons_LST-1.Run{run_subrun_id}.fits"
126
- )
110
+ run_subrun = class_instance.args[7]
111
+ run = run_subrun.split(".")[0]
112
+ class_instance.ObservationRun = run
113
+
114
+ calibration_file = Path(class_instance.args[0]).resolve()
115
+ pedestal_file = Path(class_instance.args[1]).resolve()
116
+ timecalibration_file = Path(class_instance.args[2]).resolve()
117
+ systematic_correction_file = Path(class_instance.args[3]).resolve()
118
+ class_instance.R0SubrunDataset = str((
119
+ raw_dir / flat_date / f"LST-1.1.Run{run_subrun}.fits.fz"
120
+ ).resolve())
121
+ class_instance.CoefficientsCalibrationFile = str(calibration_file)
122
+ class_instance.PedestalFile = str(pedestal_file)
123
+ class_instance.TimeCalibrationFile = str(timecalibration_file)
124
+ class_instance.SystematicCorrectionFile = str(systematic_correction_file)
125
+ class_instance.PointingFile = str(Path(class_instance.args[4]).resolve())
126
+ class_instance.RunSummaryFile = str(Path(class_instance.args[5]).resolve())
127
+ class_instance.DL1SubrunDataset = str(
128
+ (outdir_dl1 / f"dl1_LST-1.Run{run_subrun}.h5").resolve()
129
+ )
130
+ class_instance.MuonsSubrunDataset = str((
131
+ muon_dir / f"muons_LST-1.Run{run_subrun}.fits"
132
+ ).resolve())
127
133
  class_instance.InterleavedPedestalEventsFile = None
128
134
  if class_instance.args[6] is not None:
129
- class_instance.InterleavedPedestalEventsFile = os.path.realpath(class_instance.args[6])
135
+ class_instance.InterleavedPedestalEventsFile = str(Path(class_instance.args[6]))
130
136
 
131
137
  if class_instance.__name__ == "dl1ab":
132
138
  # run_str [0] 02006.0000
133
139
 
134
- class_instance.Analysisconfigfile_dl1 = os.path.realpath(configfile_dl1b)
140
+ class_instance.Analysisconfigfile_dl1 = str(Path(configfile_dl1b))
135
141
  class_instance.ObservationRun = class_instance.args[0].split(".")[0]
136
142
  class_instance.StoreImage = cfg.getboolean("lstchain", "store_image_dl1ab")
137
- class_instance.DL1SubrunDataset = os.path.realpath(
138
- f"{outdir_dl1}/dl1_LST-1.Run{class_instance.args[0]}.h5"
139
- )
143
+ class_instance.DL1SubrunDataset = str((
144
+ outdir_dl1 / f"dl1_LST-1.Run{class_instance.args[0]}.h5"
145
+ ).resolve())
140
146
 
141
147
  if class_instance.__name__ == "dl1_datacheck":
142
148
  # run_str [0] 02006.0000
143
-
144
- class_instance.ObservationRun = class_instance.args[0].split(".")[0]
145
- class_instance.DL1SubrunDataset = os.path.realpath(
146
- f"{outdir_dl1}/dl1_LST-1.Run{class_instance.args[0]}.h5"
147
- )
148
- class_instance.MuonsSubrunDataset = os.path.realpath(
149
- f"{muon_dir}/muons_LST-1.Run{class_instance.args[0]}.fits"
150
- )
151
- class_instance.DL1CheckSubrunDataset = os.path.realpath(
152
- f"{outdir_dl1}/datacheck_dl1_LST-1.Run{class_instance.args[0]}.h5"
153
- )
154
- class_instance.DL1CheckHDF5File = os.path.realpath(
155
- f"{outdir_dl1}/datacheck_dl1_LST-1.Run{class_instance.ObservationRun}.h5"
156
- )
157
- class_instance.DL1CheckPDFFile = os.path.realpath(
158
- f"{outdir_dl1}/datacheck_dl1_LST-1.Run{class_instance.ObservationRun}.pdf"
159
- )
149
+ run_subrun = class_instance.args[0]
150
+ run = run_subrun.split(".")[0]
151
+
152
+ class_instance.ObservationRun = run
153
+ class_instance.DL1SubrunDataset = str(
154
+ (outdir_dl1 / f"dl1_LST-1.Run{run_subrun}.h5").resolve()
155
+ )
156
+ class_instance.MuonsSubrunDataset = str((
157
+ muon_dir / f"muons_LST-1.Run{run_subrun}.fits"
158
+ ).resolve())
159
+ class_instance.DL1CheckSubrunDataset = str((
160
+ outdir_dl1 / f"datacheck_dl1_LST-1.Run{run_subrun}.h5"
161
+ ).resolve())
162
+ class_instance.DL1CheckHDF5File = str((
163
+ outdir_dl1 / f"datacheck_dl1_LST-1.Run{run}.h5"
164
+ ).resolve())
165
+ class_instance.DL1CheckPDFFile = str((
166
+ outdir_dl1 / f"datacheck_dl1_LST-1.Run{run}.pdf"
167
+ ).resolve())
160
168
 
161
169
  if class_instance.__name__ == "dl1_to_dl2":
162
170
  # run_str [0] 02006.0000
171
+ run_subrun = class_instance.args[0]
172
+ run = run_subrun.split(".")[0]
163
173
 
164
174
  class_instance.Analysisconfigfile_dl2 = configfile_dl2
165
- class_instance.ObservationRun = class_instance.args[0].split(".")[0]
166
- class_instance.RFModelEnergyFile = os.path.realpath(f"{rf_models_directory}/reg_energy.sav")
167
- class_instance.RFModelDispNormFile = os.path.realpath(
168
- f"{rf_models_directory}/reg_disp_norm.sav"
169
- )
170
- class_instance.RFModelDispSignFile = os.path.realpath(
171
- f"{rf_models_directory}/reg_disp_sign.sav"
175
+ class_instance.ObservationRun = run
176
+ class_instance.RFModelEnergyFile = str((rf_models_directory / "reg_energy.sav").resolve())
177
+ class_instance.RFModelDispNormFile = str(
178
+ (rf_models_directory / "reg_disp_norm.sav").resolve()
172
179
  )
173
- class_instance.RFModelGammanessFile = os.path.realpath(f"{rf_models_directory}/cls_gh.sav")
174
- class_instance.DL1SubrunDataset = os.path.realpath(
175
- f"{outdir_dl1}/dl1_LST-1.Run{class_instance.args[0]}.h5"
180
+ class_instance.RFModelDispSignFile = str(
181
+ (rf_models_directory / "reg_disp_sign.sav").resolve()
176
182
  )
177
- class_instance.DL2SubrunDataset = os.path.realpath(
178
- f"{outdir_dl2}/dl2_LST-1.Run{class_instance.args[0]}.h5"
183
+ class_instance.RFModelGammanessFile = str((rf_models_directory / "cls_gh.sav").resolve())
184
+ class_instance.DL1SubrunDataset = str(
185
+ (outdir_dl1 / f"dl1_LST-1.Run{run_subrun}.h5").resolve()
179
186
  )
180
- class_instance.DL2MergedFile = os.path.realpath(
181
- f"{outdir_dl2}/dl2_LST-1.Run{class_instance.ObservationRun}.h5"
187
+ class_instance.DL2SubrunDataset = str(
188
+ (outdir_dl2 / f"dl2_LST-1.Run{run_subrun}.h5").resolve()
182
189
  )
190
+ class_instance.DL2MergedFile = str((outdir_dl2 / f"dl2_LST-1.Run{run}.h5").resolve())
183
191
 
184
192
  if class_instance.__name__ in REDUCTION_TASKS:
185
193
  class_instance.session_name = class_instance.ObservationRun
@@ -189,5 +197,5 @@ def parse_variables(class_instance):
189
197
 
190
198
  def get_log_config():
191
199
  """Get logging configuration from provenance logger config file."""
192
- std_logger_file = files("osa.provenance").joinpath("config/logger.yaml")
200
+ std_logger_file = files("osa.provenance") / "config/logger.yaml"
193
201
  return std_logger_file.read_text()
@@ -37,7 +37,8 @@ def is_calibration_produced(drs4_pedestal_run_id: int, pedcal_run_id: int) -> bo
37
37
  Check if both daily calibration (DRS4 baseline and
38
38
  charge calibration) files are already produced.
39
39
  """
40
- return drs4_pedestal_exists(drs4_pedestal_run_id) and calibration_file_exists(pedcal_run_id)
40
+ return drs4_pedestal_exists(drs4_pedestal_run_id, options.prod_id) \
41
+ and calibration_file_exists(pedcal_run_id, options.prod_id)
41
42
 
42
43
 
43
44
  def drs4_pedestal_command(drs4_pedestal_run_id: int) -> list:
@@ -122,7 +123,7 @@ def drs4_pedestal(
122
123
  rc : int
123
124
  Return code
124
125
  """
125
- if options.simulate or drs4_pedestal_exists(drs4_pedestal_run_id):
126
+ if options.simulate or drs4_pedestal_exists(drs4_pedestal_run_id, options.prod_id):
126
127
  return 0
127
128
 
128
129
  cmd = drs4_pedestal_command(drs4_pedestal_run_id)
@@ -154,7 +155,7 @@ def calibrate_charge(
154
155
  rc: int
155
156
  Return code
156
157
  """
157
- if options.simulate or calibration_file_exists(pedcal_run_id):
158
+ if options.simulate or calibration_file_exists(pedcal_run_id, options.prod_id):
158
159
  return 0
159
160
 
160
161
  cmd = calibration_file_command(
osa/scripts/closer.py CHANGED
@@ -193,7 +193,6 @@ def post_process_files(seq_list: list):
193
193
  output_files_set = set(Path(options.directory).rglob("*Run*"))
194
194
 
195
195
  DL1AB_RE = re.compile(rf"{options.dl1_prod_id}/dl1.*.(?:h5|hdf5|hdf)")
196
- DL2_RE = re.compile(f"{options.dl2_prod_id}/dl2.*.(?:h5|hdf5|hdf)")
197
196
  MUONS_RE = re.compile(r"muons.*.fits")
198
197
  DATACHECK_RE = re.compile(r"datacheck_dl1.*.(?:h5|hdf5|hdf)")
199
198
  INTERLEAVED_RE = re.compile(r"interleaved.*.(?:h5|hdf5|hdf)")
@@ -201,13 +200,16 @@ def post_process_files(seq_list: list):
201
200
  pattern_files = dict(
202
201
  [
203
202
  ("DL1AB", DL1AB_RE),
204
- ("DL2", DL2_RE),
205
203
  ("MUON", MUONS_RE),
206
204
  ("DATACHECK", DATACHECK_RE),
207
205
  ("INTERLEAVED", INTERLEAVED_RE),
208
206
  ]
209
207
  )
210
208
 
209
+ if not options.no_dl2:
210
+ DL2_RE = re.compile(f"{options.dl2_prod_id}/dl2.*.(?:h5|hdf5|hdf)")
211
+ pattern_files["DL2"] = DL2_RE
212
+
211
213
  for concept, pattern_re in pattern_files.items():
212
214
  log.info(f"Post processing {concept} files, {len(output_files_set)} files left")
213
215
 
@@ -368,6 +370,9 @@ def extract_provenance(seq_list):
368
370
  nightdir,
369
371
  options.prod_id,
370
372
  ]
373
+ if options.no_dl2:
374
+ cmd.append("--no-dl2")
375
+
371
376
  if not options.simulate and not options.test and shutil.which("sbatch") is not None:
372
377
  subprocess.run(cmd, check=True)
373
378
  else:
@@ -41,7 +41,7 @@ def get_sbatch_script(
41
41
  )
42
42
 
43
43
 
44
- def apply_gain_selection(date: str, output_basedir: Path = None):
44
+ def apply_gain_selection(date: str, start: int, end: int, output_basedir: Path = None):
45
45
  """
46
46
  Submit the jobs to apply the gain selection to the data for a given date
47
47
  on a subrun-by-subrun basis.
@@ -64,7 +64,7 @@ def apply_gain_selection(date: str, output_basedir: Path = None):
64
64
  check_job_status_and_wait(max_jobs=1500)
65
65
 
66
66
  # Avoid running jobs while it is still night time
67
- wait_for_daytime(start=12, end=18)
67
+ wait_for_daytime(start, end)
68
68
 
69
69
  run_id = run["run_id"]
70
70
  ref_time = run["dragon_reference_time"]
@@ -121,7 +121,7 @@ def apply_gain_selection(date: str, output_basedir: Path = None):
121
121
 
122
122
  for run in calib_runs:
123
123
  # Avoid copying files while it is still night time
124
- wait_for_daytime(start=12, end=18)
124
+ wait_for_daytime(start, end)
125
125
 
126
126
  run_id = run["run_id"]
127
127
  r0_files = r0_dir.glob(f"LST-1.?.Run{run_id:05d}.????.fits.fz")
@@ -206,7 +206,15 @@ def check_failed_jobs(date: str, output_basedir: Path = None):
206
206
  @click.option("--check", is_flag=True, default=False, help="Check for failed jobs.")
207
207
  @click.argument("dates-file", type=click.Path(exists=True, path_type=Path))
208
208
  @click.argument("output-basedir", type=click.Path(path_type=Path))
209
- def main(dates_file: Path = None, output_basedir: Path = None, check: bool = False):
209
+ @click.option("-s", "--start-time", type=int, default=10, help="Time to (re)start gain selection in HH format.")
210
+ @click.option("-e", "--end-time", type=int, default=18, help="Time to stop gain selection in HH format.")
211
+ def main(
212
+ dates_file: Path = None,
213
+ output_basedir: Path = None,
214
+ check: bool = False,
215
+ start_time: int = 10,
216
+ end_time: int = 18
217
+ ):
210
218
  """
211
219
  Loop over the dates listed in the input file and launch the gain selection
212
220
  script for each of them. The input file should list the dates in the format
@@ -221,7 +229,7 @@ def main(dates_file: Path = None, output_basedir: Path = None, check: bool = Fal
221
229
  check_failed_jobs(date, output_basedir)
222
230
  else:
223
231
  for date in list_of_dates:
224
- apply_gain_selection(date, output_basedir)
232
+ apply_gain_selection(date, start_time, end_time, output_basedir)
225
233
  log.info("Done! No more dates to process.")
226
234
 
227
235
 
@@ -442,15 +442,17 @@ def produce_provenance(session_log_filename, base_filename):
442
442
  calibration_to_dl1 = define_paths(
443
443
  "calibration_to_dl1", PATH_DL1, options.dl1_prod_id, base_filename
444
444
  )
445
- calibration_to_dl2 = define_paths(
446
- "calibration_to_dl2", PATH_DL2, options.dl2_prod_id, base_filename
447
- )
448
445
  calibration_to_dl1_lines = calibration_lines + dl1_lines[1:]
449
446
  lines_dl1 = copy.deepcopy(calibration_to_dl1_lines)
450
- calibration_to_dl2_lines = calibration_to_dl1_lines + dl1_dl2_lines[1:]
451
- lines_dl2 = copy.deepcopy(calibration_to_dl2_lines)
452
447
  produce_provenance_files(lines_dl1, calibration_to_dl1)
453
- produce_provenance_files(lines_dl2, calibration_to_dl2)
448
+
449
+ if not options.no_dl2:
450
+ calibration_to_dl2 = define_paths(
451
+ "calibration_to_dl2", PATH_DL2, options.dl2_prod_id, base_filename
452
+ )
453
+ calibration_to_dl2_lines = calibration_to_dl1_lines + dl1_dl2_lines[1:]
454
+ lines_dl2 = copy.deepcopy(calibration_to_dl2_lines)
455
+ produce_provenance_files(lines_dl2, calibration_to_dl2)
454
456
 
455
457
 
456
458
  def main():
@@ -63,6 +63,7 @@ def test_simulate_processing(
63
63
  run_summary_file,
64
64
  r0_data,
65
65
  merged_run_summary,
66
+ drive_log
66
67
  ):
67
68
 
68
69
  for file in drs4_time_calibration_files:
@@ -75,6 +76,8 @@ def test_simulate_processing(
75
76
  assert r0_file.exists()
76
77
 
77
78
  assert run_summary_file.exists()
79
+ assert merged_run_summary.exists()
80
+ assert drive_log.exists()
78
81
 
79
82
  remove_provlog()
80
83
  rc = run_program("simulate_processing", "-p", "--force")
@@ -257,7 +260,7 @@ def test_datasequence(running_analysis_dir):
257
260
 
258
261
 
259
262
  def test_calibration_pipeline(running_analysis_dir):
260
- prod_id = "v0.1.0"
263
+ options.prod_id = "v0.1.0"
261
264
  drs4_run_number = "01804"
262
265
  pedcal_run_number = "01805"
263
266
  options.directory = running_analysis_dir
@@ -266,7 +269,7 @@ def test_calibration_pipeline(running_analysis_dir):
266
269
  "calibration_pipeline",
267
270
  "--date=2020-01-17",
268
271
  "--simulate",
269
- f"--prod-id={prod_id}",
272
+ f"--prod-id={options.prod_id}",
270
273
  f"--drs4-pedestal-run={drs4_run_number}",
271
274
  f"--pedcal-run={pedcal_run_number}",
272
275
  "LST1",
osa/tests/test_paths.py CHANGED
@@ -6,23 +6,24 @@ from osa.configs.config import cfg
6
6
  from osa.utils.utils import date_to_dir
7
7
 
8
8
  options.date = datetime.fromisoformat("2020-01-17")
9
+ options.prod_id = "v0.1.1"
9
10
 
10
11
 
11
12
  def test_get_calibration_file(r0_data, merged_run_summary):
12
- from osa.paths import get_calibration_file
13
+ from osa.paths import get_calibration_filename
13
14
 
14
15
  for file in r0_data:
15
16
  assert file.exists()
16
- file = get_calibration_file(1809)
17
+ file = get_calibration_filename(1809, options.prod_id)
17
18
  file.exists()
18
19
 
19
20
 
20
21
  def test_get_drs4_pedestal_file(r0_data, merged_run_summary):
21
- from osa.paths import get_drs4_pedestal_file
22
+ from osa.paths import get_drs4_pedestal_filename
22
23
 
23
24
  for file in r0_data:
24
25
  assert file.exists()
25
- file = get_drs4_pedestal_file(1804)
26
+ file = get_drs4_pedestal_filename(1804, options.prod_id)
26
27
  file.exists()
27
28
 
28
29
 
@@ -58,6 +59,7 @@ def test_destination_dir():
58
59
  base_path = Path(base_directory)
59
60
 
60
61
  data_types = {
62
+ "INTERLEAVED": "DL1",
61
63
  "DL1AB": "DL1",
62
64
  "DATACHECK": "DL1",
63
65
  "MUON": "DL1",
@@ -86,8 +88,6 @@ def test_destination_dir():
86
88
  expected_directory = (
87
89
  base_path / dst_dir / datedir / options.prod_id / options.dl2_prod_id
88
90
  )
89
- else:
90
- expected_directory = base_path / dst_dir / datedir / options.prod_id
91
91
 
92
92
  assert directory == expected_directory
93
93
 
osa/utils/cliopts.py CHANGED
@@ -10,7 +10,6 @@ from osa.configs.config import cfg
10
10
  from osa.paths import analysis_path, DEFAULT_CFG
11
11
  from osa.utils.logging import myLogger
12
12
  from osa.utils.utils import (
13
- get_calib_prod_id,
14
13
  get_dl1_prod_id,
15
14
  get_dl2_prod_id,
16
15
  get_prod_id,
@@ -35,7 +34,6 @@ __all__ = [
35
34
  "get_prod_id",
36
35
  "get_dl1_prod_id",
37
36
  "get_dl2_prod_id",
38
- "get_calib_prod_id",
39
37
  "calibration_pipeline_cliparsing",
40
38
  "calibration_pipeline_argparser",
41
39
  "autocloser_cli_parser",
@@ -171,10 +169,7 @@ def calibration_pipeline_cliparsing():
171
169
  # setting the default date and directory if needed
172
170
  options.date = set_default_date_if_needed()
173
171
  options.directory = analysis_path(options.tel_id)
174
- if cfg.get("LST1", "CALIB_PROD_ID") is not None:
175
- options.calib_prod_id = get_calib_prod_id()
176
- else:
177
- options.calib_prod_id = options.prod_id
172
+
178
173
  return opts.drs4_pedestal_run, opts.pedcal_run
179
174
 
180
175
 
@@ -331,6 +326,12 @@ def provprocess_argparser():
331
326
  dest="quit",
332
327
  help="use this flag to reset session and remove log file",
333
328
  )
329
+ parser.add_argument(
330
+ "--no-dl2",
331
+ action="store_true",
332
+ default=False,
333
+ help="Do not produce DL2 files (default False)",
334
+ )
334
335
  parser.add_argument(
335
336
  "drs4_pedestal_run_id", help="Number of the drs4_pedestal used in the calibration"
336
337
  )
@@ -359,6 +360,7 @@ def provprocessparsing():
359
360
  options.configfile = opts.config.resolve()
360
361
  options.filter = opts.filter
361
362
  options.quit = opts.quit
363
+ options.no_dl2 = opts.no_dl2
362
364
  set_prod_ids()
363
365
 
364
366
 
@@ -30,13 +30,6 @@ def test_get_prod_id():
30
30
  assert get_prod_id() == prod_id
31
31
 
32
32
 
33
- def test_get_calib_prod_id():
34
- from osa.utils.utils import get_calib_prod_id
35
-
36
- prod_id = cfg.get(options.tel_id, "CALIB_PROD_ID")
37
- assert get_calib_prod_id() == prod_id
38
-
39
-
40
33
  def test_date_to_dir():
41
34
  from osa.utils.utils import date_to_dir
42
35
 
osa/utils/utils.py CHANGED
@@ -26,7 +26,6 @@ __all__ = [
26
26
  "create_lock",
27
27
  "stringify",
28
28
  "gettag",
29
- "get_calib_prod_id",
30
29
  "get_dl1_prod_id",
31
30
  "get_dl2_prod_id",
32
31
  "time_to_seconds",
@@ -86,19 +85,6 @@ def get_prod_id():
86
85
  return options.prod_id
87
86
 
88
87
 
89
- def get_calib_prod_id() -> str:
90
- """Build calibration production ID."""
91
- if not options.calib_prod_id:
92
- if cfg.get("LST1", "CALIB_PROD_ID") is not None:
93
- options.calib_prod_id = cfg.get("LST1", "CALIB_PROD_ID")
94
- else:
95
- options.calib_prod_id = get_lstchain_version()
96
-
97
- log.debug(f"Getting prod ID for calibration products: {options.calib_prod_id}")
98
-
99
- return options.calib_prod_id
100
-
101
-
102
88
  def get_dl1_prod_id():
103
89
  """
104
90
  Get the prod ID for the dl1 products provided
@@ -262,11 +248,6 @@ def set_prod_ids():
262
248
  """Set the product IDs."""
263
249
  options.prod_id = get_prod_id()
264
250
 
265
- if cfg.get("LST1", "CALIB_PROD_ID") is not None:
266
- options.calib_prod_id = get_calib_prod_id()
267
- else:
268
- options.calib_prod_id = options.prod_id
269
-
270
251
  if cfg.get("LST1", "DL1_PROD_ID") is not None:
271
252
  options.dl1_prod_id = get_dl1_prod_id()
272
253
  else:
osa/workflow/stages.py CHANGED
@@ -11,6 +11,7 @@ from pathlib import Path
11
11
  from typing import List, Union
12
12
 
13
13
  from tenacity import retry, stop_after_attempt
14
+ import lstchain
14
15
 
15
16
  from osa.configs import options
16
17
  from osa.configs.config import cfg
@@ -75,36 +76,48 @@ class AnalysisStage:
75
76
  """
76
77
 
77
78
  if self.command == "lstchain_data_r0_to_dl1":
78
- dl1_output_file = options.directory / f"dl1_LST-1.Run{self.run}.h5"
79
- muon_output_file = options.directory / f"muons_LST-1.Run{self.run}.fits"
80
- interleaved_output_file = options.directory / f"interleaved_LST-1.Run{self.run}.h5"
81
- dl1_output_file.unlink(missing_ok=True)
82
- muon_output_file.unlink(missing_ok=True)
83
- interleaved_output_file.unlink(missing_ok=True)
84
-
79
+ self._remove_dl1a_output()
85
80
  elif self.command == "lstchain_dl1ab":
86
- dl1ab_subdirectory = options.directory / options.dl1_prod_id
87
- output_file = dl1ab_subdirectory / f"dl1_LST-1.Run{self.run}.h5"
88
- output_file.unlink(missing_ok=True)
89
-
81
+ self._remove_dl1b_output('dl1_LST-1.Run')
90
82
  elif self.command == "lstchain_check_dl1":
91
- dl1ab_subdirectory = options.directory / options.dl1_prod_id
92
- output_file = dl1ab_subdirectory / f"datacheck_dl1_LST-1.Run{self.run}.h5"
93
- output_file.unlink(missing_ok=True)
94
-
83
+ self._remove_dl1b_output('datacheck_dl1_LST-1.Run')
95
84
  elif self.command == "onsite_create_calibration_file":
96
- calib_base = Path(cfg.get("LST1", "CALIB_DIR"))
97
- date = date_to_dir(get_run_date(self.run))
98
- cal_dir = calib_base / date / "pro"
99
- output_file = cal_dir / f"calibration_filters_{options.filters}.Run{self.run}.0000.h5"
100
- output_file.unlink(missing_ok=True)
101
-
85
+ self._remove_calibration()
102
86
  elif self.command == "onsite_create_drs4_pedestal_file":
103
- drs4_pedestal_dir = Path(cfg.get("LST1", "PEDESTAL_DIR"))
104
- date = date_to_dir(get_run_date(self.run))
105
- output_file = drs4_pedestal_dir / date / f"pro/drs4_pedestal.Run{self.run}.0000.h5"
106
- output_file.unlink(missing_ok=True)
107
-
87
+ self._remove_drs4_baseline()
88
+
89
+ def _remove_drs4_baseline(self):
90
+ drs4_pedestal_basedir = Path(cfg.get("LST1", "PEDESTAL_DIR"))
91
+ date = date_to_dir(get_run_date(self.run))
92
+ drs4_pedestal_dir = drs4_pedestal_basedir / date / lstchain.__version__
93
+ file = drs4_pedestal_dir / "drs4_pedestal.Run{self.run}.0000.h5"
94
+ file.unlink(missing_ok=True)
95
+ # Also remove the link to "pro" directory
96
+ drs4_pedestal_dir_pro = drs4_pedestal_basedir / date / "pro"
97
+ drs4_pedestal_dir_pro.unlink(missing_ok=True)
98
+
99
+ def _remove_calibration(self):
100
+ calib_basedir = Path(cfg.get("LST1", "CALIB_DIR"))
101
+ date = date_to_dir(get_run_date(self.run))
102
+ calib_dir = file = calib_basedir / date / lstchain.__version__
103
+ file = calib_dir / f"calibration_filters_{options.filters}.Run{self.run}.0000.h5"
104
+ file.unlink(missing_ok=True)
105
+ # Also remove the link to "pro" directory
106
+ calib_dir_pro = file = calib_basedir / date / "pro"
107
+ calib_dir_pro.unlink(missing_ok=True)
108
+
109
+ def _remove_dl1a_output(self):
110
+ dl1_output_file = options.directory / f"dl1_LST-1.Run{self.run}.h5"
111
+ muon_output_file = options.directory / f"muons_LST-1.Run{self.run}.fits"
112
+ interleaved_output_file = options.directory / f"interleaved_LST-1.Run{self.run}.h5"
113
+ dl1_output_file.unlink(missing_ok=True)
114
+ muon_output_file.unlink(missing_ok=True)
115
+ interleaved_output_file.unlink(missing_ok=True)
116
+
117
+ def _remove_dl1b_output(self, file_prefix):
118
+ dl1ab_subdirectory = options.directory / options.dl1_prod_id
119
+ output_file = dl1ab_subdirectory / f"{file_prefix}{self.run}.h5"
120
+ output_file.unlink(missing_ok=True)
108
121
 
109
122
  def _write_checkpoint(self):
110
123
  """Write the checkpoint in the history file."""
@@ -137,7 +150,6 @@ class DRS4PedestalStage(AnalysisStage):
137
150
  config_file: Union[str, None] = None,
138
151
  ):
139
152
  super().__init__(run, command_args, config_file)
140
- self.prod_id = options.calib_prod_id
141
153
  self.run_pedcal = run_pedcal
142
154
  self.history_file = (
143
155
  Path(options.directory) / f"sequence_{options.tel_id}_{self.run_pedcal}.history"
@@ -147,7 +159,7 @@ class DRS4PedestalStage(AnalysisStage):
147
159
  """Write the checkpoint in the history file."""
148
160
  history(
149
161
  run=self.run,
150
- prod_id=self.prod_id,
162
+ prod_id=options.prod_id,
151
163
  stage=self.command,
152
164
  return_code=self.rc,
153
165
  history_file=self.history_file,
@@ -164,7 +176,6 @@ class ChargeCalibrationStage(AnalysisStage):
164
176
  config_file: Union[str, None] = None,
165
177
  ):
166
178
  super().__init__(run, command_args, config_file)
167
- self.prod_id = options.calib_prod_id
168
179
  self.history_file = (
169
180
  Path(options.directory) / f"sequence_{options.tel_id}_{self.run}.history"
170
181
  )
@@ -173,7 +184,7 @@ class ChargeCalibrationStage(AnalysisStage):
173
184
  """Write the checkpoint in the history file."""
174
185
  history(
175
186
  run=self.run,
176
- prod_id=self.prod_id,
187
+ prod_id=options.prod_id,
177
188
  stage=self.command,
178
189
  return_code=self.rc,
179
190
  history_file=self.history_file,