gammasimtools 0.11.0__py3-none-any.whl → 0.13.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.11.0.dist-info → gammasimtools-0.13.0.dist-info}/METADATA +1 -1
- {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/RECORD +66 -79
- {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/entry_points.txt +2 -1
- simtools/_version.py +2 -2
- simtools/applications/convert_all_model_parameters_from_simtel.py +77 -88
- simtools/applications/convert_geo_coordinates_of_array_elements.py +1 -1
- simtools/applications/db_get_parameter_from_db.py +52 -22
- simtools/applications/derive_photon_electron_spectrum.py +1 -1
- simtools/applications/docs_produce_array_element_report.py +1 -10
- simtools/applications/docs_produce_model_parameter_reports.py +4 -17
- simtools/applications/plot_tabular_data.py +14 -2
- simtools/applications/{production_derive_limits.py → production_derive_corsika_limits.py} +20 -8
- simtools/applications/production_extract_mc_event_data.py +125 -0
- simtools/applications/run_application.py +9 -10
- simtools/applications/submit_data_from_external.py +1 -1
- simtools/applications/submit_model_parameter_from_external.py +2 -1
- simtools/camera/single_photon_electron_spectrum.py +6 -2
- simtools/configuration/commandline_parser.py +1 -1
- simtools/constants.py +7 -0
- simtools/data_model/metadata_collector.py +159 -61
- simtools/data_model/model_data_writer.py +11 -55
- simtools/data_model/schema.py +2 -1
- simtools/data_model/validate_data.py +5 -3
- simtools/db/db_handler.py +119 -33
- simtools/model/model_parameter.py +0 -31
- simtools/production_configuration/derive_corsika_limits.py +260 -0
- simtools/production_configuration/extract_mc_event_data.py +253 -0
- simtools/ray_tracing/mirror_panel_psf.py +1 -1
- simtools/reporting/docs_read_parameters.py +164 -91
- simtools/schemas/metadata.metaschema.yml +7 -6
- simtools/schemas/model_parameter.metaschema.yml +0 -4
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +13 -5
- simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
- simtools/schemas/model_parameters/array_layouts.schema.yml +3 -0
- simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
- simtools/schemas/model_parameters/atmospheric_profile.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
- simtools/schemas/model_parameters/camera_filter.schema.yml +1 -1
- simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +3 -3
- simtools/schemas/model_parameters/fadc_max_sum.schema.yml +3 -3
- simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
- simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
- simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +1 -1
- simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
- simtools/schemas/model_parameters/nsb_skymap.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +1 -1
- simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
- simtools/schemas/plot_configuration.metaschema.yml +162 -0
- simtools/schemas/production_tables.schema.yml +1 -1
- simtools/simtel/simtel_config_reader.py +85 -34
- simtools/simtel/simtel_table_reader.py +4 -0
- simtools/utils/general.py +50 -9
- simtools/utils/names.py +7 -2
- simtools/utils/value_conversion.py +6 -4
- simtools/visualization/plot_tables.py +25 -20
- simtools/visualization/visualize.py +71 -23
- simtools/_dev_version/__init__.py +0 -9
- simtools/applications/__init__.py +0 -0
- simtools/configuration/__init__.py +0 -0
- simtools/corsika/__init__.py +0 -0
- simtools/data_model/__init__.py +0 -0
- simtools/db/__init__.py +0 -0
- simtools/io_operations/__init__.py +0 -0
- simtools/job_execution/__init__.py +0 -0
- simtools/layout/__init__.py +0 -0
- simtools/model/__init__.py +0 -0
- simtools/production_configuration/limits_calculation.py +0 -202
- simtools/ray_tracing/__init__.py +0 -0
- simtools/runners/__init__.py +0 -0
- simtools/simtel/__init__.py +0 -0
- simtools/testing/__init__.py +0 -0
- simtools/utils/__init__.py +0 -0
- simtools/visualization/__init__.py +0 -0
- {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/LICENSE +0 -0
- {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
---
|
|
2
|
+
$schema: http://json-schema.org/draft-06/schema#
|
|
3
|
+
$ref: '#/definitions/SimtoolsPlotConfiguration'
|
|
4
|
+
title: SimPipe plot configuration metaschema
|
|
5
|
+
description: YAML representation of plot configuration metaschema
|
|
6
|
+
version: 0.1.0
|
|
7
|
+
name: plot_configuration.metaschema
|
|
8
|
+
type: object
|
|
9
|
+
additionalProperties: false
|
|
10
|
+
|
|
11
|
+
definitions:
|
|
12
|
+
SimtoolsPlotConfiguration:
|
|
13
|
+
type: object
|
|
14
|
+
additionalProperties: false
|
|
15
|
+
properties:
|
|
16
|
+
CTA_SIMPIPE:
|
|
17
|
+
"$ref": "#/definitions/CTASIMPIPE"
|
|
18
|
+
SCHEMA_VERSION:
|
|
19
|
+
type: string
|
|
20
|
+
description: "Version of the schema."
|
|
21
|
+
SCHEMA_URL:
|
|
22
|
+
type: string
|
|
23
|
+
format: uri
|
|
24
|
+
description: "URL of the schema."
|
|
25
|
+
SCHEMA_NAME:
|
|
26
|
+
type: string
|
|
27
|
+
description: "Name of the schema."
|
|
28
|
+
required:
|
|
29
|
+
- CTA_SIMPIPE
|
|
30
|
+
title: "SimtoolsPlotConfiguration"
|
|
31
|
+
CTASIMPIPE:
|
|
32
|
+
type: object
|
|
33
|
+
additionalProperties: false
|
|
34
|
+
properties:
|
|
35
|
+
PLOT:
|
|
36
|
+
"$ref": "#/definitions/Plot"
|
|
37
|
+
required:
|
|
38
|
+
- PLOT
|
|
39
|
+
title: "CTASimpipe"
|
|
40
|
+
Plot:
|
|
41
|
+
description: "Plot configuration of simtools data visualization."
|
|
42
|
+
type: object
|
|
43
|
+
additionalProperties: false
|
|
44
|
+
properties:
|
|
45
|
+
TYPE:
|
|
46
|
+
type: string
|
|
47
|
+
description: "Type of the plot (e.g., mirror reflectivity, quantum_efficiency)."
|
|
48
|
+
TITLE:
|
|
49
|
+
type: string
|
|
50
|
+
description: "Title of the plot."
|
|
51
|
+
XTITLE:
|
|
52
|
+
type: string
|
|
53
|
+
description: "Title of x-axis."
|
|
54
|
+
YTITLE:
|
|
55
|
+
type: string
|
|
56
|
+
description: "Title of y-axis."
|
|
57
|
+
XSCALE:
|
|
58
|
+
type: string
|
|
59
|
+
enum: ["linear", "log"]
|
|
60
|
+
description: "Scale of x-axis (linear or log)."
|
|
61
|
+
YSCALE:
|
|
62
|
+
type: string
|
|
63
|
+
enum: ["linear", "log"]
|
|
64
|
+
description: "Scale of y-axis (linear or log)."
|
|
65
|
+
XLIM:
|
|
66
|
+
type: array
|
|
67
|
+
items:
|
|
68
|
+
type: [number, "null"]
|
|
69
|
+
description: "Limits for x-axis [min, max]. Use null for auto-limit."
|
|
70
|
+
minItems: 2
|
|
71
|
+
maxItems: 2
|
|
72
|
+
YLIM:
|
|
73
|
+
type: array
|
|
74
|
+
items:
|
|
75
|
+
type: [number, "null"]
|
|
76
|
+
description: "Limits for y-axis [min, max]. Use null for auto-limit."
|
|
77
|
+
minItems: 2
|
|
78
|
+
maxItems: 2
|
|
79
|
+
ERROR_TYPE:
|
|
80
|
+
type: string
|
|
81
|
+
enum: ["fill_between", "errorbar", "none"]
|
|
82
|
+
description: "Type of errors."
|
|
83
|
+
NO_MARKERS:
|
|
84
|
+
type: boolean
|
|
85
|
+
description: "Whether to display markers on data points."
|
|
86
|
+
PLOT_RATIO:
|
|
87
|
+
type: boolean
|
|
88
|
+
description: "Whether to display ratio plot."
|
|
89
|
+
TABLES:
|
|
90
|
+
type: array
|
|
91
|
+
description: "List of tables to plot."
|
|
92
|
+
items:
|
|
93
|
+
"$ref": "#/definitions/TableConfig"
|
|
94
|
+
required:
|
|
95
|
+
- TYPE
|
|
96
|
+
- TITLE
|
|
97
|
+
- XTITLE
|
|
98
|
+
- YTITLE
|
|
99
|
+
- TABLES
|
|
100
|
+
title: "Plot"
|
|
101
|
+
TableConfig:
|
|
102
|
+
type: object
|
|
103
|
+
description: "Configuration for a data table to plot."
|
|
104
|
+
additionalProperties: false
|
|
105
|
+
properties:
|
|
106
|
+
PARAMETER:
|
|
107
|
+
type: string
|
|
108
|
+
description: "Parameter name to retrieve data for."
|
|
109
|
+
FILE_NAME:
|
|
110
|
+
type: string
|
|
111
|
+
description: "Path to the data file."
|
|
112
|
+
TYPE:
|
|
113
|
+
type: string
|
|
114
|
+
description: "Type of data file."
|
|
115
|
+
TELESCOPE:
|
|
116
|
+
type: string
|
|
117
|
+
description: "Telescope descriptor to retrieve data for."
|
|
118
|
+
SITE:
|
|
119
|
+
type: string
|
|
120
|
+
description: "Site name (North/South)."
|
|
121
|
+
MODEL_VERSION:
|
|
122
|
+
type: string
|
|
123
|
+
description: "Model version to use."
|
|
124
|
+
PARAMETER_VERSION:
|
|
125
|
+
type: string
|
|
126
|
+
description: "Parameter version to use."
|
|
127
|
+
LABEL:
|
|
128
|
+
type: string
|
|
129
|
+
description: "Label for the plot legend."
|
|
130
|
+
COLUMN_X:
|
|
131
|
+
type: string
|
|
132
|
+
description: "Column name to use for x-axis."
|
|
133
|
+
COLUMN_Y:
|
|
134
|
+
type: string
|
|
135
|
+
description: "Column name to use for y-axis."
|
|
136
|
+
COLUMN_X_ERR:
|
|
137
|
+
type: string
|
|
138
|
+
description: "Column name to use for x-axis error."
|
|
139
|
+
COLUMN_Y_ERR:
|
|
140
|
+
type: string
|
|
141
|
+
description: "Column name to use for y-axis error."
|
|
142
|
+
NORMALIZE_Y:
|
|
143
|
+
type: boolean
|
|
144
|
+
description: "Whether to normalize y values."
|
|
145
|
+
SELECT_VALUES:
|
|
146
|
+
type: object
|
|
147
|
+
description: "Selection criteria for data filtering."
|
|
148
|
+
properties:
|
|
149
|
+
COLUMN_NAME:
|
|
150
|
+
type: string
|
|
151
|
+
description: "Column name to use for filtering."
|
|
152
|
+
VALUE:
|
|
153
|
+
type: [number, string]
|
|
154
|
+
description: "Value to filter by."
|
|
155
|
+
required:
|
|
156
|
+
- COLUMN_NAME
|
|
157
|
+
- VALUE
|
|
158
|
+
required:
|
|
159
|
+
- COLUMN_X
|
|
160
|
+
- COLUMN_Y
|
|
161
|
+
- LABEL
|
|
162
|
+
title: "TableConfig"
|
|
@@ -29,7 +29,7 @@ definitions:
|
|
|
29
29
|
pattern: '^\d+\.\d+\.\d+$'
|
|
30
30
|
propertyNames:
|
|
31
31
|
description: Allowed parameter name patterns.
|
|
32
|
-
pattern: '^([A-Za-z](ST|LL)[N,S,x]-\d{2,3}|[A-Za-z](ST|LL)[N,S,x]-(design|FlashCam|NectarCam)|OBS-(North|South)|Dummy-Telescope)$'
|
|
32
|
+
pattern: '^([A-Za-z](ST|LL|CT)[N,S,x]-\d{2,3}|[A-Za-z](ST|LL|CT)[N,S,x]-(design|FlashCam|NectarCam)|OBS-(North|South)|Dummy-Telescope)$'
|
|
33
33
|
design_model:
|
|
34
34
|
type: object
|
|
35
35
|
description: Design models.
|
|
@@ -4,13 +4,38 @@
|
|
|
4
4
|
import logging
|
|
5
5
|
import re
|
|
6
6
|
|
|
7
|
+
import astropy.units as u
|
|
7
8
|
import numpy as np
|
|
8
9
|
|
|
9
10
|
import simtools.utils.general as gen
|
|
11
|
+
from simtools.utils import names
|
|
10
12
|
|
|
11
13
|
__all__ = ["SimtelConfigReader"]
|
|
12
14
|
|
|
13
15
|
|
|
16
|
+
def get_list_of_simtel_parameters(simtel_config_file):
|
|
17
|
+
"""
|
|
18
|
+
Return list of simtel parameters found in simtel configuration file.
|
|
19
|
+
|
|
20
|
+
Parameters
|
|
21
|
+
----------
|
|
22
|
+
simtel_config_file: str
|
|
23
|
+
File name for sim_telarray configuration
|
|
24
|
+
|
|
25
|
+
Returns
|
|
26
|
+
-------
|
|
27
|
+
list
|
|
28
|
+
List of parameters found in simtel configuration file.
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
simtel_parameter_set = set()
|
|
32
|
+
with open(simtel_config_file, encoding="utf-8") as file:
|
|
33
|
+
for line in file:
|
|
34
|
+
parts_of_lines = re.split(r",\s*|\s+", line.strip())
|
|
35
|
+
simtel_parameter_set.add(parts_of_lines[1].lower())
|
|
36
|
+
return sorted(simtel_parameter_set)
|
|
37
|
+
|
|
38
|
+
|
|
14
39
|
class SimtelConfigReader:
|
|
15
40
|
"""
|
|
16
41
|
Reads model parameters from configuration files and converts to the simtools representation.
|
|
@@ -26,7 +51,7 @@ class SimtelConfigReader:
|
|
|
26
51
|
-C limits=no-internal -C initlist=no-internal -C list=no-internal\
|
|
27
52
|
-C typelist=no-internal -C maximum_telescopes=30\
|
|
28
53
|
-DNSB_AUTOSCALE -DNECTARCAM -DHYPER_LAYOUT\
|
|
29
|
-
-DNUM_TELESCOPES=30 /dev/null 2>|/dev/null | grep '(@cfg)'
|
|
54
|
+
-DNUM_TELESCOPES=30 /dev/null 2>|/dev/null | grep '(@cfg)' | sed 's/^(@cfg)
|
|
30
55
|
|
|
31
56
|
Parameters
|
|
32
57
|
----------
|
|
@@ -61,7 +86,12 @@ class SimtelConfigReader:
|
|
|
61
86
|
else None
|
|
62
87
|
)
|
|
63
88
|
self.parameter_name = self.schema_dict.get("name") if self.schema_dict else parameter_name
|
|
64
|
-
|
|
89
|
+
try:
|
|
90
|
+
self.simtel_parameter_name = names.get_simulation_software_name_from_parameter_name(
|
|
91
|
+
self.parameter_name
|
|
92
|
+
).upper()
|
|
93
|
+
except (KeyError, AttributeError):
|
|
94
|
+
self.simtel_parameter_name = self.parameter_name.upper()
|
|
65
95
|
self.simtel_telescope_name = simtel_telescope_name
|
|
66
96
|
self.camera_pixels = camera_pixels
|
|
67
97
|
self.parameter_dict = self.read_simtel_config_file(
|
|
@@ -73,7 +103,7 @@ class SimtelConfigReader:
|
|
|
73
103
|
return data_type == "limits" and self.parameter_dict.get("type") == "bool"
|
|
74
104
|
|
|
75
105
|
def _get_schema_values(self, data_type):
|
|
76
|
-
"""Check schema values for limits and
|
|
106
|
+
"""Check schema values for limits, unit, and default."""
|
|
77
107
|
try:
|
|
78
108
|
if data_type == "limits":
|
|
79
109
|
_from_schema = [
|
|
@@ -82,14 +112,25 @@ class SimtelConfigReader:
|
|
|
82
112
|
]
|
|
83
113
|
return _from_schema[0] if _from_schema[1] is None else _from_schema
|
|
84
114
|
if len(self.schema_dict["data"]) == 1:
|
|
85
|
-
return self.schema_dict["data"][0]
|
|
86
|
-
return [data.get(
|
|
115
|
+
return self.schema_dict["data"][0].get(data_type)
|
|
116
|
+
return [data.get(data_type) for data in self.schema_dict["data"]]
|
|
87
117
|
except (KeyError, IndexError):
|
|
88
118
|
return None
|
|
89
119
|
|
|
90
120
|
@staticmethod
|
|
91
121
|
def _values_match(_from_simtel, _from_schema):
|
|
92
|
-
"""
|
|
122
|
+
"""
|
|
123
|
+
Check if values match (are close for floats).
|
|
124
|
+
|
|
125
|
+
Convert where necessary astropy.Quantity to float.
|
|
126
|
+
|
|
127
|
+
"""
|
|
128
|
+
if isinstance(_from_simtel, u.Quantity):
|
|
129
|
+
_from_simtel = _from_simtel.value
|
|
130
|
+
if isinstance(_from_simtel, np.ndarray) and len(_from_simtel) > 0:
|
|
131
|
+
_from_simtel = np.array(
|
|
132
|
+
[v.value if isinstance(v, u.Quantity) else v for v in _from_simtel]
|
|
133
|
+
)
|
|
93
134
|
try:
|
|
94
135
|
if not isinstance(_from_schema, list | np.ndarray) and _from_simtel == _from_schema:
|
|
95
136
|
return True
|
|
@@ -184,6 +225,7 @@ class SimtelConfigReader:
|
|
|
184
225
|
dtype=_para_dict.get("type"),
|
|
185
226
|
n_dim=_para_dict.get("dimension"),
|
|
186
227
|
default=_para_dict.get("default"),
|
|
228
|
+
is_limit=(key == "limits"),
|
|
187
229
|
)
|
|
188
230
|
except KeyError:
|
|
189
231
|
pass
|
|
@@ -232,7 +274,7 @@ class SimtelConfigReader:
|
|
|
232
274
|
|
|
233
275
|
return column, except_from_all
|
|
234
276
|
|
|
235
|
-
def _add_value_from_simtel_cfg(self, column, dtype=None, n_dim=1, default=None):
|
|
277
|
+
def _add_value_from_simtel_cfg(self, column, dtype=None, n_dim=1, default=None, is_limit=False):
|
|
236
278
|
"""
|
|
237
279
|
Extract value(s) from simtel configuration file columns.
|
|
238
280
|
|
|
@@ -276,7 +318,42 @@ class SimtelConfigReader:
|
|
|
276
318
|
if dtype == "bool":
|
|
277
319
|
column = np.array([bool(int(item)) for item in column])
|
|
278
320
|
|
|
279
|
-
|
|
321
|
+
column, ndim = self._process_column(column, dtype)
|
|
322
|
+
if not is_limit:
|
|
323
|
+
column = self._add_units(column)
|
|
324
|
+
return column, ndim
|
|
325
|
+
|
|
326
|
+
def _add_units(self, column):
|
|
327
|
+
"""
|
|
328
|
+
Add units as given in schema file to column.
|
|
329
|
+
|
|
330
|
+
Take into account array types and dimensionless units.
|
|
331
|
+
Ensure that integer values are returned as integers (astropy converts
|
|
332
|
+
values to floats when multiplying them with units).
|
|
333
|
+
|
|
334
|
+
"""
|
|
335
|
+
try:
|
|
336
|
+
unit = self._get_schema_values("unit")
|
|
337
|
+
except TypeError: # no schema defined
|
|
338
|
+
return column
|
|
339
|
+
if unit is None or unit == "dimensionless":
|
|
340
|
+
return column
|
|
341
|
+
|
|
342
|
+
if isinstance(column, np.ndarray) and len(column) == len(unit):
|
|
343
|
+
return np.array(
|
|
344
|
+
[
|
|
345
|
+
col * u.Unit(un) if un != "dimensionless" else col
|
|
346
|
+
for col, un in zip(column, unit)
|
|
347
|
+
],
|
|
348
|
+
dtype=object,
|
|
349
|
+
)
|
|
350
|
+
if isinstance(unit, str):
|
|
351
|
+
column_with_unit = column * u.Unit(unit)
|
|
352
|
+
if isinstance(column, int | np.integer):
|
|
353
|
+
return u.Quantity(int(column_with_unit.value), unit, dtype=type(column))
|
|
354
|
+
return column_with_unit
|
|
355
|
+
|
|
356
|
+
return None
|
|
280
357
|
|
|
281
358
|
def _process_column(self, column, dtype):
|
|
282
359
|
"""
|
|
@@ -324,29 +401,3 @@ class SimtelConfigReader:
|
|
|
324
401
|
if self.camera_pixels is not None and self.simtel_parameter_name in ["NIGHTSKY_BACKGROUND"]:
|
|
325
402
|
return str(np.dtype(column[0].lower())), self.camera_pixels
|
|
326
403
|
return str(np.dtype(column[0].lower())), int(column[1])
|
|
327
|
-
|
|
328
|
-
def _get_simtel_parameter_name(self, parameter_name):
|
|
329
|
-
"""
|
|
330
|
-
Return parameter name as used in sim_telarray.
|
|
331
|
-
|
|
332
|
-
This is documented in the schema file.
|
|
333
|
-
|
|
334
|
-
Parameters
|
|
335
|
-
----------
|
|
336
|
-
parameter_name: str
|
|
337
|
-
Model parameter name (as used in simtools)
|
|
338
|
-
|
|
339
|
-
Returns
|
|
340
|
-
-------
|
|
341
|
-
str
|
|
342
|
-
Parameter name as used in sim_telarray.
|
|
343
|
-
|
|
344
|
-
"""
|
|
345
|
-
try:
|
|
346
|
-
for sim_soft in self.schema_dict["simulation_software"]:
|
|
347
|
-
if sim_soft["name"] == "sim_telarray":
|
|
348
|
-
return sim_soft["internal_parameter_name"].upper()
|
|
349
|
-
except (KeyError, TypeError):
|
|
350
|
-
pass
|
|
351
|
-
|
|
352
|
-
return parameter_name.upper()
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import logging
|
|
5
5
|
import re
|
|
6
|
+
from pathlib import Path
|
|
6
7
|
|
|
7
8
|
import astropy.units as u
|
|
8
9
|
from astropy.table import Table
|
|
@@ -253,6 +254,9 @@ def read_simtel_table(parameter_name, file_path):
|
|
|
253
254
|
Table
|
|
254
255
|
Astropy table.
|
|
255
256
|
"""
|
|
257
|
+
if Path(file_path).suffix == ".ecsv": # table is already in correct format
|
|
258
|
+
return Table.read(file_path, format="ascii.ecsv")
|
|
259
|
+
|
|
256
260
|
if parameter_name == "atmospheric_transmission":
|
|
257
261
|
return _read_simtel_data_for_atmospheric_transmission(file_path)
|
|
258
262
|
|
simtools/utils/general.py
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import copy
|
|
4
4
|
import datetime
|
|
5
|
+
import glob
|
|
5
6
|
import json
|
|
6
7
|
import logging
|
|
7
8
|
import os
|
|
@@ -455,6 +456,34 @@ def find_file(name, loc):
|
|
|
455
456
|
raise FileNotFoundError(msg)
|
|
456
457
|
|
|
457
458
|
|
|
459
|
+
def resolve_file_patterns(file_names):
|
|
460
|
+
"""
|
|
461
|
+
Return a list of files names from string, list, or wildcard pattern.
|
|
462
|
+
|
|
463
|
+
Parameters
|
|
464
|
+
----------
|
|
465
|
+
file_names: str, list
|
|
466
|
+
File names to be searched for (wildcards allowed).
|
|
467
|
+
|
|
468
|
+
Returns
|
|
469
|
+
-------
|
|
470
|
+
list
|
|
471
|
+
List of file names found.
|
|
472
|
+
"""
|
|
473
|
+
if file_names is None:
|
|
474
|
+
raise ValueError("No file list provided.")
|
|
475
|
+
if not isinstance(file_names, list):
|
|
476
|
+
file_names = [file_names]
|
|
477
|
+
|
|
478
|
+
_files = []
|
|
479
|
+
for file_name in file_names:
|
|
480
|
+
# use glob (and not Path.glob) for easier wildcard handling
|
|
481
|
+
_files.extend(Path(f) for f in glob.glob(str(file_name), recursive=True)) # noqa: PTH207
|
|
482
|
+
if not _files:
|
|
483
|
+
raise FileNotFoundError(f"No files found: {file_names}")
|
|
484
|
+
return _files
|
|
485
|
+
|
|
486
|
+
|
|
458
487
|
def get_log_excerpt(log_file, n_last_lines=30):
|
|
459
488
|
"""
|
|
460
489
|
Get an excerpt from a log file, namely the n_last_lines of the file.
|
|
@@ -696,16 +725,28 @@ def validate_data_type(reference_dtype, value=None, dtype=None, allow_subtypes=T
|
|
|
696
725
|
):
|
|
697
726
|
return True
|
|
698
727
|
|
|
699
|
-
if
|
|
700
|
-
return
|
|
728
|
+
if reference_dtype in ("boolean", "bool"):
|
|
729
|
+
return _is_valid_boolean_type(dtype, value)
|
|
701
730
|
|
|
702
|
-
|
|
703
|
-
np.issubdtype(reference_dtype, np.integer) or np.issubdtype(reference_dtype, np.floating)
|
|
704
|
-
):
|
|
705
|
-
return True
|
|
731
|
+
return _is_valid_numeric_type(dtype, reference_dtype)
|
|
706
732
|
|
|
707
|
-
|
|
733
|
+
|
|
734
|
+
def _is_valid_boolean_type(dtype, value):
|
|
735
|
+
"""Check if dtype or value is a valid boolean type."""
|
|
736
|
+
if value in {0, 1}:
|
|
708
737
|
return True
|
|
738
|
+
return np.issubdtype(dtype, np.bool_)
|
|
739
|
+
|
|
740
|
+
|
|
741
|
+
def _is_valid_numeric_type(dtype, reference_dtype):
|
|
742
|
+
"""Check if dtype is a valid numeric type compared to reference_dtype."""
|
|
743
|
+
if np.issubdtype(dtype, np.integer):
|
|
744
|
+
return np.issubdtype(reference_dtype, np.integer) or np.issubdtype(
|
|
745
|
+
reference_dtype, np.floating
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
if np.issubdtype(dtype, np.floating):
|
|
749
|
+
return np.issubdtype(reference_dtype, np.floating)
|
|
709
750
|
|
|
710
751
|
return False
|
|
711
752
|
|
|
@@ -851,8 +892,8 @@ def get_structure_array_from_table(table, column_names):
|
|
|
851
892
|
Structured array containing the table data.
|
|
852
893
|
"""
|
|
853
894
|
return np.array(
|
|
854
|
-
list(zip(*[np.array(table[col]) for col in column_names])),
|
|
855
|
-
dtype=[(col, np.array(table[col]).dtype) for col in column_names],
|
|
895
|
+
list(zip(*[np.array(table[col]) for col in column_names if col in table.colnames])),
|
|
896
|
+
dtype=[(col, np.array(table[col]).dtype) for col in column_names if col in table.colnames],
|
|
856
897
|
)
|
|
857
898
|
|
|
858
899
|
|
simtools/utils/names.py
CHANGED
|
@@ -353,6 +353,8 @@ def get_array_element_type_from_name(array_element_name):
|
|
|
353
353
|
"""
|
|
354
354
|
Get array element type from array element name (e.g "MSTN" from "MSTN-01").
|
|
355
355
|
|
|
356
|
+
For sites, return site name.
|
|
357
|
+
|
|
356
358
|
Parameters
|
|
357
359
|
----------
|
|
358
360
|
array_element_name: str
|
|
@@ -363,7 +365,10 @@ def get_array_element_type_from_name(array_element_name):
|
|
|
363
365
|
str
|
|
364
366
|
Array element type.
|
|
365
367
|
"""
|
|
366
|
-
|
|
368
|
+
try: # e.g. instrument is 'North' as given for the site parameters
|
|
369
|
+
return validate_site_name(array_element_name)
|
|
370
|
+
except ValueError: # any other telescope or calibration device
|
|
371
|
+
return _validate_name(array_element_name.split("-")[0], array_elements())
|
|
367
372
|
|
|
368
373
|
|
|
369
374
|
def get_array_element_id_from_name(array_element_name):
|
|
@@ -460,7 +465,7 @@ def get_collection_name_from_array_element_name(array_element_name, array_elemen
|
|
|
460
465
|
"""
|
|
461
466
|
try:
|
|
462
467
|
return array_elements()[get_array_element_type_from_name(array_element_name)]["collection"]
|
|
463
|
-
except ValueError as exc:
|
|
468
|
+
except (ValueError, KeyError) as exc:
|
|
464
469
|
if array_elements_only:
|
|
465
470
|
raise ValueError(f"Invalid array element name {array_element_name}") from exc
|
|
466
471
|
try:
|
|
@@ -123,13 +123,15 @@ def _split_value_is_quantity(value, is_integer=False):
|
|
|
123
123
|
|
|
124
124
|
|
|
125
125
|
def _split_value_is_string(value, is_integer=False):
|
|
126
|
-
"""Split
|
|
126
|
+
"""Split value and unit for a string."""
|
|
127
127
|
if value.isdigit(): # single integer value
|
|
128
128
|
return int(value), None
|
|
129
129
|
try: # single value with/without unit
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
)
|
|
130
|
+
quantity = u.Quantity(value)
|
|
131
|
+
unit = str(quantity.unit)
|
|
132
|
+
if unit.isdigit(): # cases where numbers are wrongly identified as units
|
|
133
|
+
raise ValueError
|
|
134
|
+
return (int(quantity.value), unit) if is_integer else (quantity.value, unit)
|
|
133
135
|
except ValueError:
|
|
134
136
|
return _split_value_is_list(gen.convert_string_to_list(value), is_integer)
|
|
135
137
|
except TypeError: # string value (not numerical)
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
"""Plot tabular data."""
|
|
3
3
|
|
|
4
4
|
import numpy as np
|
|
5
|
+
from astropy.table import Table
|
|
5
6
|
|
|
6
7
|
import simtools.utils.general as gen
|
|
8
|
+
from simtools.db import db_handler
|
|
7
9
|
from simtools.io_operations import legacy_data_handler
|
|
8
|
-
from simtools.model.site_model import SiteModel
|
|
9
|
-
from simtools.model.telescope_model import TelescopeModel
|
|
10
10
|
from simtools.visualization import visualize
|
|
11
11
|
|
|
12
12
|
|
|
@@ -50,11 +50,15 @@ def read_table_data(config, db_config):
|
|
|
50
50
|
if "parameter" in _config:
|
|
51
51
|
table = _read_table_from_model_database(_config, db_config)
|
|
52
52
|
elif "file_name" in _config:
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
if "legacy" in _config.get("type", ""):
|
|
54
|
+
table = legacy_data_handler.read_legacy_data_as_table(
|
|
55
|
+
_config["file_name"], _config["type"]
|
|
56
|
+
)
|
|
57
|
+
else:
|
|
58
|
+
table = Table.read(_config["file_name"], format="ascii.ecsv")
|
|
56
59
|
else:
|
|
57
60
|
raise ValueError("No table data defined in configuration.")
|
|
61
|
+
|
|
58
62
|
if _config.get("normalize_y"):
|
|
59
63
|
table[_config["column_y"]] = (
|
|
60
64
|
table[_config["column_y"]] / table[_config["column_y"]].max()
|
|
@@ -66,7 +70,13 @@ def read_table_data(config, db_config):
|
|
|
66
70
|
_config["select_values"]["value"],
|
|
67
71
|
)
|
|
68
72
|
data[_config["label"]] = gen.get_structure_array_from_table(
|
|
69
|
-
table,
|
|
73
|
+
table,
|
|
74
|
+
[
|
|
75
|
+
_config["column_x"],
|
|
76
|
+
_config["column_y"],
|
|
77
|
+
_config.get("column_x_err"),
|
|
78
|
+
_config.get("column_y_err"),
|
|
79
|
+
],
|
|
70
80
|
)
|
|
71
81
|
return data
|
|
72
82
|
|
|
@@ -85,20 +95,15 @@ def _read_table_from_model_database(table_config, db_config):
|
|
|
85
95
|
Table
|
|
86
96
|
Astropy table.
|
|
87
97
|
"""
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
site=table_config["site"],
|
|
98
|
-
model_version=table_config["model_version"],
|
|
99
|
-
mongo_db_config=db_config,
|
|
100
|
-
)
|
|
101
|
-
return model.get_model_file_as_table(table_config["parameter"])
|
|
98
|
+
db = db_handler.DatabaseHandler(mongo_db_config=db_config)
|
|
99
|
+
return db.export_model_file(
|
|
100
|
+
parameter=table_config["parameter"],
|
|
101
|
+
site=table_config["site"],
|
|
102
|
+
array_element_name=table_config.get("telescope"),
|
|
103
|
+
parameter_version=table_config.get("parameter_version"),
|
|
104
|
+
model_version=table_config.get("model_version"),
|
|
105
|
+
export_file_as_table=True,
|
|
106
|
+
)
|
|
102
107
|
|
|
103
108
|
|
|
104
109
|
def _select_values_from_table(table, column_name, value):
|