gammasimtools 0.19.0__py3-none-any.whl → 0.20.0__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.19.0.dist-info → gammasimtools-0.20.0.dist-info}/METADATA +1 -3
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.20.0.dist-info}/RECORD +43 -41
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.20.0.dist-info}/entry_points.txt +2 -2
- simtools/_version.py +2 -2
- simtools/applications/calculate_incident_angles.py +182 -0
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +17 -14
- simtools/applications/db_add_value_from_json_to_db.py +6 -9
- simtools/applications/db_generate_compound_indexes.py +7 -3
- simtools/applications/db_get_file_from_db.py +11 -23
- simtools/applications/derive_trigger_rates.py +91 -0
- simtools/applications/plot_simtel_events.py +73 -31
- simtools/applications/validate_file_using_schema.py +7 -4
- simtools/configuration/commandline_parser.py +17 -11
- simtools/data_model/validate_data.py +8 -3
- simtools/db/db_handler.py +83 -26
- simtools/db/db_model_upload.py +11 -16
- simtools/dependencies.py +10 -5
- simtools/layout/array_layout_utils.py +37 -5
- simtools/model/array_model.py +18 -1
- simtools/model/site_model.py +25 -0
- simtools/production_configuration/derive_corsika_limits.py +9 -34
- simtools/ray_tracing/incident_angles.py +706 -0
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +2 -2
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_spectrum.schema.yml +22 -29
- simtools/schemas/model_parameters/stars.schema.yml +1 -1
- simtools/schemas/production_tables.schema.yml +5 -0
- simtools/simtel/simtel_config_writer.py +17 -19
- simtools/simtel/simtel_io_event_histograms.py +253 -516
- simtools/simtel/simtel_io_event_reader.py +51 -2
- simtools/simtel/simtel_io_event_writer.py +31 -11
- simtools/simtel/simtel_io_metadata.py +1 -1
- simtools/simtel/simtel_table_reader.py +3 -3
- simtools/telescope_trigger_rates.py +119 -0
- simtools/testing/log_inspector.py +13 -11
- simtools/utils/geometry.py +20 -0
- simtools/visualization/plot_incident_angles.py +431 -0
- simtools/visualization/plot_simtel_event_histograms.py +376 -0
- simtools/visualization/visualize.py +1 -3
- simtools/applications/calculate_trigger_rate.py +0 -187
- simtools/applications/generate_sim_telarray_histograms.py +0 -196
- simtools/simtel/simtel_io_histogram.py +0 -623
- simtools/simtel/simtel_io_histograms.py +0 -556
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.20.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.20.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.19.0.dist-info → gammasimtools-0.20.0.dist-info}/top_level.txt +0 -0
- /simtools/visualization/{simtel_event_plots.py → plot_simtel_events.py} +0 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
r"""
|
|
2
|
+
Derive cosmic-ray trigger rates for a single telescope or an array of telescopes.
|
|
3
|
+
|
|
4
|
+
Uses simulated background events (e.g. from proton primaries) to calculate the trigger rates.
|
|
5
|
+
Input is reduced event data generated from simulations for the given configuration.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Command line arguments
|
|
9
|
+
----------------------
|
|
10
|
+
event_data_file (str, required)
|
|
11
|
+
Event data file containing reduced event data.
|
|
12
|
+
array_layout_name (list, optional)
|
|
13
|
+
Name of the array layout to use for the simulation.
|
|
14
|
+
telescope_ids (str, optional)
|
|
15
|
+
Path to a file containing telescope configurations.
|
|
16
|
+
plot_histograms (bool, optional)
|
|
17
|
+
Plot histograms of the event data.
|
|
18
|
+
model_version (str, optional)
|
|
19
|
+
Version of the simulation model to use.
|
|
20
|
+
site (str, optional)
|
|
21
|
+
Name of the site where the simulation is being run.
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
Example
|
|
25
|
+
-------
|
|
26
|
+
|
|
27
|
+
Derive trigger rates for the South Alpha layout:
|
|
28
|
+
|
|
29
|
+
.. code-block:: console
|
|
30
|
+
|
|
31
|
+
simtools-derive-trigger-rates \\
|
|
32
|
+
--site South \\
|
|
33
|
+
--model_version 6.0.0 \\
|
|
34
|
+
--event_data_file /path/to/event_data_file.h5 \\
|
|
35
|
+
--array_layout_name alpha\\
|
|
36
|
+
--plot_histograms
|
|
37
|
+
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
import logging
|
|
41
|
+
|
|
42
|
+
import simtools.utils.general as gen
|
|
43
|
+
from simtools.configuration import configurator
|
|
44
|
+
from simtools.telescope_trigger_rates import telescope_trigger_rates
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _parse():
|
|
48
|
+
"""Parse command line configuration."""
|
|
49
|
+
config = configurator.Configurator(
|
|
50
|
+
description="Derive trigger rates for a single telescope or an array of telescopes.",
|
|
51
|
+
)
|
|
52
|
+
config.parser.add_argument(
|
|
53
|
+
"--event_data_file",
|
|
54
|
+
type=str,
|
|
55
|
+
required=True,
|
|
56
|
+
help="Event data file containing reduced event data.",
|
|
57
|
+
)
|
|
58
|
+
config.parser.add_argument(
|
|
59
|
+
"--telescope_ids",
|
|
60
|
+
type=str,
|
|
61
|
+
required=False,
|
|
62
|
+
help="Path to a file containing telescope configurations.",
|
|
63
|
+
)
|
|
64
|
+
config.parser.add_argument(
|
|
65
|
+
"--plot_histograms",
|
|
66
|
+
help="Plot histograms of the event data.",
|
|
67
|
+
action="store_true",
|
|
68
|
+
default=False,
|
|
69
|
+
)
|
|
70
|
+
return config.initialize(
|
|
71
|
+
db_config=True,
|
|
72
|
+
output=True,
|
|
73
|
+
simulation_model=[
|
|
74
|
+
"site",
|
|
75
|
+
"model_version",
|
|
76
|
+
"layout",
|
|
77
|
+
],
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def main(): # noqa: D103
|
|
82
|
+
args_dict, db_config = _parse()
|
|
83
|
+
|
|
84
|
+
logger = logging.getLogger()
|
|
85
|
+
logger.setLevel(gen.get_log_level_from_user(args_dict.get("log_level", "info")))
|
|
86
|
+
|
|
87
|
+
telescope_trigger_rates(args_dict, db_config)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
main()
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
r"""
|
|
4
4
|
Plot simulated events.
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
Produces figures from one or more sim_telarray (.simtel.zst) files
|
|
7
|
+
It is meant to run after simulations (e.g., simtools-simulate-flasher,
|
|
8
|
+
simtools-simulate-illuminator).
|
|
9
9
|
|
|
10
10
|
What it does
|
|
11
11
|
------------
|
|
@@ -84,7 +84,7 @@ from simtools.configuration import configurator
|
|
|
84
84
|
from simtools.corsika.corsika_histograms_visualize import save_figs_to_pdf
|
|
85
85
|
from simtools.data_model.metadata_collector import MetadataCollector
|
|
86
86
|
from simtools.io import io_handler
|
|
87
|
-
from simtools.visualization.
|
|
87
|
+
from simtools.visualization.plot_simtel_events import (
|
|
88
88
|
plot_simtel_event_image,
|
|
89
89
|
plot_simtel_integrated_pedestal_image,
|
|
90
90
|
plot_simtel_integrated_signal_image,
|
|
@@ -106,6 +106,64 @@ PLOT_CHOICES = {
|
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
|
|
109
|
+
def _call_peak_timing(
|
|
110
|
+
filename,
|
|
111
|
+
*,
|
|
112
|
+
tel_id=None,
|
|
113
|
+
sum_threshold=10.0,
|
|
114
|
+
peak_width=8,
|
|
115
|
+
examples=3,
|
|
116
|
+
timing_bins=None,
|
|
117
|
+
event_index=None,
|
|
118
|
+
):
|
|
119
|
+
"""Call ``plot_simtel_peak_timing`` and support optional ``return_stats``.
|
|
120
|
+
|
|
121
|
+
Parameters
|
|
122
|
+
----------
|
|
123
|
+
filename : pathlib.Path or str
|
|
124
|
+
Path to the input simtel file.
|
|
125
|
+
tel_id : int, optional
|
|
126
|
+
Telescope ID to visualize.
|
|
127
|
+
sum_threshold : float, default 10.0
|
|
128
|
+
Minimum pixel sum to consider a pixel.
|
|
129
|
+
peak_width : int, default 8
|
|
130
|
+
Expected peak width in samples.
|
|
131
|
+
examples : int, default 3
|
|
132
|
+
Number of example traces to draw.
|
|
133
|
+
timing_bins : int or None, optional
|
|
134
|
+
Number of bins for timing histogram (contiguous if not set).
|
|
135
|
+
event_index : int or None, optional
|
|
136
|
+
0-based index of the event to plot; default is the first event.
|
|
137
|
+
|
|
138
|
+
Returns
|
|
139
|
+
-------
|
|
140
|
+
object or None
|
|
141
|
+
The matplotlib Figure if available, otherwise ``None``.
|
|
142
|
+
"""
|
|
143
|
+
try:
|
|
144
|
+
fig_stats = plot_simtel_peak_timing(
|
|
145
|
+
filename,
|
|
146
|
+
tel_id=tel_id,
|
|
147
|
+
sum_threshold=sum_threshold,
|
|
148
|
+
peak_width=peak_width,
|
|
149
|
+
examples=examples,
|
|
150
|
+
timing_bins=timing_bins,
|
|
151
|
+
return_stats=True,
|
|
152
|
+
event_index=event_index,
|
|
153
|
+
)
|
|
154
|
+
return fig_stats[0] if isinstance(fig_stats, tuple) else fig_stats
|
|
155
|
+
except TypeError:
|
|
156
|
+
return plot_simtel_peak_timing(
|
|
157
|
+
filename,
|
|
158
|
+
tel_id=tel_id,
|
|
159
|
+
sum_threshold=sum_threshold,
|
|
160
|
+
peak_width=peak_width,
|
|
161
|
+
examples=examples,
|
|
162
|
+
timing_bins=timing_bins,
|
|
163
|
+
event_index=event_index,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
109
167
|
def _parse(label: str):
|
|
110
168
|
"""Parse command line configuration."""
|
|
111
169
|
config = configurator.Configurator(
|
|
@@ -263,30 +321,6 @@ def _collect_figures_for_file(
|
|
|
263
321
|
else list(plots)
|
|
264
322
|
)
|
|
265
323
|
|
|
266
|
-
def _call_peak_timing():
|
|
267
|
-
try:
|
|
268
|
-
fig_stats = plot_simtel_peak_timing(
|
|
269
|
-
filename,
|
|
270
|
-
tel_id=args.get("tel_id"),
|
|
271
|
-
sum_threshold=args.get("sum_threshold", 10.0),
|
|
272
|
-
peak_width=args.get("peak_width", 8),
|
|
273
|
-
examples=args.get("examples", 3),
|
|
274
|
-
timing_bins=args.get("timing_bins"),
|
|
275
|
-
return_stats=True,
|
|
276
|
-
event_index=args.get("event_index"),
|
|
277
|
-
)
|
|
278
|
-
return fig_stats[0] if isinstance(fig_stats, tuple) else fig_stats
|
|
279
|
-
except TypeError:
|
|
280
|
-
return plot_simtel_peak_timing(
|
|
281
|
-
filename,
|
|
282
|
-
tel_id=args.get("tel_id"),
|
|
283
|
-
sum_threshold=args.get("sum_threshold", 10.0),
|
|
284
|
-
peak_width=args.get("peak_width", 8),
|
|
285
|
-
examples=args.get("examples", 3),
|
|
286
|
-
timing_bins=args.get("timing_bins"),
|
|
287
|
-
event_index=args.get("event_index"),
|
|
288
|
-
)
|
|
289
|
-
|
|
290
324
|
# function name -> (callable, defaults)
|
|
291
325
|
dispatch: dict[str, tuple[object, dict[str, object]]] = {
|
|
292
326
|
"event_image": (
|
|
@@ -313,12 +347,20 @@ def _collect_figures_for_file(
|
|
|
313
347
|
plot_simtel_integrated_pedestal_image,
|
|
314
348
|
{"tel_id": None, "half_width": 8, "offset": 16, "event_index": None},
|
|
315
349
|
),
|
|
350
|
+
"peak_timing": (
|
|
351
|
+
_call_peak_timing,
|
|
352
|
+
{
|
|
353
|
+
"tel_id": None,
|
|
354
|
+
"sum_threshold": 10.0,
|
|
355
|
+
"peak_width": 8,
|
|
356
|
+
"examples": 3,
|
|
357
|
+
"timing_bins": None,
|
|
358
|
+
"event_index": None,
|
|
359
|
+
},
|
|
360
|
+
),
|
|
316
361
|
}
|
|
317
362
|
|
|
318
363
|
for plot_name in plots_to_run:
|
|
319
|
-
if plot_name == "peak_timing":
|
|
320
|
-
add(_call_peak_timing(), "peak_timing")
|
|
321
|
-
continue
|
|
322
364
|
entry = dispatch.get(plot_name)
|
|
323
365
|
if entry is None:
|
|
324
366
|
logger.warning("Unknown plot selection '%s'", plot_name)
|
|
@@ -145,10 +145,13 @@ def validate_dict_using_schema(args_dict, logger):
|
|
|
145
145
|
except FileNotFoundError as exc:
|
|
146
146
|
raise FileNotFoundError(f"Error reading schema file from {file_name}") from exc
|
|
147
147
|
data = data if isinstance(data, list) else [data]
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
148
|
+
try:
|
|
149
|
+
for data_dict in data:
|
|
150
|
+
schema.validate_dict_using_schema(
|
|
151
|
+
data_dict, _get_schema_file_name(args_dict, data_dict)
|
|
152
|
+
)
|
|
153
|
+
except Exception as exc:
|
|
154
|
+
raise ValueError(f"Validation of file {file_name} failed") from exc
|
|
152
155
|
logger.info(f"Successful validation of file {file_name}")
|
|
153
156
|
|
|
154
157
|
|
|
@@ -222,6 +222,13 @@ class CommandLineParser(argparse.ArgumentParser):
|
|
|
222
222
|
required=False,
|
|
223
223
|
default=None,
|
|
224
224
|
)
|
|
225
|
+
_job_group.add_argument(
|
|
226
|
+
"--db_simulation_model_version",
|
|
227
|
+
help="version of simulation model database",
|
|
228
|
+
type=str.strip,
|
|
229
|
+
required=False,
|
|
230
|
+
default=None,
|
|
231
|
+
)
|
|
225
232
|
|
|
226
233
|
def initialize_simulation_model_arguments(self, model_options):
|
|
227
234
|
"""
|
|
@@ -740,28 +747,27 @@ class CommandLineParser(argparse.ArgumentParser):
|
|
|
740
747
|
@staticmethod
|
|
741
748
|
def parse_quantity_pair(string):
|
|
742
749
|
"""
|
|
743
|
-
Parse a string representing a pair of astropy quantities
|
|
744
|
-
|
|
745
|
-
Args:
|
|
746
|
-
string: The input string (e.g., "0 deg 1.5 deg").
|
|
750
|
+
Parse a string representing a pair of astropy quantities.
|
|
747
751
|
|
|
748
752
|
Returns
|
|
749
753
|
-------
|
|
750
|
-
|
|
754
|
+
tuple
|
|
755
|
+
A tuple of two astropy.units.Quantity objects.
|
|
751
756
|
|
|
752
757
|
Raises
|
|
753
758
|
------
|
|
754
|
-
|
|
759
|
+
ValueError
|
|
760
|
+
If the string cannot be parsed into exactly two quantities.
|
|
755
761
|
"""
|
|
756
|
-
pattern = r"(\d
|
|
762
|
+
pattern = r"(?>[\d\.eE+-]+)\s*(?>[A-Za-z]+)"
|
|
757
763
|
matches = re.findall(pattern, string)
|
|
758
764
|
if len(matches) != 2:
|
|
759
765
|
raise ValueError("Input string does not contain exactly two quantities.")
|
|
760
766
|
|
|
761
|
-
|
|
762
|
-
u.Quantity(
|
|
763
|
-
|
|
764
|
-
|
|
767
|
+
try:
|
|
768
|
+
return tuple(u.Quantity(m) for m in matches)
|
|
769
|
+
except Exception as exc:
|
|
770
|
+
raise ValueError(f"Could not parse quantities: {exc}") from exc
|
|
765
771
|
|
|
766
772
|
@staticmethod
|
|
767
773
|
def parse_integer_and_quantity(input_string):
|
|
@@ -187,9 +187,14 @@ class DataValidator:
|
|
|
187
187
|
value_as_list, unit_as_list = self._get_value_and_units_as_lists()
|
|
188
188
|
|
|
189
189
|
for index, (value, unit) in enumerate(zip(value_as_list, unit_as_list)):
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
190
|
+
try:
|
|
191
|
+
value_as_list[index], unit_as_list[index] = self._validate_value_and_unit(
|
|
192
|
+
value, unit, index
|
|
193
|
+
)
|
|
194
|
+
except TypeError as ex:
|
|
195
|
+
raise TypeError(
|
|
196
|
+
f"Error validating dictionary using {self.schema_file_name}"
|
|
197
|
+
) from ex
|
|
193
198
|
|
|
194
199
|
if len(value_as_list) == 1:
|
|
195
200
|
self.data_dict["value"], self.data_dict["unit"] = value_as_list[0], unit_as_list[0]
|
simtools/db/db_handler.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Module to handle interaction with DB."""
|
|
2
2
|
|
|
3
|
+
import io
|
|
3
4
|
import logging
|
|
4
5
|
import re
|
|
5
6
|
from collections import defaultdict
|
|
@@ -8,6 +9,7 @@ from threading import Lock
|
|
|
8
9
|
|
|
9
10
|
import gridfs
|
|
10
11
|
import jsonschema
|
|
12
|
+
from astropy.table import Table
|
|
11
13
|
from bson.objectid import ObjectId
|
|
12
14
|
from packaging.version import Version
|
|
13
15
|
from pymongo import MongoClient
|
|
@@ -50,8 +52,19 @@ jsonschema_db_dict = {
|
|
|
50
52
|
"type": "string",
|
|
51
53
|
"description": "Name of simulation model database",
|
|
52
54
|
},
|
|
55
|
+
"db_simulation_model_version": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"description": "Version of simulation model database",
|
|
58
|
+
},
|
|
53
59
|
},
|
|
54
|
-
"required": [
|
|
60
|
+
"required": [
|
|
61
|
+
"db_server",
|
|
62
|
+
"db_api_port",
|
|
63
|
+
"db_api_user",
|
|
64
|
+
"db_api_pw",
|
|
65
|
+
"db_simulation_model",
|
|
66
|
+
"db_simulation_model_version",
|
|
67
|
+
],
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
|
|
@@ -82,7 +95,12 @@ class DatabaseHandler:
|
|
|
82
95
|
self._set_up_connection()
|
|
83
96
|
self._find_latest_simulation_model_db()
|
|
84
97
|
self.db_name = (
|
|
85
|
-
self.
|
|
98
|
+
self.get_db_name(
|
|
99
|
+
model_version=self.mongo_db_config.get("db_simulation_model_version"),
|
|
100
|
+
model_name=self.mongo_db_config.get("db_simulation_model"),
|
|
101
|
+
)
|
|
102
|
+
if self.mongo_db_config
|
|
103
|
+
else None
|
|
86
104
|
)
|
|
87
105
|
|
|
88
106
|
def _set_up_connection(self):
|
|
@@ -92,6 +110,16 @@ class DatabaseHandler:
|
|
|
92
110
|
with lock:
|
|
93
111
|
DatabaseHandler.db_client = self._open_mongo_db()
|
|
94
112
|
|
|
113
|
+
def get_db_name(self, db_name=None, model_version=None, model_name=None):
|
|
114
|
+
"""Build DB name from configuration."""
|
|
115
|
+
if db_name:
|
|
116
|
+
return db_name
|
|
117
|
+
if model_version and model_name:
|
|
118
|
+
return f"{model_name}-{model_version.replace('.', '-')}"
|
|
119
|
+
if model_version or model_name:
|
|
120
|
+
return None
|
|
121
|
+
return None if (model_version or model_name) else self.db_name
|
|
122
|
+
|
|
95
123
|
def _validate_mongo_db_config(self, mongo_db_config):
|
|
96
124
|
"""Validate the MongoDB configuration."""
|
|
97
125
|
if mongo_db_config is None or all(value is None for value in mongo_db_config.values()):
|
|
@@ -140,8 +168,7 @@ class DatabaseHandler:
|
|
|
140
168
|
"""
|
|
141
169
|
Find the latest released version of the simulation model and update the DB config.
|
|
142
170
|
|
|
143
|
-
This is indicated by
|
|
144
|
-
(field "db_simulation_model" in the database configuration dictionary).
|
|
171
|
+
This is indicated by "LATEST" to the simulation model data base version.
|
|
145
172
|
Only released versions are considered, pre-releases are ignored.
|
|
146
173
|
|
|
147
174
|
Raises
|
|
@@ -151,27 +178,27 @@ class DatabaseHandler:
|
|
|
151
178
|
|
|
152
179
|
"""
|
|
153
180
|
try:
|
|
181
|
+
db_simulation_model_version = self.mongo_db_config["db_simulation_model_version"]
|
|
154
182
|
db_simulation_model = self.mongo_db_config["db_simulation_model"]
|
|
155
|
-
if
|
|
183
|
+
if db_simulation_model_version != "LATEST":
|
|
156
184
|
return
|
|
157
|
-
except TypeError: #
|
|
185
|
+
except TypeError: # db_simulation_model_version is None
|
|
158
186
|
return
|
|
159
187
|
|
|
160
|
-
prefix = db_simulation_model.replace("LATEST", "")
|
|
161
188
|
list_of_db_names = self.db_client.list_database_names()
|
|
162
|
-
filtered_list_of_db_names = [
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
)
|
|
189
|
+
filtered_list_of_db_names = [
|
|
190
|
+
s for s in list_of_db_names if s.startswith(db_simulation_model)
|
|
191
|
+
]
|
|
192
|
+
pattern = re.compile(rf"{re.escape(db_simulation_model)}-v(\d+)-(\d+)-(\d+)(?:-(.+))?$")
|
|
167
193
|
|
|
194
|
+
versioned_strings = []
|
|
168
195
|
for s in filtered_list_of_db_names:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
196
|
+
m = pattern.match(s)
|
|
197
|
+
if m:
|
|
198
|
+
# skip pre-releases (have suffix)
|
|
199
|
+
if m.group(4) is None:
|
|
200
|
+
version_str = f"{m.group(1)}.{m.group(2)}.{m.group(3)}"
|
|
201
|
+
versioned_strings.append((s, Version(version_str)))
|
|
175
202
|
|
|
176
203
|
if versioned_strings:
|
|
177
204
|
latest_string, _ = max(versioned_strings, key=lambda x: x[1])
|
|
@@ -180,7 +207,7 @@ class DatabaseHandler:
|
|
|
180
207
|
f"Updated the DB simulation model to the latest version {latest_string}"
|
|
181
208
|
)
|
|
182
209
|
else:
|
|
183
|
-
raise ValueError("
|
|
210
|
+
raise ValueError("LATEST requested but no released versions found in DB.")
|
|
184
211
|
|
|
185
212
|
def generate_compound_indexes(self, db_name=None):
|
|
186
213
|
"""
|
|
@@ -774,17 +801,47 @@ class DatabaseHandler:
|
|
|
774
801
|
with open(Path(path).joinpath(file.filename), "wb") as output_file:
|
|
775
802
|
fs_output.download_to_stream_by_name(file.filename, output_file)
|
|
776
803
|
|
|
777
|
-
def
|
|
804
|
+
def get_ecsv_file_as_astropy_table(self, file_name, db_name=None):
|
|
778
805
|
"""
|
|
779
|
-
|
|
806
|
+
Read contents of an ECSV file from the database and return it as an Astropy Table.
|
|
807
|
+
|
|
808
|
+
Files are not written to disk.
|
|
780
809
|
|
|
781
810
|
Parameters
|
|
782
811
|
----------
|
|
812
|
+
file_name: str
|
|
813
|
+
The name of the ECSV file.
|
|
783
814
|
db_name: str
|
|
784
|
-
|
|
815
|
+
The name of the database.
|
|
816
|
+
|
|
817
|
+
Returns
|
|
818
|
+
-------
|
|
819
|
+
astropy.table.Table
|
|
820
|
+
The contents of the ECSV file as an Astropy Table.
|
|
821
|
+
"""
|
|
822
|
+
db = DatabaseHandler.db_client[db_name or self.db_name]
|
|
823
|
+
fs = gridfs.GridFSBucket(db)
|
|
824
|
+
|
|
825
|
+
buf = io.BytesIO()
|
|
826
|
+
try:
|
|
827
|
+
fs.download_to_stream_by_name(file_name, buf)
|
|
828
|
+
except gridfs.errors.NoFile as exc:
|
|
829
|
+
raise FileNotFoundError(f"ECSV file '{file_name}' not found in DB.") from exc
|
|
830
|
+
buf.seek(0)
|
|
831
|
+
return Table.read(buf.getvalue().decode("utf-8"), format="ascii.ecsv")
|
|
832
|
+
|
|
833
|
+
def add_production_table(self, production_table, db_name=None):
|
|
834
|
+
"""
|
|
835
|
+
Add a production table to the DB.
|
|
836
|
+
|
|
837
|
+
Parameters
|
|
838
|
+
----------
|
|
785
839
|
production_table: dict
|
|
786
840
|
The production table to add to the DB.
|
|
841
|
+
db_name: str
|
|
842
|
+
the name of the DB.
|
|
787
843
|
"""
|
|
844
|
+
db_name = db_name or self.db_name
|
|
788
845
|
collection = self.get_collection("production_tables", db_name=db_name or self.db_name)
|
|
789
846
|
self._logger.debug(f"Adding production for {production_table.get('collection')} to to DB")
|
|
790
847
|
collection.insert_one(production_table)
|
|
@@ -792,8 +849,8 @@ class DatabaseHandler:
|
|
|
792
849
|
|
|
793
850
|
def add_new_parameter(
|
|
794
851
|
self,
|
|
795
|
-
db_name,
|
|
796
852
|
par_dict,
|
|
853
|
+
db_name=None,
|
|
797
854
|
collection_name="telescopes",
|
|
798
855
|
file_prefix=None,
|
|
799
856
|
):
|
|
@@ -805,10 +862,10 @@ class DatabaseHandler:
|
|
|
805
862
|
|
|
806
863
|
Parameters
|
|
807
864
|
----------
|
|
808
|
-
db_name: str
|
|
809
|
-
the name of the DB
|
|
810
865
|
par_dict: dict
|
|
811
866
|
dictionary with parameter data
|
|
867
|
+
db_name: str
|
|
868
|
+
the name of the DB
|
|
812
869
|
collection_name: str
|
|
813
870
|
The name of the collection to add a parameter to.
|
|
814
871
|
file_prefix: str or Path
|
|
@@ -859,7 +916,7 @@ class DatabaseHandler:
|
|
|
859
916
|
the name of the DB
|
|
860
917
|
**kwargs (optional): keyword arguments for file creation.
|
|
861
918
|
The full list of arguments can be found in, \
|
|
862
|
-
https://
|
|
919
|
+
https://www.mongodb.com/docs/manual/core/gridfs/
|
|
863
920
|
mostly these are unnecessary though.
|
|
864
921
|
|
|
865
922
|
Returns
|
simtools/db/db_model_upload.py
CHANGED
|
@@ -9,20 +9,18 @@ from simtools.utils import names
|
|
|
9
9
|
logger = logging.getLogger(__name__)
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def add_values_from_json_to_db(file, collection, db,
|
|
12
|
+
def add_values_from_json_to_db(file, collection, db, file_prefix):
|
|
13
13
|
"""
|
|
14
14
|
Upload new model parameter from json files to db.
|
|
15
15
|
|
|
16
16
|
Parameters
|
|
17
17
|
----------
|
|
18
18
|
file : list
|
|
19
|
-
|
|
19
|
+
JSON file to be uploaded to the DB.
|
|
20
20
|
collection : str
|
|
21
21
|
The DB collection to which to add the file.
|
|
22
22
|
db : DatabaseHandler
|
|
23
23
|
Database handler object.
|
|
24
|
-
db_name : str
|
|
25
|
-
Name of the database to be created.
|
|
26
24
|
file_prefix : str
|
|
27
25
|
Path to location of all additional files to be uploaded.
|
|
28
26
|
"""
|
|
@@ -30,29 +28,28 @@ def add_values_from_json_to_db(file, collection, db, db_name, file_prefix):
|
|
|
30
28
|
logger.debug(
|
|
31
29
|
f"Adding the following parameter to the DB: {par_dict['parameter']} "
|
|
32
30
|
f"version {par_dict['parameter_version']} "
|
|
33
|
-
f"(collection {collection} in database {
|
|
31
|
+
f"(collection {collection} in database {db.get_db_name()})"
|
|
34
32
|
)
|
|
35
33
|
|
|
36
34
|
db.add_new_parameter(
|
|
37
|
-
db_name=db_name,
|
|
38
35
|
par_dict=par_dict,
|
|
39
36
|
collection_name=collection,
|
|
40
37
|
file_prefix=file_prefix,
|
|
41
38
|
)
|
|
42
39
|
|
|
43
40
|
|
|
44
|
-
def add_model_parameters_to_db(
|
|
41
|
+
def add_model_parameters_to_db(input_path, db):
|
|
45
42
|
"""
|
|
46
43
|
Read model parameters from a directory and upload them to the database.
|
|
47
44
|
|
|
48
45
|
Parameters
|
|
49
46
|
----------
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
input_path : Path, str
|
|
48
|
+
Path to the directory containing the model parameters.
|
|
52
49
|
db : DatabaseHandler
|
|
53
50
|
Database handler object.
|
|
54
51
|
"""
|
|
55
|
-
input_path = Path(
|
|
52
|
+
input_path = Path(input_path)
|
|
56
53
|
logger.info(f"Reading model parameters from repository path {input_path}")
|
|
57
54
|
array_elements = [d for d in input_path.iterdir() if d.is_dir()]
|
|
58
55
|
for element in array_elements:
|
|
@@ -67,12 +64,11 @@ def add_model_parameters_to_db(args_dict, db):
|
|
|
67
64
|
file=file,
|
|
68
65
|
collection=collection,
|
|
69
66
|
db=db,
|
|
70
|
-
db_name=args_dict["db_name"],
|
|
71
67
|
file_prefix=input_path / "Files",
|
|
72
68
|
)
|
|
73
69
|
|
|
74
70
|
|
|
75
|
-
def add_production_tables_to_db(
|
|
71
|
+
def add_production_tables_to_db(input_path, db):
|
|
76
72
|
"""
|
|
77
73
|
Read production tables from a directory and upload them to the database.
|
|
78
74
|
|
|
@@ -81,12 +77,12 @@ def add_production_tables_to_db(args_dict, db):
|
|
|
81
77
|
|
|
82
78
|
Parameters
|
|
83
79
|
----------
|
|
84
|
-
|
|
85
|
-
|
|
80
|
+
input_path : Path, str
|
|
81
|
+
Path to the directory containing the production tables.
|
|
86
82
|
db : DatabaseHandler
|
|
87
83
|
Database handler object.
|
|
88
84
|
"""
|
|
89
|
-
input_path = Path(
|
|
85
|
+
input_path = Path(input_path)
|
|
90
86
|
logger.info(f"Reading production tables from repository path {input_path}")
|
|
91
87
|
|
|
92
88
|
for model in filter(Path.is_dir, input_path.iterdir()):
|
|
@@ -101,7 +97,6 @@ def add_production_tables_to_db(args_dict, db):
|
|
|
101
97
|
continue
|
|
102
98
|
logger.info(f"Adding production table for {collection} to the database")
|
|
103
99
|
db.add_production_table(
|
|
104
|
-
db_name=args_dict["db_name"],
|
|
105
100
|
production_table=data,
|
|
106
101
|
)
|
|
107
102
|
|
simtools/dependencies.py
CHANGED
|
@@ -40,7 +40,8 @@ def get_version_string(db_config=None, run_time=None):
|
|
|
40
40
|
|
|
41
41
|
"""
|
|
42
42
|
return (
|
|
43
|
-
f"Database
|
|
43
|
+
f"Database name: {get_database_version_or_name(db_config, version=False)}\n"
|
|
44
|
+
f"Database version: {get_database_version_or_name(db_config, version=True)}\n"
|
|
44
45
|
f"sim_telarray version: {get_sim_telarray_version(run_time)}\n"
|
|
45
46
|
f"CORSIKA version: {get_corsika_version(run_time)}\n"
|
|
46
47
|
f"Build options: {get_build_options(run_time)}\n"
|
|
@@ -48,25 +49,29 @@ def get_version_string(db_config=None, run_time=None):
|
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
|
|
51
|
-
def
|
|
52
|
+
def get_database_version_or_name(db_config, version=True):
|
|
52
53
|
"""
|
|
53
|
-
Get the version of the simulation model data base used.
|
|
54
|
+
Get the version or name of the simulation model data base used.
|
|
54
55
|
|
|
55
56
|
Parameters
|
|
56
57
|
----------
|
|
57
58
|
db_config : dict
|
|
58
59
|
Dictionary containing the database configuration.
|
|
60
|
+
version : bool
|
|
61
|
+
If True, return the version of the database. If False, return the name.
|
|
59
62
|
|
|
60
63
|
Returns
|
|
61
64
|
-------
|
|
62
65
|
str
|
|
63
|
-
Version of the simulation model data base used.
|
|
66
|
+
Version or name of the simulation model data base used.
|
|
64
67
|
|
|
65
68
|
"""
|
|
66
69
|
if db_config is None:
|
|
67
70
|
return None
|
|
68
71
|
db = DatabaseHandler(db_config)
|
|
69
|
-
return db.mongo_db_config.get(
|
|
72
|
+
return db.mongo_db_config.get(
|
|
73
|
+
"db_simulation_model_version" if version else "db_simulation_model"
|
|
74
|
+
)
|
|
70
75
|
|
|
71
76
|
|
|
72
77
|
def get_sim_telarray_version(run_time):
|