gammasimtools 0.23.0__py3-none-any.whl → 0.25.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.23.0.dist-info → gammasimtools-0.25.0.dist-info}/METADATA +1 -1
- {gammasimtools-0.23.0.dist-info → gammasimtools-0.25.0.dist-info}/RECORD +89 -85
- {gammasimtools-0.23.0.dist-info → gammasimtools-0.25.0.dist-info}/entry_points.txt +1 -0
- simtools/_version.py +2 -2
- simtools/application_control.py +54 -4
- simtools/applications/convert_geo_coordinates_of_array_elements.py +1 -1
- simtools/applications/db_add_file_to_db.py +2 -2
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +1 -1
- simtools/applications/db_add_value_from_json_to_db.py +2 -2
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +1 -1
- simtools/applications/db_generate_compound_indexes.py +1 -1
- simtools/applications/db_get_array_layouts_from_db.py +2 -2
- simtools/applications/db_get_file_from_db.py +1 -1
- simtools/applications/db_get_parameter_from_db.py +1 -1
- simtools/applications/db_inspect_databases.py +4 -2
- simtools/applications/db_upload_model_repository.py +1 -1
- simtools/applications/derive_ctao_array_layouts.py +1 -1
- simtools/applications/derive_psf_parameters.py +5 -0
- simtools/applications/derive_pulse_shape_parameters.py +195 -0
- simtools/applications/generate_array_config.py +1 -1
- simtools/applications/maintain_simulation_model_add_production.py +11 -21
- simtools/applications/plot_array_layout.py +63 -1
- simtools/applications/production_generate_grid.py +1 -1
- simtools/applications/simulate_flasher.py +3 -2
- simtools/applications/simulate_pedestals.py +1 -1
- simtools/applications/simulate_prod.py +8 -23
- simtools/applications/simulate_prod_htcondor_generator.py +7 -0
- simtools/applications/submit_array_layouts.py +7 -5
- simtools/applications/validate_camera_fov.py +1 -1
- simtools/applications/validate_cumulative_psf.py +2 -2
- simtools/applications/validate_file_using_schema.py +49 -123
- simtools/applications/validate_optics.py +1 -1
- simtools/configuration/commandline_parser.py +15 -15
- simtools/configuration/configurator.py +1 -1
- simtools/corsika/corsika_config.py +199 -91
- simtools/data_model/model_data_writer.py +15 -3
- simtools/data_model/schema.py +145 -36
- simtools/data_model/validate_data.py +82 -48
- simtools/db/db_handler.py +61 -294
- simtools/db/db_model_upload.py +3 -2
- simtools/db/mongo_db.py +626 -0
- simtools/dependencies.py +38 -17
- simtools/io/eventio_handler.py +128 -0
- simtools/job_execution/htcondor_script_generator.py +0 -2
- simtools/layout/array_layout.py +7 -7
- simtools/layout/array_layout_utils.py +4 -4
- simtools/model/array_model.py +72 -72
- simtools/model/calibration_model.py +12 -9
- simtools/model/model_parameter.py +196 -160
- simtools/model/model_repository.py +176 -39
- simtools/model/model_utils.py +3 -3
- simtools/model/site_model.py +59 -27
- simtools/model/telescope_model.py +21 -13
- simtools/ray_tracing/mirror_panel_psf.py +4 -4
- simtools/ray_tracing/psf_analysis.py +11 -8
- simtools/ray_tracing/psf_parameter_optimisation.py +823 -680
- simtools/reporting/docs_auto_report_generator.py +1 -1
- simtools/reporting/docs_read_parameters.py +72 -11
- simtools/runners/corsika_runner.py +12 -3
- simtools/runners/corsika_simtel_runner.py +6 -0
- simtools/runners/runner_services.py +17 -7
- simtools/runners/simtel_runner.py +12 -54
- simtools/schemas/model_parameters/flasher_pulse_exp_decay.schema.yml +2 -0
- simtools/schemas/model_parameters/flasher_pulse_shape.schema.yml +50 -0
- simtools/schemas/model_parameters/flasher_pulse_width.schema.yml +2 -0
- simtools/schemas/simulation_models_info.schema.yml +4 -1
- simtools/simtel/pulse_shapes.py +268 -0
- simtools/simtel/simtel_config_writer.py +179 -21
- simtools/simtel/simtel_io_event_writer.py +2 -2
- simtools/simtel/simulator_array.py +58 -12
- simtools/simtel/simulator_light_emission.py +45 -8
- simtools/simulator.py +361 -346
- simtools/testing/assertions.py +110 -10
- simtools/testing/configuration.py +1 -1
- simtools/testing/log_inspector.py +4 -1
- simtools/testing/sim_telarray_metadata.py +1 -1
- simtools/testing/validate_output.py +46 -15
- simtools/utils/names.py +2 -4
- simtools/utils/value_conversion.py +10 -5
- simtools/version.py +61 -0
- simtools/visualization/legend_handlers.py +14 -4
- simtools/visualization/plot_array_layout.py +229 -33
- simtools/visualization/plot_mirrors.py +837 -0
- simtools/visualization/plot_pixels.py +1 -1
- simtools/visualization/plot_psf.py +1 -1
- simtools/visualization/plot_tables.py +1 -1
- simtools/simtel/simtel_io_file_info.py +0 -62
- {gammasimtools-0.23.0.dist-info → gammasimtools-0.25.0.dist-info}/WHEEL +0 -0
- {gammasimtools-0.23.0.dist-info → gammasimtools-0.25.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.23.0.dist-info → gammasimtools-0.25.0.dist-info}/top_level.txt +0 -0
simtools/db/db_handler.py
CHANGED
|
@@ -1,70 +1,16 @@
|
|
|
1
1
|
"""Module to handle interaction with DB."""
|
|
2
2
|
|
|
3
|
-
import io
|
|
4
3
|
import logging
|
|
5
|
-
import re
|
|
6
4
|
from collections import defaultdict
|
|
7
5
|
from pathlib import Path
|
|
8
|
-
from threading import Lock
|
|
9
|
-
|
|
10
|
-
import gridfs
|
|
11
|
-
import jsonschema
|
|
12
|
-
from astropy.table import Table
|
|
13
|
-
from bson.objectid import ObjectId
|
|
14
|
-
from pymongo import MongoClient
|
|
15
6
|
|
|
16
7
|
from simtools.data_model import validate_data
|
|
17
|
-
from simtools.
|
|
8
|
+
from simtools.db.mongo_db import MongoDBHandler
|
|
9
|
+
from simtools.io import io_handler
|
|
18
10
|
from simtools.simtel import simtel_table_reader
|
|
19
11
|
from simtools.utils import names, value_conversion
|
|
20
12
|
from simtools.version import resolve_version_to_latest_patch
|
|
21
13
|
|
|
22
|
-
logging.getLogger("pymongo").setLevel(logging.WARNING)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
# pylint: disable=unsubscriptable-object
|
|
26
|
-
# The above comment is because pylint does not know that DatabaseHandler.db_client is subscriptable
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
jsonschema_db_dict = {
|
|
30
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema#",
|
|
31
|
-
"type": "object",
|
|
32
|
-
"description": "MongoDB configuration",
|
|
33
|
-
"properties": {
|
|
34
|
-
"db_server": {"type": "string", "description": "DB server address"},
|
|
35
|
-
"db_api_port": {
|
|
36
|
-
"type": "integer",
|
|
37
|
-
"minimum": 1,
|
|
38
|
-
"maximum": 65535,
|
|
39
|
-
"default": 27017,
|
|
40
|
-
"description": "Port to use",
|
|
41
|
-
},
|
|
42
|
-
"db_api_user": {"type": "string", "description": "API username"},
|
|
43
|
-
"db_api_pw": {"type": "string", "description": "Password for the API user"},
|
|
44
|
-
"db_api_authentication_database": {
|
|
45
|
-
"type": ["string", "null"],
|
|
46
|
-
"default": "admin",
|
|
47
|
-
"description": "DB with user info (optional)",
|
|
48
|
-
},
|
|
49
|
-
"db_simulation_model": {
|
|
50
|
-
"type": "string",
|
|
51
|
-
"description": "Name of simulation model database",
|
|
52
|
-
},
|
|
53
|
-
"db_simulation_model_version": {
|
|
54
|
-
"type": "string",
|
|
55
|
-
"description": "Version of simulation model database",
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
"required": [
|
|
59
|
-
"db_server",
|
|
60
|
-
"db_api_port",
|
|
61
|
-
"db_api_user",
|
|
62
|
-
"db_api_pw",
|
|
63
|
-
"db_simulation_model",
|
|
64
|
-
"db_simulation_model_version",
|
|
65
|
-
],
|
|
66
|
-
}
|
|
67
|
-
|
|
68
14
|
|
|
69
15
|
class DatabaseHandler:
|
|
70
16
|
"""
|
|
@@ -72,67 +18,57 @@ class DatabaseHandler:
|
|
|
72
18
|
|
|
73
19
|
Note the two types of version variables used in this class:
|
|
74
20
|
|
|
75
|
-
- db_simulation_model_version (from
|
|
21
|
+
- db_simulation_model_version (from db_config): version of the simulation model database
|
|
76
22
|
- model_version (from production_tables): version of the model contained in the database
|
|
77
23
|
|
|
78
24
|
Parameters
|
|
79
25
|
----------
|
|
80
|
-
|
|
81
|
-
Dictionary with the
|
|
26
|
+
db_config: dict
|
|
27
|
+
Dictionary with the DB configuration.
|
|
82
28
|
"""
|
|
83
29
|
|
|
84
30
|
ALLOWED_FILE_EXTENSIONS = [".dat", ".txt", ".lis", ".cfg", ".yml", ".yaml", ".ecsv"]
|
|
85
31
|
|
|
86
|
-
db_client = None
|
|
87
32
|
production_table_cached = {}
|
|
88
33
|
model_parameters_cached = {}
|
|
89
34
|
model_versions_cached = {}
|
|
90
35
|
|
|
91
|
-
def __init__(self,
|
|
36
|
+
def __init__(self, db_config=None):
|
|
92
37
|
"""Initialize the DatabaseHandler class."""
|
|
93
38
|
self._logger = logging.getLogger(__name__)
|
|
94
39
|
|
|
95
|
-
self.
|
|
40
|
+
self.db_config = MongoDBHandler.validate_db_config(db_config)
|
|
96
41
|
self.io_handler = io_handler.IOHandler()
|
|
97
|
-
self.
|
|
42
|
+
self.mongo_db_handler = MongoDBHandler(db_config) if self.db_config else None
|
|
98
43
|
|
|
99
|
-
self._set_up_connection()
|
|
100
44
|
self.db_name = (
|
|
101
|
-
|
|
102
|
-
db_simulation_model_version=self.
|
|
103
|
-
model_name=self.
|
|
45
|
+
MongoDBHandler.get_db_name(
|
|
46
|
+
db_simulation_model_version=self.db_config.get("db_simulation_model_version"),
|
|
47
|
+
model_name=self.db_config.get("db_simulation_model"),
|
|
104
48
|
)
|
|
105
|
-
if self.
|
|
49
|
+
if self.db_config
|
|
106
50
|
else None
|
|
107
51
|
)
|
|
108
52
|
|
|
109
|
-
def _set_up_connection(self):
|
|
110
|
-
"""Open the connection to MongoDB."""
|
|
111
|
-
if self.mongo_db_config and DatabaseHandler.db_client is None:
|
|
112
|
-
lock = Lock()
|
|
113
|
-
with lock:
|
|
114
|
-
DatabaseHandler.db_client = self._open_mongo_db()
|
|
115
|
-
|
|
116
53
|
def get_db_name(self, db_name=None, db_simulation_model_version=None, model_name=None):
|
|
117
54
|
"""Build DB name from configuration."""
|
|
118
55
|
if db_name:
|
|
119
56
|
return db_name
|
|
120
57
|
if db_simulation_model_version and model_name:
|
|
121
|
-
return
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
58
|
+
return MongoDBHandler.get_db_name(
|
|
59
|
+
db_simulation_model_version=db_simulation_model_version,
|
|
60
|
+
model_name=model_name,
|
|
61
|
+
)
|
|
62
|
+
if not (db_simulation_model_version or model_name):
|
|
63
|
+
return self.db_name
|
|
64
|
+
return None
|
|
125
65
|
|
|
126
66
|
def print_connection_info(self):
|
|
127
67
|
"""Print the connection information."""
|
|
128
|
-
if self.
|
|
129
|
-
self.
|
|
130
|
-
f"Connected to MongoDB at {self.mongo_db_config['db_server']}:"
|
|
131
|
-
f"{self.mongo_db_config['db_api_port']} "
|
|
132
|
-
f"using database: {self.db_name}"
|
|
133
|
-
)
|
|
68
|
+
if self.mongo_db_handler:
|
|
69
|
+
self.mongo_db_handler.print_connection_info(self.db_name)
|
|
134
70
|
else:
|
|
135
|
-
self._logger.info("No
|
|
71
|
+
self._logger.info("No database defined.")
|
|
136
72
|
|
|
137
73
|
def is_remote_database(self):
|
|
138
74
|
"""
|
|
@@ -145,55 +81,7 @@ class DatabaseHandler:
|
|
|
145
81
|
bool
|
|
146
82
|
True if the database is remote, False otherwise.
|
|
147
83
|
"""
|
|
148
|
-
|
|
149
|
-
db_server = self.mongo_db_config["db_server"]
|
|
150
|
-
domain_pattern = r"^([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$"
|
|
151
|
-
return bool(re.match(domain_pattern, db_server))
|
|
152
|
-
return False
|
|
153
|
-
|
|
154
|
-
def _validate_mongo_db_config(self, mongo_db_config):
|
|
155
|
-
"""Validate the MongoDB configuration."""
|
|
156
|
-
if mongo_db_config is None or all(value is None for value in mongo_db_config.values()):
|
|
157
|
-
return None
|
|
158
|
-
try:
|
|
159
|
-
jsonschema.validate(instance=mongo_db_config, schema=jsonschema_db_dict)
|
|
160
|
-
return mongo_db_config
|
|
161
|
-
except jsonschema.exceptions.ValidationError as err:
|
|
162
|
-
raise ValueError("Invalid MongoDB configuration") from err
|
|
163
|
-
|
|
164
|
-
def _open_mongo_db(self):
|
|
165
|
-
"""
|
|
166
|
-
Open a connection to MongoDB and return the client to read/write to the DB with.
|
|
167
|
-
|
|
168
|
-
Returns
|
|
169
|
-
-------
|
|
170
|
-
A PyMongo DB client
|
|
171
|
-
|
|
172
|
-
Raises
|
|
173
|
-
------
|
|
174
|
-
KeyError
|
|
175
|
-
If the DB configuration is invalid
|
|
176
|
-
"""
|
|
177
|
-
direct_connection = self.mongo_db_config["db_server"] in (
|
|
178
|
-
"localhost",
|
|
179
|
-
"simtools-mongodb",
|
|
180
|
-
"mongodb",
|
|
181
|
-
)
|
|
182
|
-
return MongoClient(
|
|
183
|
-
self.mongo_db_config["db_server"],
|
|
184
|
-
port=self.mongo_db_config["db_api_port"],
|
|
185
|
-
username=self.mongo_db_config["db_api_user"],
|
|
186
|
-
password=self.mongo_db_config["db_api_pw"],
|
|
187
|
-
authSource=(
|
|
188
|
-
self.mongo_db_config.get("db_api_authentication_database")
|
|
189
|
-
if self.mongo_db_config.get("db_api_authentication_database")
|
|
190
|
-
else "admin"
|
|
191
|
-
),
|
|
192
|
-
directConnection=direct_connection,
|
|
193
|
-
ssl=not direct_connection,
|
|
194
|
-
tlsallowinvalidhostnames=True,
|
|
195
|
-
tlsallowinvalidcertificates=True,
|
|
196
|
-
)
|
|
84
|
+
return bool(self.mongo_db_handler and self.mongo_db_handler.is_remote_database())
|
|
197
85
|
|
|
198
86
|
def generate_compound_indexes_for_databases(
|
|
199
87
|
self, db_name, db_simulation_model, db_simulation_model_version
|
|
@@ -209,53 +97,10 @@ class DatabaseHandler:
|
|
|
209
97
|
Name of the simulation model.
|
|
210
98
|
db_simulation_model_version: str
|
|
211
99
|
Version of the simulation model.
|
|
212
|
-
|
|
213
|
-
Raises
|
|
214
|
-
------
|
|
215
|
-
ValueError
|
|
216
|
-
If the requested database is not found.
|
|
217
|
-
|
|
218
100
|
"""
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
]
|
|
222
|
-
requested = self.get_db_name(
|
|
223
|
-
db_name=db_name,
|
|
224
|
-
db_simulation_model_version=db_simulation_model_version,
|
|
225
|
-
model_name=db_simulation_model,
|
|
101
|
+
self.mongo_db_handler.generate_compound_indexes_for_databases(
|
|
102
|
+
db_name, db_simulation_model, db_simulation_model_version
|
|
226
103
|
)
|
|
227
|
-
if requested != "all" and requested not in databases:
|
|
228
|
-
raise ValueError(
|
|
229
|
-
f"Requested database '{requested}' not found. "
|
|
230
|
-
f"Following databases are available: {', '.join(databases)}"
|
|
231
|
-
)
|
|
232
|
-
|
|
233
|
-
databases = databases if requested == "all" else [requested]
|
|
234
|
-
for dbs in databases:
|
|
235
|
-
self._logger.info(f"Generating compound indexes for database: {dbs}")
|
|
236
|
-
self.generate_compound_indexes(db_name=dbs)
|
|
237
|
-
|
|
238
|
-
def generate_compound_indexes(self, db_name=None):
|
|
239
|
-
"""
|
|
240
|
-
Generate compound indexes for the MongoDB collections.
|
|
241
|
-
|
|
242
|
-
Indexes based on the typical query patterns.
|
|
243
|
-
"""
|
|
244
|
-
db_name = db_name or self.db_name
|
|
245
|
-
collection_names = [
|
|
246
|
-
"telescopes",
|
|
247
|
-
"sites",
|
|
248
|
-
"configuration_sim_telarray",
|
|
249
|
-
"configuration_corsika",
|
|
250
|
-
"calibration_devices",
|
|
251
|
-
]
|
|
252
|
-
for collection_name in collection_names:
|
|
253
|
-
db_collection = self.get_collection(collection_name, db_name=db_name)
|
|
254
|
-
db_collection.create_index(
|
|
255
|
-
[("instrument", 1), ("site", 1), ("parameter", 1), ("parameter_version", 1)]
|
|
256
|
-
)
|
|
257
|
-
db_collection = self.get_collection("production_tables", db_name=db_name)
|
|
258
|
-
db_collection.create_index([("collection", 1), ("model_version", 1)])
|
|
259
104
|
|
|
260
105
|
def get_model_parameter(
|
|
261
106
|
self,
|
|
@@ -298,9 +143,7 @@ class DatabaseHandler:
|
|
|
298
143
|
model_version = resolve_version_to_latest_patch(
|
|
299
144
|
model_version, self.get_model_versions(collection_name)
|
|
300
145
|
)
|
|
301
|
-
production_table = self.
|
|
302
|
-
collection_name, model_version
|
|
303
|
-
)
|
|
146
|
+
production_table = self.read_production_table_from_db(collection_name, model_version)
|
|
304
147
|
array_element_list = self._get_array_element_list(
|
|
305
148
|
array_element_name, site, production_table, collection_name
|
|
306
149
|
)
|
|
@@ -320,7 +163,7 @@ class DatabaseHandler:
|
|
|
320
163
|
query["instrument"] = array_element_name
|
|
321
164
|
if site:
|
|
322
165
|
query["site"] = site
|
|
323
|
-
return self.
|
|
166
|
+
return self._read_db(query=query, collection_name=collection_name)
|
|
324
167
|
|
|
325
168
|
def get_model_parameters(self, site, array_element_name, collection, model_version):
|
|
326
169
|
"""
|
|
@@ -347,7 +190,7 @@ class DatabaseHandler:
|
|
|
347
190
|
model_version = resolve_version_to_latest_patch(
|
|
348
191
|
model_version, self.get_model_versions(collection)
|
|
349
192
|
)
|
|
350
|
-
production_table = self.
|
|
193
|
+
production_table = self.read_production_table_from_db(collection, model_version)
|
|
351
194
|
array_element_list = self._get_array_element_list(
|
|
352
195
|
array_element_name, site, production_table, collection
|
|
353
196
|
)
|
|
@@ -414,7 +257,7 @@ class DatabaseHandler:
|
|
|
414
257
|
parameter_version_table = production_table["parameters"][array_element]
|
|
415
258
|
except KeyError: # allow missing array elements (parameter dict is checked later)
|
|
416
259
|
return {}
|
|
417
|
-
DatabaseHandler.model_parameters_cached[cache_key] = self.
|
|
260
|
+
DatabaseHandler.model_parameters_cached[cache_key] = self._read_db(
|
|
418
261
|
query=self._get_query_from_parameter_version_table(
|
|
419
262
|
parameter_version_table, array_element, site
|
|
420
263
|
),
|
|
@@ -439,7 +282,7 @@ class DatabaseHandler:
|
|
|
439
282
|
The collection from the DB.
|
|
440
283
|
"""
|
|
441
284
|
db_name = db_name or self.db_name
|
|
442
|
-
return
|
|
285
|
+
return self.mongo_db_handler.get_collection(collection_name, db_name)
|
|
443
286
|
|
|
444
287
|
def get_collections(self, db_name=None, model_collections_only=False):
|
|
445
288
|
"""
|
|
@@ -456,17 +299,10 @@ class DatabaseHandler:
|
|
|
456
299
|
-------
|
|
457
300
|
list
|
|
458
301
|
List of collection names
|
|
459
|
-
|
|
460
302
|
"""
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
db_name
|
|
465
|
-
].list_collection_names()
|
|
466
|
-
collections = self.list_of_collections[db_name]
|
|
467
|
-
if model_collections_only:
|
|
468
|
-
return [collection for collection in collections if not collection.startswith("fs.")]
|
|
469
|
-
return collections
|
|
303
|
+
return self.mongo_db_handler.get_collections(
|
|
304
|
+
db_name or self.db_name, model_collections_only
|
|
305
|
+
)
|
|
470
306
|
|
|
471
307
|
def export_model_file(
|
|
472
308
|
self,
|
|
@@ -555,8 +391,8 @@ class DatabaseHandler:
|
|
|
555
391
|
if Path(dest).joinpath(file_name).exists():
|
|
556
392
|
instance_ids[file_name] = "file exists"
|
|
557
393
|
else:
|
|
558
|
-
file_path_instance = self.
|
|
559
|
-
self.
|
|
394
|
+
file_path_instance = self.mongo_db_handler.get_file_from_db(db_name, file_name)
|
|
395
|
+
self._write_file_from_db_to_disk(db_name, dest, file_path_instance)
|
|
560
396
|
instance_ids[file_name] = file_path_instance._id # pylint: disable=protected-access
|
|
561
397
|
return instance_ids
|
|
562
398
|
|
|
@@ -577,7 +413,7 @@ class DatabaseHandler:
|
|
|
577
413
|
query_dict["site"] = site
|
|
578
414
|
return query_dict
|
|
579
415
|
|
|
580
|
-
def
|
|
416
|
+
def _read_db(self, query, collection_name):
|
|
581
417
|
"""
|
|
582
418
|
Query MongoDB.
|
|
583
419
|
|
|
@@ -597,20 +433,17 @@ class DatabaseHandler:
|
|
|
597
433
|
ValueError
|
|
598
434
|
if query returned no results.
|
|
599
435
|
"""
|
|
600
|
-
|
|
601
|
-
posts = list(collection.find(query))
|
|
602
|
-
if not posts:
|
|
603
|
-
raise ValueError(
|
|
604
|
-
f"The following query for {collection_name} returned zero results: {query} "
|
|
605
|
-
)
|
|
436
|
+
posts = self.mongo_db_handler.query_db(query, collection_name, self.db_name)
|
|
606
437
|
parameters = {}
|
|
607
438
|
for post in posts:
|
|
608
439
|
par_now = post["parameter"]
|
|
609
440
|
parameters[par_now] = post
|
|
610
|
-
parameters[par_now]["entry_date"] =
|
|
441
|
+
parameters[par_now]["entry_date"] = self.mongo_db_handler.get_entry_date_from_document(
|
|
442
|
+
post
|
|
443
|
+
)
|
|
611
444
|
return {k: parameters[k] for k in sorted(parameters)}
|
|
612
445
|
|
|
613
|
-
def
|
|
446
|
+
def read_production_table_from_db(self, collection_name, model_version):
|
|
614
447
|
"""
|
|
615
448
|
Read production table for the given collection from MongoDB.
|
|
616
449
|
|
|
@@ -637,8 +470,7 @@ class DatabaseHandler:
|
|
|
637
470
|
pass
|
|
638
471
|
|
|
639
472
|
query = {"model_version": model_version, "collection": collection_name}
|
|
640
|
-
|
|
641
|
-
post = collection.find_one(query)
|
|
473
|
+
post = self.mongo_db_handler.find_one(query, "production_tables", self.db_name)
|
|
642
474
|
if not post:
|
|
643
475
|
raise ValueError(f"The following query returned zero results: {query}")
|
|
644
476
|
|
|
@@ -647,7 +479,7 @@ class DatabaseHandler:
|
|
|
647
479
|
"model_version": post["model_version"],
|
|
648
480
|
"parameters": post["parameters"],
|
|
649
481
|
"design_model": post.get("design_model", {}),
|
|
650
|
-
"entry_date":
|
|
482
|
+
"entry_date": self.mongo_db_handler.get_entry_date_from_document(post),
|
|
651
483
|
}
|
|
652
484
|
|
|
653
485
|
def get_model_versions(self, collection_name="telescopes"):
|
|
@@ -691,7 +523,7 @@ class DatabaseHandler:
|
|
|
691
523
|
model_version = resolve_version_to_latest_patch(
|
|
692
524
|
model_version, self.get_model_versions(collection)
|
|
693
525
|
)
|
|
694
|
-
production_table = self.
|
|
526
|
+
production_table = self.read_production_table_from_db(collection, model_version)
|
|
695
527
|
return sorted([entry for entry in production_table["parameters"] if "-design" not in entry])
|
|
696
528
|
|
|
697
529
|
def get_design_model(self, model_version, array_element_name, collection="telescopes"):
|
|
@@ -716,7 +548,7 @@ class DatabaseHandler:
|
|
|
716
548
|
model_version = resolve_version_to_latest_patch(
|
|
717
549
|
model_version, self.get_model_versions(collection)
|
|
718
550
|
)
|
|
719
|
-
production_table = self.
|
|
551
|
+
production_table = self.read_production_table_from_db(collection, model_version)
|
|
720
552
|
try:
|
|
721
553
|
return production_table["design_model"][array_element_name]
|
|
722
554
|
except KeyError:
|
|
@@ -747,7 +579,7 @@ class DatabaseHandler:
|
|
|
747
579
|
model_version = resolve_version_to_latest_patch(
|
|
748
580
|
model_version, self.get_model_versions(collection)
|
|
749
581
|
)
|
|
750
|
-
production_table = self.
|
|
582
|
+
production_table = self.read_production_table_from_db(collection, model_version)
|
|
751
583
|
all_array_elements = production_table["parameters"]
|
|
752
584
|
return sorted(
|
|
753
585
|
[
|
|
@@ -803,38 +635,7 @@ class DatabaseHandler:
|
|
|
803
635
|
)
|
|
804
636
|
raise ValueError(f"Unknown simulation software: {simulation_software}")
|
|
805
637
|
|
|
806
|
-
|
|
807
|
-
def _get_file_mongo_db(db_name, file_name):
|
|
808
|
-
"""
|
|
809
|
-
Extract a file from MongoDB and return GridFS file instance.
|
|
810
|
-
|
|
811
|
-
Parameters
|
|
812
|
-
----------
|
|
813
|
-
db_name: str
|
|
814
|
-
the name of the DB with files of tabulated data
|
|
815
|
-
file_name: str
|
|
816
|
-
The name of the file requested
|
|
817
|
-
|
|
818
|
-
Returns
|
|
819
|
-
-------
|
|
820
|
-
GridOut
|
|
821
|
-
A file instance returned by GridFS find_one
|
|
822
|
-
|
|
823
|
-
Raises
|
|
824
|
-
------
|
|
825
|
-
FileNotFoundError
|
|
826
|
-
If the desired file is not found.
|
|
827
|
-
|
|
828
|
-
"""
|
|
829
|
-
db = DatabaseHandler.db_client[db_name]
|
|
830
|
-
file_system = gridfs.GridFS(db)
|
|
831
|
-
if file_system.exists({"filename": file_name}):
|
|
832
|
-
return file_system.find_one({"filename": file_name})
|
|
833
|
-
|
|
834
|
-
raise FileNotFoundError(f"The file {file_name} does not exist in the database {db_name}")
|
|
835
|
-
|
|
836
|
-
@staticmethod
|
|
837
|
-
def _write_file_from_mongo_to_disk(db_name, path, file):
|
|
638
|
+
def _write_file_from_db_to_disk(self, db_name, path, file):
|
|
838
639
|
"""
|
|
839
640
|
Extract a file from MongoDB and write it to disk.
|
|
840
641
|
|
|
@@ -847,10 +648,7 @@ class DatabaseHandler:
|
|
|
847
648
|
file: GridOut
|
|
848
649
|
A file instance returned by GridFS find_one
|
|
849
650
|
"""
|
|
850
|
-
|
|
851
|
-
fs_output = gridfs.GridFSBucket(db)
|
|
852
|
-
with open(Path(path).joinpath(file.filename), "wb") as output_file:
|
|
853
|
-
fs_output.download_to_stream_by_name(file.filename, output_file)
|
|
651
|
+
self.mongo_db_handler.write_file_from_db_to_disk(db_name, path, file)
|
|
854
652
|
|
|
855
653
|
def get_ecsv_file_as_astropy_table(self, file_name, db_name=None):
|
|
856
654
|
"""
|
|
@@ -870,16 +668,9 @@ class DatabaseHandler:
|
|
|
870
668
|
astropy.table.Table
|
|
871
669
|
The contents of the ECSV file as an Astropy Table.
|
|
872
670
|
"""
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
buf = io.BytesIO()
|
|
877
|
-
try:
|
|
878
|
-
fs.download_to_stream_by_name(file_name, buf)
|
|
879
|
-
except gridfs.errors.NoFile as exc:
|
|
880
|
-
raise FileNotFoundError(f"ECSV file '{file_name}' not found in DB.") from exc
|
|
881
|
-
buf.seek(0)
|
|
882
|
-
return Table.read(buf.getvalue().decode("utf-8"), format="ascii.ecsv")
|
|
671
|
+
return self.mongo_db_handler.get_ecsv_file_as_astropy_table(
|
|
672
|
+
file_name, db_name or self.db_name
|
|
673
|
+
)
|
|
883
674
|
|
|
884
675
|
def add_production_table(self, production_table, db_name=None):
|
|
885
676
|
"""
|
|
@@ -892,10 +683,10 @@ class DatabaseHandler:
|
|
|
892
683
|
db_name: str
|
|
893
684
|
the name of the DB.
|
|
894
685
|
"""
|
|
895
|
-
db_name = db_name or self.db_name
|
|
896
|
-
collection = self.get_collection("production_tables", db_name=db_name or self.db_name)
|
|
897
686
|
self._logger.debug(f"Adding production for {production_table.get('collection')} to the DB")
|
|
898
|
-
|
|
687
|
+
self.mongo_db_handler.insert_one(
|
|
688
|
+
production_table, "production_tables", db_name or self.db_name
|
|
689
|
+
)
|
|
899
690
|
DatabaseHandler.production_table_cached.clear()
|
|
900
691
|
DatabaseHandler.model_versions_cached.clear()
|
|
901
692
|
|
|
@@ -926,7 +717,6 @@ class DatabaseHandler:
|
|
|
926
717
|
par_dict = validate_data.DataValidator.validate_model_parameter(par_dict)
|
|
927
718
|
|
|
928
719
|
db_name = db_name or self.db_name
|
|
929
|
-
collection = self.get_collection(collection_name, db_name=db_name)
|
|
930
720
|
|
|
931
721
|
par_dict["value"], _base_unit, _ = value_conversion.get_value_unit_type(
|
|
932
722
|
value=par_dict["value"], unit_str=par_dict.get("unit", None)
|
|
@@ -941,14 +731,12 @@ class DatabaseHandler:
|
|
|
941
731
|
f"corresponding to the {par_dict['parameter']} parameter, must be provided."
|
|
942
732
|
)
|
|
943
733
|
file_path = Path(file_prefix).joinpath(par_dict["value"])
|
|
944
|
-
if not ascii_handler.is_utf8_file(file_path):
|
|
945
|
-
raise ValueError(f"File is not UTF-8 encoded: {file_path}")
|
|
946
734
|
files_to_add_to_db.add(f"{file_path}")
|
|
947
735
|
|
|
948
736
|
self._logger.debug(
|
|
949
737
|
f"Adding a new entry to DB {db_name} and collection {collection_name}:\n{par_dict}"
|
|
950
738
|
)
|
|
951
|
-
|
|
739
|
+
self.mongo_db_handler.insert_one(par_dict, collection_name, db_name)
|
|
952
740
|
|
|
953
741
|
for file_to_insert_now in files_to_add_to_db:
|
|
954
742
|
self._logger.debug(f"Will also add the file {file_to_insert_now} to the DB")
|
|
@@ -956,7 +744,7 @@ class DatabaseHandler:
|
|
|
956
744
|
|
|
957
745
|
self._reset_parameter_cache()
|
|
958
746
|
|
|
959
|
-
def insert_file_to_db(self, file_name, db_name=None
|
|
747
|
+
def insert_file_to_db(self, file_name, db_name=None):
|
|
960
748
|
"""
|
|
961
749
|
Insert a file to the DB.
|
|
962
750
|
|
|
@@ -966,35 +754,14 @@ class DatabaseHandler:
|
|
|
966
754
|
The name of the file to insert (full path).
|
|
967
755
|
db_name: str
|
|
968
756
|
the name of the DB
|
|
969
|
-
**kwargs (optional): keyword arguments for file creation.
|
|
970
|
-
The full list of arguments can be found in, \
|
|
971
|
-
https://www.mongodb.com/docs/manual/core/gridfs/
|
|
972
|
-
mostly these are unnecessary though.
|
|
973
757
|
|
|
974
758
|
Returns
|
|
975
759
|
-------
|
|
976
|
-
|
|
977
|
-
If the file exists, return its GridOut._id, otherwise insert the file and return
|
|
978
|
-
|
|
979
|
-
|
|
760
|
+
file_id: GridOut._id
|
|
761
|
+
If the file exists, return its GridOut._id, otherwise insert the file and return
|
|
762
|
+
its newly created DB GridOut._id.
|
|
980
763
|
"""
|
|
981
|
-
|
|
982
|
-
db = DatabaseHandler.db_client[db_name]
|
|
983
|
-
file_system = gridfs.GridFS(db)
|
|
984
|
-
|
|
985
|
-
kwargs.setdefault("content_type", "ascii/dat")
|
|
986
|
-
kwargs.setdefault("filename", Path(file_name).name)
|
|
987
|
-
|
|
988
|
-
if file_system.exists({"filename": kwargs["filename"]}):
|
|
989
|
-
self._logger.warning(
|
|
990
|
-
f"The file {kwargs['filename']} exists in the DB. Returning its ID"
|
|
991
|
-
)
|
|
992
|
-
return file_system.find_one( # pylint: disable=protected-access
|
|
993
|
-
{"filename": kwargs["filename"]}
|
|
994
|
-
)._id
|
|
995
|
-
self._logger.debug(f"Writing file to DB: {file_name}")
|
|
996
|
-
with open(file_name, "rb") as data_file:
|
|
997
|
-
return file_system.put(data_file, **kwargs)
|
|
764
|
+
return self.mongo_db_handler.insert_file_to_db(file_name, db_name or self.db_name)
|
|
998
765
|
|
|
999
766
|
def _cache_key(self, site=None, array_element_name=None, model_version=None, collection=None):
|
|
1000
767
|
"""
|
|
@@ -1085,7 +852,7 @@ class DatabaseHandler:
|
|
|
1085
852
|
return [array_element_name]
|
|
1086
853
|
if collection == "configuration_sim_telarray":
|
|
1087
854
|
# get design model from 'telescope' or 'calibration_device' production tables
|
|
1088
|
-
production_table = self.
|
|
855
|
+
production_table = self.read_production_table_from_db(
|
|
1089
856
|
names.get_collection_name_from_array_element_name(array_element_name),
|
|
1090
857
|
production_table["model_version"],
|
|
1091
858
|
)
|
simtools/db/db_model_upload.py
CHANGED
|
@@ -186,7 +186,8 @@ def _read_production_tables(model_path):
|
|
|
186
186
|
models = [model_path.name]
|
|
187
187
|
if (model_path / "info.yml").exists():
|
|
188
188
|
info = ascii_handler.collect_data_from_file(file_name=model_path / "info.yml")
|
|
189
|
-
|
|
189
|
+
if info.get("model_update") == "patch_update":
|
|
190
|
+
models.extend(info.get("model_version_history", []))
|
|
190
191
|
# sort oldest --> newest
|
|
191
192
|
models = sorted(set(models), key=Version, reverse=False)
|
|
192
193
|
for model in models:
|
|
@@ -288,7 +289,7 @@ def _confirm_remote_database_upload(db):
|
|
|
288
289
|
if not db.is_remote_database():
|
|
289
290
|
return True
|
|
290
291
|
|
|
291
|
-
db_config = db.
|
|
292
|
+
db_config = db.db_config
|
|
292
293
|
db_server = db_config.get("db_server", "unknown server") if db_config else "unknown server"
|
|
293
294
|
|
|
294
295
|
try:
|