ctao-calibpipe 0.3.0rc2__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.
Files changed (105) hide show
  1. calibpipe/__init__.py +5 -0
  2. calibpipe/_dev_version/__init__.py +9 -0
  3. calibpipe/_version.py +34 -0
  4. calibpipe/atmosphere/__init__.py +1 -0
  5. calibpipe/atmosphere/atmosphere_containers.py +109 -0
  6. calibpipe/atmosphere/meteo_data_handlers.py +485 -0
  7. calibpipe/atmosphere/models/README.md +14 -0
  8. calibpipe/atmosphere/models/__init__.py +1 -0
  9. calibpipe/atmosphere/models/macobac.ecsv +23 -0
  10. calibpipe/atmosphere/models/reference_MDPs/__init__.py +1 -0
  11. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_intermediate.ecsv +8 -0
  12. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_summer.ecsv +8 -0
  13. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_winter.ecsv +8 -0
  14. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-south_summer.ecsv +8 -0
  15. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-south_winter.ecsv +8 -0
  16. calibpipe/atmosphere/models/reference_atmospheres/__init__.py +1 -0
  17. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_intermediate.ecsv +73 -0
  18. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_summer.ecsv +73 -0
  19. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_winter.ecsv +73 -0
  20. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-south_summer.ecsv +73 -0
  21. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-south_winter.ecsv +73 -0
  22. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/__init__.py +1 -0
  23. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_intermediate.ecsv +857 -0
  24. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_summer.ecsv +857 -0
  25. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_winter.ecsv +857 -0
  26. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-south_summer.ecsv +857 -0
  27. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-south_winter.ecsv +857 -0
  28. calibpipe/atmosphere/templates/request_templates/__init__.py +1 -0
  29. calibpipe/atmosphere/templates/request_templates/copernicus.json +11 -0
  30. calibpipe/atmosphere/templates/request_templates/gdas.json +12 -0
  31. calibpipe/core/__init__.py +39 -0
  32. calibpipe/core/common_metadata_containers.py +198 -0
  33. calibpipe/core/exceptions.py +87 -0
  34. calibpipe/database/__init__.py +24 -0
  35. calibpipe/database/adapter/__init__.py +23 -0
  36. calibpipe/database/adapter/adapter.py +80 -0
  37. calibpipe/database/adapter/database_containers/__init__.py +63 -0
  38. calibpipe/database/adapter/database_containers/atmosphere.py +199 -0
  39. calibpipe/database/adapter/database_containers/common_metadata.py +150 -0
  40. calibpipe/database/adapter/database_containers/container_map.py +59 -0
  41. calibpipe/database/adapter/database_containers/observatory.py +61 -0
  42. calibpipe/database/adapter/database_containers/table_version_manager.py +39 -0
  43. calibpipe/database/adapter/database_containers/throughput.py +30 -0
  44. calibpipe/database/adapter/database_containers/version_control.py +17 -0
  45. calibpipe/database/connections/__init__.py +28 -0
  46. calibpipe/database/connections/calibpipe_database.py +60 -0
  47. calibpipe/database/connections/postgres_utils.py +97 -0
  48. calibpipe/database/connections/sql_connection.py +103 -0
  49. calibpipe/database/connections/user_confirmation.py +19 -0
  50. calibpipe/database/interfaces/__init__.py +71 -0
  51. calibpipe/database/interfaces/hashable_row_data.py +54 -0
  52. calibpipe/database/interfaces/queries.py +180 -0
  53. calibpipe/database/interfaces/sql_column_info.py +67 -0
  54. calibpipe/database/interfaces/sql_metadata.py +6 -0
  55. calibpipe/database/interfaces/sql_table_info.py +131 -0
  56. calibpipe/database/interfaces/table_handler.py +333 -0
  57. calibpipe/database/interfaces/types.py +96 -0
  58. calibpipe/telescope/throughput/containers.py +66 -0
  59. calibpipe/tests/conftest.py +274 -0
  60. calibpipe/tests/data/atmosphere/molecular_atmosphere/__init__.py +0 -0
  61. calibpipe/tests/data/atmosphere/molecular_atmosphere/contemporary_MDP.ecsv +34 -0
  62. calibpipe/tests/data/atmosphere/molecular_atmosphere/macobac.csv +852 -0
  63. calibpipe/tests/data/atmosphere/molecular_atmosphere/macobac.ecsv +23 -0
  64. calibpipe/tests/data/atmosphere/molecular_atmosphere/merged_file.ecsv +1082 -0
  65. calibpipe/tests/data/atmosphere/molecular_atmosphere/meteo_data_copernicus.ecsv +1082 -0
  66. calibpipe/tests/data/atmosphere/molecular_atmosphere/meteo_data_gdas.ecsv +66 -0
  67. calibpipe/tests/data/atmosphere/molecular_atmosphere/observatory_configurations.json +71 -0
  68. calibpipe/tests/data/utils/__init__.py +0 -0
  69. calibpipe/tests/data/utils/meteo_data_winter_and_summer.ecsv +12992 -0
  70. calibpipe/tests/test_conftest_data.py +200 -0
  71. calibpipe/tests/unittests/array/test_cross_calibration.py +412 -0
  72. calibpipe/tests/unittests/atmosphere/astral_testing.py +107 -0
  73. calibpipe/tests/unittests/atmosphere/test_meteo_data_handler.py +775 -0
  74. calibpipe/tests/unittests/atmosphere/test_molecular_atmosphere.py +327 -0
  75. calibpipe/tests/unittests/database/test_table_handler.py +163 -0
  76. calibpipe/tests/unittests/database/test_types.py +38 -0
  77. calibpipe/tests/unittests/telescope/camera/test_calculate_camcalib_coefficients.py +456 -0
  78. calibpipe/tests/unittests/telescope/camera/test_produce_camcalib_test_data.py +37 -0
  79. calibpipe/tests/unittests/telescope/throughput/test_muon_throughput_calibrator.py +693 -0
  80. calibpipe/tests/unittests/test_bootstrap_db.py +79 -0
  81. calibpipe/tests/unittests/utils/test_observatory.py +309 -0
  82. calibpipe/tools/atmospheric_base_tool.py +78 -0
  83. calibpipe/tools/atmospheric_model_db_loader.py +181 -0
  84. calibpipe/tools/basic_tool_with_db.py +38 -0
  85. calibpipe/tools/camcalib_test_data.py +374 -0
  86. calibpipe/tools/camera_calibrator.py +462 -0
  87. calibpipe/tools/contemporary_mdp_producer.py +87 -0
  88. calibpipe/tools/init_db.py +37 -0
  89. calibpipe/tools/macobac_calculator.py +82 -0
  90. calibpipe/tools/molecular_atmospheric_model_producer.py +197 -0
  91. calibpipe/tools/muon_throughput_calculator.py +219 -0
  92. calibpipe/tools/observatory_data_db_loader.py +71 -0
  93. calibpipe/tools/reference_atmospheric_model_selector.py +201 -0
  94. calibpipe/tools/telescope_cross_calibration_calculator.py +721 -0
  95. calibpipe/utils/__init__.py +10 -0
  96. calibpipe/utils/observatory.py +486 -0
  97. calibpipe/utils/observatory_containers.py +26 -0
  98. calibpipe/version.py +24 -0
  99. ctao_calibpipe-0.3.0rc2.dist-info/METADATA +92 -0
  100. ctao_calibpipe-0.3.0rc2.dist-info/RECORD +105 -0
  101. ctao_calibpipe-0.3.0rc2.dist-info/WHEEL +5 -0
  102. ctao_calibpipe-0.3.0rc2.dist-info/entry_points.txt +12 -0
  103. ctao_calibpipe-0.3.0rc2.dist-info/licenses/AUTHORS.md +13 -0
  104. ctao_calibpipe-0.3.0rc2.dist-info/licenses/LICENSE +21 -0
  105. ctao_calibpipe-0.3.0rc2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,374 @@
