gammasimtools 0.5.1__py3-none-any.whl → 0.6.1__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.
- {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/METADATA +80 -28
- gammasimtools-0.6.1.dist-info/RECORD +91 -0
- {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/WHEEL +1 -1
- {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/entry_points.txt +4 -2
- simtools/_version.py +14 -2
- simtools/applications/add_file_to_db.py +2 -1
- simtools/applications/compare_cumulative_psf.py +10 -15
- simtools/applications/db_development_tools/add_new_parameter_to_db.py +12 -6
- simtools/applications/derive_mirror_rnda.py +95 -71
- simtools/applications/generate_corsika_histograms.py +216 -131
- simtools/applications/generate_default_metadata.py +110 -0
- simtools/applications/generate_simtel_array_histograms.py +192 -0
- simtools/applications/get_file_from_db.py +1 -1
- simtools/applications/get_parameter.py +3 -3
- simtools/applications/make_regular_arrays.py +89 -93
- simtools/applications/{plot_layout_array.py → plot_array_layout.py} +15 -14
- simtools/applications/print_array_elements.py +81 -34
- simtools/applications/produce_array_config.py +2 -2
- simtools/applications/production.py +39 -5
- simtools/applications/sim_showers_for_trigger_rates.py +26 -30
- simtools/applications/simulate_prod.py +49 -107
- simtools/applications/submit_data_from_external.py +8 -10
- simtools/applications/tune_psf.py +16 -18
- simtools/applications/validate_camera_efficiency.py +63 -9
- simtools/applications/validate_camera_fov.py +9 -13
- simtools/applications/validate_file_using_schema.py +127 -0
- simtools/applications/validate_optics.py +13 -15
- simtools/camera_efficiency.py +73 -80
- simtools/configuration/commandline_parser.py +52 -22
- simtools/configuration/configurator.py +98 -33
- simtools/constants.py +9 -0
- simtools/corsika/corsika_config.py +28 -22
- simtools/corsika/corsika_default_config.py +282 -0
- simtools/corsika/corsika_histograms.py +328 -282
- simtools/corsika/corsika_histograms_visualize.py +162 -163
- simtools/corsika/corsika_runner.py +8 -4
- simtools/corsika_simtel/corsika_simtel_runner.py +18 -23
- simtools/data_model/data_reader.py +129 -0
- simtools/data_model/metadata_collector.py +346 -118
- simtools/data_model/metadata_model.py +123 -218
- simtools/data_model/model_data_writer.py +79 -22
- simtools/data_model/validate_data.py +96 -46
- simtools/db_handler.py +67 -42
- simtools/io_operations/__init__.py +0 -0
- simtools/io_operations/hdf5_handler.py +112 -0
- simtools/{io_handler.py → io_operations/io_handler.py} +51 -22
- simtools/job_execution/job_manager.py +1 -1
- simtools/layout/{layout_array.py → array_layout.py} +168 -199
- simtools/layout/geo_coordinates.py +196 -0
- simtools/layout/telescope_position.py +12 -12
- simtools/model/array_model.py +16 -14
- simtools/model/camera.py +5 -8
- simtools/model/mirrors.py +136 -73
- simtools/model/model_utils.py +1 -69
- simtools/model/telescope_model.py +32 -25
- simtools/psf_analysis.py +26 -19
- simtools/ray_tracing.py +54 -26
- simtools/schemas/data.metaschema.yml +400 -0
- simtools/schemas/metadata.metaschema.yml +566 -0
- simtools/simtel/simtel_config_writer.py +14 -5
- simtools/simtel/simtel_histograms.py +266 -83
- simtools/simtel/simtel_runner.py +8 -7
- simtools/simtel/simtel_runner_array.py +7 -8
- simtools/simtel/simtel_runner_camera_efficiency.py +48 -2
- simtools/simtel/simtel_runner_ray_tracing.py +61 -25
- simtools/simulator.py +43 -50
- simtools/utils/general.py +232 -286
- simtools/utils/geometry.py +163 -0
- simtools/utils/names.py +294 -142
- simtools/visualization/legend_handlers.py +115 -9
- simtools/visualization/visualize.py +13 -13
- gammasimtools-0.5.1.dist-info/RECORD +0 -83
- simtools/applications/plot_simtel_histograms.py +0 -120
- simtools/applications/validate_schema_files.py +0 -135
- simtools/corsika/corsika_output_visualize.py +0 -345
- simtools/data_model/validate_schema.py +0 -285
- {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/LICENSE +0 -0
- {gammasimtools-0.5.1.dist-info → gammasimtools-0.6.1.dist-info}/top_level.txt +0 -0
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import copy
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
|
-
import matplotlib.pyplot as plt
|
|
5
4
|
import numpy as np
|
|
5
|
+
from astropy import units as u
|
|
6
|
+
from ctapipe.io import write_table
|
|
6
7
|
from eventio import EventIOFile, Histograms
|
|
7
8
|
from eventio.search_utils import yield_toplevel_of_type
|
|
8
|
-
from matplotlib.backends.backend_pdf import PdfPages
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
from simtools import version
|
|
11
|
+
from simtools.io_operations.hdf5_handler import fill_hdf5_table
|
|
12
|
+
from simtools.utils.names import sanitize_name
|
|
11
13
|
|
|
14
|
+
__all__ = ["InconsistentHistogramFormat", "SimtelHistograms"]
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
|
|
17
|
+
class InconsistentHistogramFormat(Exception):
|
|
14
18
|
"""Exception for bad histogram format."""
|
|
15
19
|
|
|
16
20
|
|
|
@@ -32,27 +36,17 @@ class SimtelHistograms:
|
|
|
32
36
|
Initialize SimtelHistograms
|
|
33
37
|
"""
|
|
34
38
|
self._logger = logging.getLogger(__name__)
|
|
39
|
+
if not isinstance(histogram_files, list):
|
|
40
|
+
histogram_files = [histogram_files]
|
|
35
41
|
self._histogram_files = histogram_files
|
|
36
42
|
self._is_test = test
|
|
37
|
-
self.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
"""
|
|
41
|
-
Plot all histograms and save a single pdf file.
|
|
42
|
-
|
|
43
|
-
Parameters
|
|
44
|
-
----------
|
|
45
|
-
fig_name: str
|
|
46
|
-
Name of the output figure file.
|
|
47
|
-
"""
|
|
48
|
-
self._combine_histogram_files()
|
|
49
|
-
self._plot_combined_histograms(fig_name)
|
|
43
|
+
self._list_of_histograms = None
|
|
44
|
+
self._combined_hists = None
|
|
45
|
+
self.__meta_dict = None
|
|
50
46
|
|
|
51
47
|
@property
|
|
52
48
|
def number_of_histograms(self):
|
|
53
49
|
"""Returns number of histograms."""
|
|
54
|
-
if not hasattr(self, "combined_hists"):
|
|
55
|
-
self._combine_histogram_files()
|
|
56
50
|
return len(self.combined_hists)
|
|
57
51
|
|
|
58
52
|
def get_histogram_title(self, i_hist):
|
|
@@ -69,83 +63,199 @@ class SimtelHistograms:
|
|
|
69
63
|
str
|
|
70
64
|
Histogram title.
|
|
71
65
|
"""
|
|
72
|
-
if not hasattr(self, "combined_hists"):
|
|
73
|
-
self._combine_histogram_files()
|
|
74
66
|
return self.combined_hists[i_hist]["title"]
|
|
75
67
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
68
|
+
@property
|
|
69
|
+
def list_of_histograms(self):
|
|
70
|
+
"""
|
|
71
|
+
Returns a list with the histograms for each file.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
list:
|
|
76
|
+
List of histograms.
|
|
77
|
+
"""
|
|
78
|
+
if self._list_of_histograms is None:
|
|
79
|
+
self._list_of_histograms = []
|
|
80
|
+
for file in self._histogram_files:
|
|
81
|
+
with EventIOFile(file) as f:
|
|
82
|
+
for o in yield_toplevel_of_type(f, Histograms):
|
|
87
83
|
hists = o.parse()
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
self.combined_hists = copy.copy(hists)
|
|
96
|
-
|
|
97
|
-
else:
|
|
98
|
-
# Remaining files
|
|
99
|
-
for hist, this_combined_hist in zip(hists, self.combined_hists):
|
|
100
|
-
# Checking consistency of histograms
|
|
101
|
-
for key_to_test in [
|
|
102
|
-
"lower_x",
|
|
103
|
-
"upper_x",
|
|
104
|
-
"n_bins_x",
|
|
105
|
-
"title",
|
|
106
|
-
]:
|
|
107
|
-
if hist[key_to_test] != this_combined_hist[key_to_test]:
|
|
108
|
-
msg = "Trying to add histograms with inconsistent dimensions"
|
|
109
|
-
self._logger.error(msg)
|
|
110
|
-
raise BadHistogramFormat(msg)
|
|
111
|
-
|
|
112
|
-
this_combined_hist["data"] = np.add(
|
|
113
|
-
this_combined_hist["data"], hist["data"]
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
n_files += int(count_file)
|
|
117
|
-
|
|
118
|
-
self._logger.debug(f"End of reading {n_files} files")
|
|
119
|
-
|
|
120
|
-
def _plot_combined_histograms(self, fig_name):
|
|
121
|
-
"""
|
|
122
|
-
Plot all histograms into pdf pages and save the figure as a pdf file.
|
|
84
|
+
self._list_of_histograms.append(hists)
|
|
85
|
+
return self._list_of_histograms
|
|
86
|
+
|
|
87
|
+
def _check_consistency(self, first_hist_file, second_hist_file):
|
|
88
|
+
"""
|
|
89
|
+
Checks whether two histograms have the same format.
|
|
90
|
+
Raises an error in case they are not consistent.
|
|
123
91
|
|
|
124
92
|
Parameters
|
|
125
93
|
----------
|
|
126
|
-
|
|
127
|
-
|
|
94
|
+
first_hist_file: dict
|
|
95
|
+
One histogram from a single file.
|
|
96
|
+
second_hist_file: dict
|
|
97
|
+
One histogram from a single file.
|
|
98
|
+
|
|
99
|
+
Raises
|
|
100
|
+
------
|
|
101
|
+
InconsistentHistogramFormat:
|
|
102
|
+
if the format of the histograms have inconsistent dimensions.
|
|
103
|
+
"""
|
|
104
|
+
for key_to_test in [
|
|
105
|
+
"lower_x",
|
|
106
|
+
"upper_x",
|
|
107
|
+
"n_bins_x",
|
|
108
|
+
"title",
|
|
109
|
+
]:
|
|
110
|
+
if first_hist_file[key_to_test] != second_hist_file[key_to_test]:
|
|
111
|
+
msg = "Trying to add histograms with inconsistent dimensions"
|
|
112
|
+
self._logger.error(msg)
|
|
113
|
+
raise InconsistentHistogramFormat(msg)
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def combined_hists(self):
|
|
117
|
+
"""Add the values of the same type of histogram from the various lists into a single
|
|
118
|
+
histogram list."""
|
|
119
|
+
# Processing and combining histograms from multiple files
|
|
120
|
+
if self._combined_hists is None:
|
|
121
|
+
self._combined_hists = []
|
|
122
|
+
for i_hist, hists_one_file in enumerate(self.list_of_histograms):
|
|
123
|
+
if i_hist == 0:
|
|
124
|
+
# First file
|
|
125
|
+
self._combined_hists = copy.copy(hists_one_file)
|
|
126
|
+
|
|
127
|
+
else:
|
|
128
|
+
for hist, this_combined_hist in zip(hists_one_file, self._combined_hists):
|
|
129
|
+
self._check_consistency(hist, this_combined_hist)
|
|
130
|
+
|
|
131
|
+
this_combined_hist["data"] = np.add(
|
|
132
|
+
this_combined_hist["data"], hist["data"]
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
self._logger.debug(f"End of reading {len(self.list_of_histograms)} files")
|
|
136
|
+
return self._combined_hists
|
|
137
|
+
|
|
138
|
+
@combined_hists.setter
|
|
139
|
+
def combined_hists(self, new_combined_hists):
|
|
128
140
|
"""
|
|
141
|
+
Setter for combined_hists.
|
|
129
142
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
143
|
+
Parameters
|
|
144
|
+
----------
|
|
145
|
+
new_combined_hists:
|
|
146
|
+
Combined histograms.
|
|
147
|
+
"""
|
|
148
|
+
self._combined_hists = new_combined_hists
|
|
136
149
|
|
|
137
|
-
|
|
150
|
+
def _derive_trigger_rate_histograms(self, livetime):
|
|
151
|
+
"""
|
|
152
|
+
Calculates the trigger rate histograms, i.e., the ratio in which the events
|
|
153
|
+
are triggered in each bin of impact distance and log energy for each histogram file for
|
|
154
|
+
the livetime defined by `livetime`.
|
|
155
|
+
The livetime gives the amount of time used in a small production to produce the histograms
|
|
156
|
+
used. It is assumed that the livetime is the same for all the histogram files used and that
|
|
157
|
+
the radius (x-axis in the histograms) is given in meters.
|
|
138
158
|
|
|
139
|
-
|
|
140
|
-
|
|
159
|
+
Parameters
|
|
160
|
+
----------
|
|
161
|
+
livetime: astropy.Quantity
|
|
162
|
+
Time used in the simulation that produced the histograms. E.g., 1*u.h.
|
|
141
163
|
|
|
142
|
-
|
|
164
|
+
Returns
|
|
165
|
+
-------
|
|
166
|
+
list:
|
|
167
|
+
List with the trigger rate histograms for each file.
|
|
168
|
+
"""
|
|
169
|
+
if isinstance(livetime, u.Quantity):
|
|
170
|
+
livetime = livetime.to(u.s)
|
|
171
|
+
else:
|
|
172
|
+
livetime = livetime * u.s
|
|
173
|
+
events_histogram = {}
|
|
174
|
+
trigged_events_histogram = {}
|
|
175
|
+
# Save the appropriate histograms to a dictionary
|
|
176
|
+
for i_file, hists_one_file in enumerate(self.list_of_histograms):
|
|
177
|
+
for hist in hists_one_file:
|
|
178
|
+
if hist["id"] == 1:
|
|
179
|
+
events_histogram[i_file] = hist
|
|
180
|
+
|
|
181
|
+
elif hist["id"] == 2:
|
|
182
|
+
trigged_events_histogram[i_file] = hist
|
|
183
|
+
|
|
184
|
+
list_of_trigger_rate_hists = []
|
|
185
|
+
# Calculate the event rate histograms
|
|
186
|
+
for i_file, hists_one_file in enumerate(self.list_of_histograms):
|
|
187
|
+
event_rate_histogram = copy.copy(events_histogram[i_file])
|
|
188
|
+
area_dict = np.pi * (
|
|
189
|
+
(events_histogram[i_file]["upper_x"]) ** 2
|
|
190
|
+
- (events_histogram[i_file]["lower_x"]) ** 2
|
|
191
|
+
)
|
|
143
192
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
193
|
+
event_rate_histogram["data"] = (
|
|
194
|
+
np.zeros_like(trigged_events_histogram[i_file]["data"]) / livetime.unit
|
|
195
|
+
)
|
|
196
|
+
bins_with_events = events_histogram[i_file]["data"] != 0
|
|
197
|
+
event_rate_histogram["data"][bins_with_events] = (
|
|
198
|
+
trigged_events_histogram[i_file]["data"][bins_with_events]
|
|
199
|
+
/ events_histogram[i_file]["data"][bins_with_events]
|
|
200
|
+
* area_dict
|
|
201
|
+
/ livetime
|
|
202
|
+
)
|
|
147
203
|
|
|
148
|
-
|
|
204
|
+
# Keeping only the necessary information for proceeding with integration
|
|
205
|
+
keys_to_keep = [
|
|
206
|
+
"data",
|
|
207
|
+
"lower_x",
|
|
208
|
+
"lower_y",
|
|
209
|
+
"upper_x",
|
|
210
|
+
"upper_y",
|
|
211
|
+
"entries",
|
|
212
|
+
"n_bins_x",
|
|
213
|
+
"n_bins_y",
|
|
214
|
+
]
|
|
215
|
+
event_rate_histogram = {
|
|
216
|
+
key: event_rate_histogram[key]
|
|
217
|
+
for key in keys_to_keep
|
|
218
|
+
if key in event_rate_histogram
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
list_of_trigger_rate_hists.append(event_rate_histogram)
|
|
222
|
+
return list_of_trigger_rate_hists
|
|
223
|
+
|
|
224
|
+
def _integrate_trigger_rate_histograms(self, hists):
|
|
225
|
+
"""
|
|
226
|
+
Integrates in energy the trigger rate histogram based on the histogram bin edges.
|
|
227
|
+
|
|
228
|
+
Parameters
|
|
229
|
+
----------
|
|
230
|
+
hists: list
|
|
231
|
+
List with the final trigger rate for each histogram.
|
|
232
|
+
"""
|
|
233
|
+
|
|
234
|
+
list_of_integrated_hists = []
|
|
235
|
+
for _, hist in enumerate(hists):
|
|
236
|
+
energy_axis = np.logspace(hist["lower_y"], hist["upper_y"], hist["n_bins_y"])
|
|
237
|
+
radius_axis = np.linspace(hist["lower_x"], hist["upper_x"], hist["n_bins_x"])
|
|
238
|
+
integrated_hist = np.zeros_like(radius_axis)
|
|
239
|
+
for i_radius, _ in enumerate(radius_axis):
|
|
240
|
+
integrated_hist[i_radius] = np.sum(
|
|
241
|
+
hist["data"][:-1, i_radius].value * np.diff(energy_axis)
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
list_of_integrated_hists.append(np.sum(integrated_hist) * hist["data"][0, 0].unit)
|
|
245
|
+
return list_of_integrated_hists
|
|
246
|
+
|
|
247
|
+
def trigger_rate_per_histogram(self, livetime):
|
|
248
|
+
"""
|
|
249
|
+
Estimates the trigger rate for each histogram passed.
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
livetime: astropy.Quantity
|
|
254
|
+
Time used in the simulation that produced the histograms.
|
|
255
|
+
"""
|
|
256
|
+
hists = self._derive_trigger_rate_histograms(livetime=livetime)
|
|
257
|
+
trigger_rates = self._integrate_trigger_rate_histograms(hists)
|
|
258
|
+
return trigger_rates
|
|
149
259
|
|
|
150
260
|
def plot_one_histogram(self, i_hist, ax):
|
|
151
261
|
"""
|
|
@@ -229,3 +339,76 @@ class SimtelHistograms:
|
|
|
229
339
|
ax.hist(centers, bins=x_bins, weights=hist["data"])
|
|
230
340
|
ax.set_xlim(xlim)
|
|
231
341
|
return
|
|
342
|
+
|
|
343
|
+
@property
|
|
344
|
+
def _meta_dict(self):
|
|
345
|
+
"""
|
|
346
|
+
Define the meta dictionary for exporting the histograms.
|
|
347
|
+
|
|
348
|
+
Returns
|
|
349
|
+
-------
|
|
350
|
+
dict
|
|
351
|
+
Meta dictionary for the hdf5 files with the histograms.
|
|
352
|
+
"""
|
|
353
|
+
|
|
354
|
+
if self.__meta_dict is None:
|
|
355
|
+
self.__meta_dict = {
|
|
356
|
+
"simtools_version": version.__version__,
|
|
357
|
+
"note": "Only lower bin edges are given.",
|
|
358
|
+
}
|
|
359
|
+
return self.__meta_dict
|
|
360
|
+
|
|
361
|
+
def export_histograms(self, hdf5_file_name, overwrite=False):
|
|
362
|
+
"""
|
|
363
|
+
Export the histograms to hdf5 files.
|
|
364
|
+
|
|
365
|
+
Parameters
|
|
366
|
+
----------
|
|
367
|
+
hdf5_file_name: str
|
|
368
|
+
Name of the file to be saved with the hdf5 tables.
|
|
369
|
+
overwrite: bool
|
|
370
|
+
If True overwrites the histograms already saved in the hdf5 file.
|
|
371
|
+
"""
|
|
372
|
+
for histogram in self.combined_hists:
|
|
373
|
+
x_bin_edges_list = np.linspace(
|
|
374
|
+
histogram["lower_x"],
|
|
375
|
+
histogram["upper_x"],
|
|
376
|
+
num=histogram["n_bins_x"] + 1,
|
|
377
|
+
endpoint=True,
|
|
378
|
+
)
|
|
379
|
+
if histogram["n_bins_y"] > 0:
|
|
380
|
+
y_bin_edges_list = np.linspace(
|
|
381
|
+
histogram["lower_y"],
|
|
382
|
+
histogram["upper_y"],
|
|
383
|
+
num=histogram["n_bins_y"] + 1,
|
|
384
|
+
endpoint=True,
|
|
385
|
+
)
|
|
386
|
+
else:
|
|
387
|
+
y_bin_edges_list = None
|
|
388
|
+
|
|
389
|
+
self._meta_dict["Title"] = sanitize_name(histogram["title"])
|
|
390
|
+
|
|
391
|
+
table = fill_hdf5_table(
|
|
392
|
+
hist=histogram["data"],
|
|
393
|
+
x_bin_edges=x_bin_edges_list,
|
|
394
|
+
y_bin_edges=y_bin_edges_list,
|
|
395
|
+
x_label=None,
|
|
396
|
+
y_label=None,
|
|
397
|
+
meta_data=self._meta_dict,
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
self._logger.debug(
|
|
401
|
+
f"Writing histogram with name {self._meta_dict['Title']} to " f"{hdf5_file_name}."
|
|
402
|
+
)
|
|
403
|
+
# overwrite takes precedence over append
|
|
404
|
+
if overwrite is True:
|
|
405
|
+
append = False
|
|
406
|
+
else:
|
|
407
|
+
append = True
|
|
408
|
+
write_table(
|
|
409
|
+
table,
|
|
410
|
+
hdf5_file_name,
|
|
411
|
+
f"/{self._meta_dict['Title']}",
|
|
412
|
+
append=append,
|
|
413
|
+
overwrite=overwrite,
|
|
414
|
+
)
|
simtools/simtel/simtel_runner.py
CHANGED
|
@@ -45,7 +45,7 @@ class SimtelRunner:
|
|
|
45
45
|
self._script_dir = None
|
|
46
46
|
self._script_file = None
|
|
47
47
|
|
|
48
|
-
self.
|
|
48
|
+
self.runs_per_set = 1
|
|
49
49
|
|
|
50
50
|
def __repr__(self):
|
|
51
51
|
return f"SimtelRunner(label={self.label})\n"
|
|
@@ -140,8 +140,8 @@ class SimtelRunner:
|
|
|
140
140
|
file.write(f"{line}\n")
|
|
141
141
|
file.write("# End of extras\n\n")
|
|
142
142
|
|
|
143
|
-
|
|
144
|
-
for _ in range(
|
|
143
|
+
n = 1 if test else self.runs_per_set
|
|
144
|
+
for _ in range(n):
|
|
145
145
|
file.write(f"{command}\n\n")
|
|
146
146
|
|
|
147
147
|
# Printing out runtime
|
|
@@ -178,10 +178,10 @@ class SimtelRunner:
|
|
|
178
178
|
self._logger.info(f"Running (test) with command: {command}")
|
|
179
179
|
self._run_simtel_and_check_output(command)
|
|
180
180
|
else:
|
|
181
|
-
self._logger.debug(f"Running ({self.
|
|
181
|
+
self._logger.debug(f"Running ({self.runs_per_set}x) with command: {command}")
|
|
182
182
|
self._run_simtel_and_check_output(command)
|
|
183
183
|
|
|
184
|
-
for _ in range(self.
|
|
184
|
+
for _ in range(self.runs_per_set - 1):
|
|
185
185
|
self._run_simtel_and_check_output(command)
|
|
186
186
|
|
|
187
187
|
self._check_run_result(run_number=run_number)
|
|
@@ -236,8 +236,9 @@ class SimtelRunner:
|
|
|
236
236
|
return False
|
|
237
237
|
|
|
238
238
|
@staticmethod
|
|
239
|
-
def _config_option(par, value=None):
|
|
239
|
+
def _config_option(par, value=None, weak_option=False):
|
|
240
240
|
"""Util function for building sim_telarray command."""
|
|
241
|
-
|
|
241
|
+
option_syntax = "-W" if weak_option else "-C"
|
|
242
|
+
c = f" {option_syntax} {par}"
|
|
242
243
|
c += f"={value}" if value is not None else ""
|
|
243
244
|
return c
|
|
@@ -2,7 +2,7 @@ import logging
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
4
|
import simtools.utils.general as gen
|
|
5
|
-
from simtools import io_handler
|
|
5
|
+
from simtools.io_operations import io_handler
|
|
6
6
|
from simtools.simtel.simtel_runner import InvalidOutputFile, SimtelRunner
|
|
7
7
|
|
|
8
8
|
__all__ = ["SimtelRunnerArray"]
|
|
@@ -68,11 +68,11 @@ class SimtelRunnerArray(SimtelRunner):
|
|
|
68
68
|
self._base_directory = self.io_handler.get_output_directory(self.label, "array-simulator")
|
|
69
69
|
|
|
70
70
|
# Loading config_data
|
|
71
|
-
_config_data_in = gen.
|
|
71
|
+
_config_data_in = gen.collect_data_from_file_or_dict(config_file, config_data)
|
|
72
72
|
_parameter_file = self.io_handler.get_input_data_file(
|
|
73
73
|
"parameters", "simtel-runner-array_parameters.yml"
|
|
74
74
|
)
|
|
75
|
-
_parameters = gen.
|
|
75
|
+
_parameters = gen.collect_data_from_file_or_dict(_parameter_file, None)
|
|
76
76
|
self.config = gen.validate_config_data(_config_data_in, _parameters)
|
|
77
77
|
|
|
78
78
|
self._load_simtel_data_directories()
|
|
@@ -105,7 +105,7 @@ class SimtelRunnerArray(SimtelRunner):
|
|
|
105
105
|
|
|
106
106
|
def get_info_for_file_name(self, run_number):
|
|
107
107
|
"""
|
|
108
|
-
Get a
|
|
108
|
+
Get a dictionary with the info necessary for building the sim_telarray file names.
|
|
109
109
|
|
|
110
110
|
Returns
|
|
111
111
|
-------
|
|
@@ -226,7 +226,7 @@ class SimtelRunnerArray(SimtelRunner):
|
|
|
226
226
|
_resources = {}
|
|
227
227
|
|
|
228
228
|
_resources["runtime"] = None
|
|
229
|
-
with open(sub_log_file, "r") as file:
|
|
229
|
+
with open(sub_log_file, "r", encoding="utf-8") as file:
|
|
230
230
|
for line in reversed(list(file)):
|
|
231
231
|
if "RUNTIME" in line:
|
|
232
232
|
_resources["runtime"] = int(line.split()[1])
|
|
@@ -274,7 +274,7 @@ class SimtelRunnerArray(SimtelRunner):
|
|
|
274
274
|
command += super()._config_option("power_law", "2.5")
|
|
275
275
|
command += super()._config_option("histogram_file", histogram_file)
|
|
276
276
|
command += super()._config_option("output_file", output_file)
|
|
277
|
-
command += super()._config_option("random_state", "
|
|
277
|
+
command += super()._config_option("random_state", "none")
|
|
278
278
|
command += super()._config_option("show", "all")
|
|
279
279
|
command += f" {kwargs['input_file']}"
|
|
280
280
|
command += f" > {self._log_file} 2>&1 || exit"
|
|
@@ -290,5 +290,4 @@ class SimtelRunnerArray(SimtelRunner):
|
|
|
290
290
|
msg = "sim_telarray output file does not exist."
|
|
291
291
|
self._logger.error(msg)
|
|
292
292
|
raise InvalidOutputFile(msg)
|
|
293
|
-
|
|
294
|
-
self._logger.debug("Everything looks fine with the sim_telarray output file.")
|
|
293
|
+
self._logger.debug(f"simtel_array output file {output_file} exists.")
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from pathlib import Path
|
|
2
3
|
|
|
3
4
|
from simtools.simtel.simtel_runner import SimtelRunner
|
|
4
5
|
|
|
@@ -32,6 +33,7 @@ class SimtelRunnerCameraEfficiency(SimtelRunner):
|
|
|
32
33
|
file_simtel=None,
|
|
33
34
|
file_log=None,
|
|
34
35
|
zenith_angle=None,
|
|
36
|
+
nsb_spectrum=None,
|
|
35
37
|
):
|
|
36
38
|
"""
|
|
37
39
|
Initialize SimtelRunner.
|
|
@@ -47,6 +49,20 @@ class SimtelRunnerCameraEfficiency(SimtelRunner):
|
|
|
47
49
|
self._file_simtel = file_simtel
|
|
48
50
|
self._file_log = file_log
|
|
49
51
|
self.zenith_angle = zenith_angle
|
|
52
|
+
self.nsb_spectrum = nsb_spectrum
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def nsb_spectrum(self):
|
|
56
|
+
"""nsb_spectrum property"""
|
|
57
|
+
return self._nsb_spectrum
|
|
58
|
+
|
|
59
|
+
@nsb_spectrum.setter
|
|
60
|
+
def nsb_spectrum(self, nsb_spectrum):
|
|
61
|
+
"""Setter for nsb_spectrum"""
|
|
62
|
+
if nsb_spectrum is not None:
|
|
63
|
+
self._nsb_spectrum = self._validate_or_fix_nsb_spectrum_file_format(nsb_spectrum)
|
|
64
|
+
else:
|
|
65
|
+
self._nsb_spectrum = None
|
|
50
66
|
|
|
51
67
|
def _shall_run(self, **kwargs): # pylint: disable=unused-argument; applies only to this line
|
|
52
68
|
"""Tells if simulations should be run again based on the existence of output files."""
|
|
@@ -83,7 +99,7 @@ class SimtelRunnerCameraEfficiency(SimtelRunner):
|
|
|
83
99
|
# Processing camera filter
|
|
84
100
|
# A special case is testeff does not support 2D distributions
|
|
85
101
|
camera_filter_file = self._telescope_model.get_parameter_value("camera_filter")
|
|
86
|
-
if self._telescope_model.
|
|
102
|
+
if self._telescope_model.is_file_2d("camera_filter"):
|
|
87
103
|
camera_filter_file = self._get_one_dim_distribution(
|
|
88
104
|
"camera_filter", "camera_filter_incidence_angle"
|
|
89
105
|
)
|
|
@@ -93,7 +109,7 @@ class SimtelRunnerCameraEfficiency(SimtelRunner):
|
|
|
93
109
|
mirror_reflectivity = self._telescope_model.get_parameter_value("mirror_reflectivity")
|
|
94
110
|
if mirror_class == 2:
|
|
95
111
|
mirror_reflectivity_secondary = mirror_reflectivity
|
|
96
|
-
if self._telescope_model.
|
|
112
|
+
if self._telescope_model.is_file_2d("mirror_reflectivity"):
|
|
97
113
|
mirror_reflectivity = self._get_one_dim_distribution(
|
|
98
114
|
"mirror_reflectivity", "primary_mirror_incidence_angle"
|
|
99
115
|
)
|
|
@@ -102,6 +118,8 @@ class SimtelRunnerCameraEfficiency(SimtelRunner):
|
|
|
102
118
|
)
|
|
103
119
|
|
|
104
120
|
command = str(self._simtel_source_path.joinpath("sim_telarray/bin/testeff"))
|
|
121
|
+
if self.nsb_spectrum is not None:
|
|
122
|
+
command += f" -fnsb {self.nsb_spectrum}"
|
|
105
123
|
command += " -nm -nsb-extra"
|
|
106
124
|
command += f" -alt {self._telescope_model.get_parameter_value('altitude')}"
|
|
107
125
|
command += f" -fatm {self._telescope_model.get_parameter_value('atmospheric_transmission')}"
|
|
@@ -190,3 +208,31 @@ class SimtelRunnerCameraEfficiency(SimtelRunner):
|
|
|
190
208
|
)
|
|
191
209
|
|
|
192
210
|
return one_dim_file
|
|
211
|
+
|
|
212
|
+
def _validate_or_fix_nsb_spectrum_file_format(self, nsb_spectrum_file):
|
|
213
|
+
"""
|
|
214
|
+
Validate or fix the nsb spectrum file format.
|
|
215
|
+
The nsb spectrum file format required by sim_telarray has three columns:
|
|
216
|
+
wavelength (nm), ignored, NSB flux [1e9 * ph/m2/s/sr/nm],
|
|
217
|
+
where the second column is ignored by sim_telarray and the third is used for the NSB flux.
|
|
218
|
+
This function makes sure the file has at least three columns,
|
|
219
|
+
by copying the second column to the third.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
validated_nsb_spectrum_file = (
|
|
223
|
+
self._telescope_model.get_config_directory() / Path(nsb_spectrum_file).name
|
|
224
|
+
)
|
|
225
|
+
with open(nsb_spectrum_file, "r", encoding="utf-8") as file:
|
|
226
|
+
lines = file.readlines()
|
|
227
|
+
with open(validated_nsb_spectrum_file, "w", encoding="utf-8") as file:
|
|
228
|
+
for line in lines:
|
|
229
|
+
if line.startswith("#"):
|
|
230
|
+
file.write(line)
|
|
231
|
+
continue
|
|
232
|
+
split_line = line.split()
|
|
233
|
+
if len(split_line) == 2:
|
|
234
|
+
split_line.append(split_line[1])
|
|
235
|
+
file.write(f"{split_line[0]} {split_line[1]} {split_line[2]}\n")
|
|
236
|
+
else:
|
|
237
|
+
file.write(line)
|
|
238
|
+
return validated_nsb_spectrum_file
|