1
+ """Utility tool to produce test data for the camera calibration tools in the calibpipe package."""
2
+
3
+ import astropy.units as u
4
+ import yaml
5
+ from astropy.time import Time
6
+ from ctapipe.core import Tool, run_tool
7
+ from ctapipe.core.traits import (
8
+ Bool,
9
+ CaselessStrEnum,
10
+ CInt,
11
+ List,
12
+ Path,
13
+ Set,
14
+ Unicode,
15
+ )
16
+ from ctapipe.instrument import SubarrayDescription
17
+ from ctapipe.io import read_table, write_table
18
+ from ctapipe.io.hdf5dataformat import (
19
+ DL1_PIXEL_STATISTICS_GROUP,
20
+ DL1_TEL_IMAGES_GROUP,
21
+ )
22
+ from ctapipe.tools.calculate_pixel_stats import PixelStatisticsCalculatorTool
23
+ from ctapipe.tools.merge import MergeTool
24
+ from ctapipe.tools.process import ProcessorTool
25
+ from traitlets.config.loader import Config
26
+
27
+ __all__ = [
28
+ "CamCalibTestDataTool",
29
+ ]
30
+
31
+
32
+ class CamCalibTestDataTool(Tool):
33
+ """Utility tool to produce test data for the camera calibration."""
34
+
35
+ name = "calibpipe-produce-camcalib-test-data"
36
+
37
+ description = "Produce test data for the camera calibration tools."
38
+
39
+ examples = """
40
+ To produce the test data for the camera calibration tools, you need to provide the input files
41
+ for the pedestal and flatfield events, as well as the configuration files (see examples
42
+ in the calibpipe documentation) for processing these events and aggregating the statistics.
43
+ The timestamp of the events will be set to a realistic value based on the
44
+ reference time and trigger rate defined in the tool. The output files will be created in the
45
+ specified output directory, with the prefix defined in the configuration.
46
+
47
+ Run with the following command to produce the test data:
48
+
49
+ > calibpipe-produce-camcalib-test-data \\
50
+ --pedestal pedestal_events.simtel.gz \\
51
+ --flatfield flatfield_events.simtel.gz \\
52
+ --output-dir ./output \\
53
+ --CamCalibTestDataTool.process_pedestal_config ctapipe_process_pedestal.yaml \\
54
+ --CamCalibTestDataTool.process_flatfield_config ctapipe_process_flatfield.yaml \\
55
+ --CamCalibTestDataTool.agg_stats_sky_pedestal_image_config ctapipe_calculate_pixel_stats_sky_pedestal_image.yaml \\
56
+ --CamCalibTestDataTool.agg_stats_flatfield_image_config ctapipe_calculate_pixel_stats_flatfield_image.yaml \\
57
+ --CamCalibTestDataTool.agg_stats_flatfield_peak_time_config ctapipe_calculate_pixel_stats_flatfield_peak_time.yaml \\
58
+ --CamCalibTestDataTool.prefix calibpipe_vX.Y.Z_statsagg \\
59
+ """
60
+
61
+ pedestal_input_url = Path(
62
+ help="Simtel input file for pedestal events",
63
+ allow_none=False,
64
+ exists=True,
65
+ directory_ok=False,
66
+ file_ok=True,
67
+ ).tag(config=True)
68
+
69
+ flatfield_input_url = Path(
70
+ help="Simtel input file for flatfield events",
71
+ allow_none=False,
72
+ exists=True,
73
+ directory_ok=False,
74
+ file_ok=True,
75
+ ).tag(config=True)
76
+
77
+ process_pedestal_config = Path(
78
+ help="Path to the configuration file for processing pedestal events",
79
+ allow_none=False,
80
+ exists=True,
81
+ directory_ok=False,
82
+ file_ok=True,
83
+ ).tag(config=True)
84
+
85
+ process_flatfield_config = Path(
86
+ help="Path to the configuration file for processing flatfield events",
87
+ allow_none=False,
88
+ exists=True,
89
+ directory_ok=False,
90
+ file_ok=True,
91
+ ).tag(config=True)
92
+
93
+ agg_stats_sky_pedestal_image_config = Path(
94
+ help="Path to the configuration file for aggregating sky pedestal image statistics",
95
+ allow_none=False,
96
+ exists=True,
97
+ directory_ok=False,
98
+ file_ok=True,
99
+ ).tag(config=True)
100
+
101
+ agg_stats_flatfield_image_config = Path(
102
+ help="Path to the configuration file for aggregating flatfield image statistics",
103
+ allow_none=False,
104
+ exists=True,
105
+ directory_ok=False,
106
+ file_ok=True,
107
+ ).tag(config=True)
108
+
109
+ agg_stats_flatfield_peak_time_config = Path(
110
+ help="Path to the configuration file for aggregating flatfield peak time statistics",
111
+ allow_none=False,
112
+ exists=True,
113
+ directory_ok=False,
114
+ file_ok=True,
115
+ ).tag(config=True)
116
+
117
+ allowed_tels = Set(
118
+ trait=CInt(),
119
+ default_value=None,
120
+ allow_none=True,
121
+ help=(
122
+ "List of allowed telescope IDs, others will be ignored. If None, all "
123
+ "telescopes in the input stream will be included. Requires the "
124
+ "telescope IDs to match between the groups of the monitoring file."
125
+ ),
126
+ ).tag(config=True)
127
+
128
+ prefix = Unicode(
129
+ default_value="statsagg_test_data",
130
+ allow_none=False,
131
+ help="Prefix to be used for the output files of the statistics aggregation",
132
+ ).tag(config=True)
133
+
134
+ aggregation_modes = List(
135
+ trait=CaselessStrEnum(["single_chunk", "same_chunks", "different_chunks"]),
136
+ default_value=["single_chunk", "same_chunks", "different_chunks"],
137
+ allow_none=False,
138
+ help=(
139
+ "List of aggregation modes for the pixel statistics. "
140
+ "Options are: 'single_chunk', 'same_chunks', 'different_chunks'. "
141
+ "If 'single_chunk' is selected, all monitoring groups are aggregated in a single chunk. "
142
+ "If 'same_chunks' is selected, all monitoring groups are aggregated in the same chunks. "
143
+ "If 'different_chunks' is selected, each monitoring groups are aggregated in different chunks."
144
+ ),
145
+ ).tag(config=True)
146
+
147
+ skip_r1_calibration = Bool(
148
+ default_value=True,
149
+ help=(
150
+ "If True (default), skip the R1 calibration step in the simtel event source. "
151
+ "This is useful for testing and validation purposes of the camera calibration routines. "
152
+ ),
153
+ ).tag(config=True)
154
+
155
+ output_dir = Path(
156
+ help="Directory to store the output files",
157
+ allow_none=False,
158
+ exists=True,
159
+ directory_ok=True,
160
+ file_ok=False,
161
+ ).tag(config=True)
162
+
163
+ aliases = {
164
+ ("p", "pedestal"): "CamCalibTestDataTool.pedestal_input_url",
165
+ ("f", "flatfield"): "CamCalibTestDataTool.flatfield_input_url",
166
+ ("o", "output-dir"): "CamCalibTestDataTool.output_dir",
167
+ }
168
+
169
+ # Define reference time and trigger rate for the tests. These values
170
+ # are used to create realistic timestamps for the aggregated chunks.
171
+ REFERENCE_TIME = Time.now()
172
+ REFERENCE_TRIGGER_RATE = 1000.0 * u.Hz
173
+
174
+ def setup(self):
175
+ """Set up the tool."""
176
+ # Load the subarray description from the input files
177
+ subarray_pedestal = SubarrayDescription.read(self.pedestal_input_url)
178
+ subarray_flatfield = SubarrayDescription.read(self.flatfield_input_url)
179
+ # Check if the subarray descriptions match
180
+ if not subarray_pedestal.__eq__(subarray_flatfield):
181
+ raise ValueError(
182
+ "The subarray descriptions of the pedestal and flatfield input files do not match."
183
+ )
184
+ # Select a new subarray if the allowed_tels configuration is used
185
+ self.subarray = (
186
+ subarray_pedestal
187
+ if self.allowed_tels is None
188
+ else subarray_pedestal.select_subarray(self.allowed_tels)
189
+ )
190
+ # The monitoring groups and their configurations to be used in the tests
191
+ self.monitoring_groups = {
192
+ "sky_pedestal_image": self.agg_stats_sky_pedestal_image_config,
193
+ "flatfield_image": self.agg_stats_flatfield_image_config,
194
+ "flatfield_peak_time": self.agg_stats_flatfield_peak_time_config,
195
+ }
196
+
197
+ def start(self):
198
+ """Iterate over the telescope IDs and calculate the camera calibration coefficients."""
199
+ # Set the path to the simtel calibration events
200
+ # Set the output file path for pedestal images
201
+ pedestal_dl1_image_file = self.output_dir / "pedestal_events.dl1.h5"
202
+ with open(self.process_pedestal_config) as yaml_file:
203
+ pedestal_config = yaml.safe_load(yaml_file)
204
+ pedestal_dl1_image_file = self._run_ctapipe_process_tool(
205
+ self.pedestal_input_url, pedestal_dl1_image_file, pedestal_config
206
+ )
207
+ # Set the output file path for flatfield images
208
+ flatfield_dl1_image_file = self.output_dir / "flatfield_events.dl1.h5"
209
+ with open(self.process_flatfield_config) as yaml_file:
210
+ flatfield_config = yaml.safe_load(yaml_file)
211
+ flatfield_dl1_image_file = self._run_ctapipe_process_tool(
212
+ self.flatfield_input_url, flatfield_dl1_image_file, flatfield_config
213
+ )
214
+
215
+ for aggregation_mode in self.aggregation_modes:
216
+ # Iterate over the telescope IDs and calculate the camera calibration coefficients
217
+ for t, tel_id in enumerate(self.subarray.tel_ids):
218
+ # Create the statistics aggregation file for the given aggregation mode
219
+ # Default chunk duration for the statistics aggregation
220
+ chunk_duration = 25.0 * u.s
221
+ # Loop over the monitoring groups and calculate pixel statistics
222
+ for mon_group, mon_config in self.monitoring_groups.items():
223
+ # Set the output file path for the statistics aggregation
224
+ output_file = (
225
+ self.output_dir
226
+ / f"{self.prefix}_{mon_group}_{aggregation_mode}.dl1.h5"
227
+ )
228
+ # Set the input file path for the PixelStatisticsCalculator
229
+ dl1_image_file = (
230
+ pedestal_dl1_image_file
231
+ if mon_group == "sky_pedestal_image"
232
+ else flatfield_dl1_image_file
233
+ )
234
+ # Get the standard configuration for the PixelStatisticsCalculator
235
+ with open(mon_config) as yaml_file:
236
+ pix_stats_config = yaml.safe_load(yaml_file)
237
+ # Set some additional parameters using cli arguments
238
+ cli_argv = [
239
+ f"--input_url={dl1_image_file}",
240
+ f"--output_path={output_file}",
241
+ ]
242
+ if t > 0:
243
+ cli_argv.append("--append")
244
+ n_events = len(
245
+ read_table(
246
+ dl1_image_file,
247
+ path=f"{DL1_TEL_IMAGES_GROUP}/tel_{tel_id:03d}",
248
+ )
249
+ )
250
+ # Modify the configuration for the specific chunk mode
251
+ if aggregation_mode == "single_chunk":
252
+ chunk_duration = 1000.0 * u.s
253
+ # Overwrite the chunk size for the specific aggregator
254
+ cli_argv.append(f"--SizeChunking.chunk_size={n_events}")
255
+ elif aggregation_mode == "same_chunks":
256
+ chunk_duration = 100.0 * u.s
257
+ # Overwrite the chunk size for the specific aggregator
258
+ cli_argv.append(f"--SizeChunking.chunk_size={n_events//10}")
259
+ elif aggregation_mode == "different_chunks":
260
+ # Use different chunk sizes for each monitoring group
261
+ if mon_group == "sky_pedestal_image":
262
+ chunk_duration = 200.0 * u.s
263
+ cli_argv.append(
264
+ f"--SizeChunking.chunk_size={2 * (n_events//10)}"
265
+ )
266
+ elif mon_group == "flatfield_image":
267
+ chunk_duration = 100.0 * u.s
268
+ cli_argv.append(
269
+ f"--SizeChunking.chunk_size={n_events//10}"
270
+ )
271
+ elif mon_group == "flatfield_peak_time":
272
+ chunk_duration = 500.0 * u.s
273
+ cli_argv.append(
274
+ f"--SizeChunking.chunk_size={5 * (n_events//10)}"
275
+ )
276
+
277
+ # Run the PixelStatisticsCalculatorTool to calculate pixel statistics
278
+ run_tool(
279
+ PixelStatisticsCalculatorTool(
280
+ config=Config(pix_stats_config)
281
+ ),
282
+ argv=cli_argv,
283
+ cwd=self.output_dir,
284
+ raises=True,
285
+ )
286
+ # Overwrite timestamps in the output file to make them realistic
287
+ # Read the created statsagg table for the specific monitoring group
288
+ stats_aggregation_tab = read_table(
289
+ output_file,
290
+ path=f"{DL1_PIXEL_STATISTICS_GROUP}/{mon_group}/tel_{tel_id:03d}",
291
+ )
292
+ # Loop over the chunks and set the new timestamps
293
+ for chunk_nr in range(len(stats_aggregation_tab)):
294
+ stats_aggregation_tab["time_start"][chunk_nr] = (
295
+ self.REFERENCE_TIME
296
+ + (1 / self.REFERENCE_TRIGGER_RATE).to(u.s)
297
+ + chunk_nr * chunk_duration
298
+ )
299
+ stats_aggregation_tab["time_end"][chunk_nr] = (
300
+ self.REFERENCE_TIME + (chunk_nr + 1) * chunk_duration
301
+ )
302
+ # Set a different starting time (outside the default 1 second tolerance)
303
+ # for the pedestal group if the mode is 'diffent_chunks'. This is to ensure
304
+ # that the we can later test when the chunk interpolator is returning NaN values
305
+ # for the first and last unique timestamps.
306
+ if aggregation_mode == "different_chunks":
307
+ if mon_group == "sky_pedestal_image":
308
+ stats_aggregation_tab["time_start"][0] -= 2 * u.s
309
+ stats_aggregation_tab["time_end"][-1] += 2 * u.s
310
+ # Overwrite the table in the output file
311
+ write_table(
312
+ stats_aggregation_tab,
313
+ output_file,
314
+ f"{DL1_PIXEL_STATISTICS_GROUP}/{mon_group}/tel_{tel_id:03d}",
315
+ overwrite=True,
316
+ )
317
+ # Create the monitoring file by merging the output files for the statistics aggregation
318
+ output_files = [
319
+ str(
320
+ self.output_dir
321
+ / f"{self.prefix}_{mon_group}_{aggregation_mode}.dl1.h5"
322
+ )
323
+ for mon_group in self.monitoring_groups
324
+ ]
325
+ monitoring_file = (
326
+ self.output_dir / f"{self.prefix}_{aggregation_mode}.dl1.h5"
327
+ )
328
+ self.log.info(
329
+ "Merge the following output files for the statistics aggregation: %s",
330
+ ", ".join(str(f) for f in output_files),
331
+ )
332
+ run_tool(
333
+ MergeTool(),
334
+ argv=output_files
335
+ + [
336
+ f"--output={monitoring_file}",
337
+ "--monitoring",
338
+ "--single-ob",
339
+ ],
340
+ cwd=self.output_dir,
341
+ raises=True,
342
+ )
343
+ self.log.info(
344
+ "The monitoring file was created in '%s' with the following groups: %s",
345
+ monitoring_file,
346
+ self.monitoring_groups.keys(),
347
+ )
348
+
349
+ def finish(self):
350
+ """Shut down the tool."""
351
+ self.log.info("Tool is shutting down")
352
+
353
+ def _run_ctapipe_process_tool(self, input_data, output_file, config):
354
+ """Produce the DL1A file containing the images."""
355
+ # Run the ProcessorTool to create images
356
+ run_tool(
357
+ ProcessorTool(config=Config(config)),
358
+ argv=[
359
+ f"--input={input_data}",
360
+ f"--output={output_file}",
361
+ "--overwrite",
362
+ ],
363
+ )
364
+ return output_file
365
+
366
+
367
+ def main():
368
+ # Run the tool
369
+ tool = CamCalibTestDataTool()
370
+ tool.run()
371
+
372
+
373
+ if __name__ == "main":
374
+ main()