gammasimtools 0.9.0__py3-none-any.whl → 0.11.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.9.0.dist-info → gammasimtools-0.11.0.dist-info}/METADATA +4 -2
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/RECORD +133 -117
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/entry_points.txt +6 -1
- simtools/_version.py +9 -4
- simtools/applications/calculate_trigger_rate.py +15 -38
- simtools/applications/convert_all_model_parameters_from_simtel.py +9 -29
- simtools/applications/convert_geo_coordinates_of_array_elements.py +47 -45
- simtools/applications/convert_model_parameter_from_simtel.py +2 -3
- simtools/applications/db_add_file_to_db.py +1 -3
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +110 -0
- simtools/applications/db_add_value_from_json_to_db.py +1 -2
- simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +6 -6
- simtools/applications/db_get_file_from_db.py +11 -12
- simtools/applications/db_get_parameter_from_db.py +26 -35
- simtools/applications/derive_mirror_rnda.py +1 -2
- simtools/applications/derive_photon_electron_spectrum.py +99 -0
- simtools/applications/derive_psf_parameters.py +1 -0
- simtools/applications/docs_produce_array_element_report.py +71 -0
- simtools/applications/docs_produce_model_parameter_reports.py +63 -0
- simtools/applications/generate_array_config.py +17 -17
- simtools/applications/generate_corsika_histograms.py +2 -2
- simtools/applications/generate_regular_arrays.py +19 -17
- simtools/applications/generate_simtel_array_histograms.py +11 -48
- simtools/applications/production_derive_limits.py +95 -0
- simtools/applications/production_generate_simulation_config.py +37 -33
- simtools/applications/production_scale_events.py +4 -9
- simtools/applications/run_application.py +165 -0
- simtools/applications/simulate_light_emission.py +0 -4
- simtools/applications/simulate_prod.py +1 -1
- simtools/applications/simulate_prod_htcondor_generator.py +26 -26
- simtools/applications/submit_data_from_external.py +12 -4
- simtools/applications/submit_model_parameter_from_external.py +18 -11
- simtools/applications/validate_camera_efficiency.py +2 -2
- simtools/applications/validate_file_using_schema.py +26 -22
- simtools/camera/single_photon_electron_spectrum.py +168 -0
- simtools/configuration/commandline_parser.py +37 -1
- simtools/configuration/configurator.py +8 -10
- simtools/constants.py +10 -3
- simtools/corsika/corsika_config.py +19 -17
- simtools/corsika/corsika_histograms.py +5 -7
- simtools/corsika/corsika_histograms_visualize.py +2 -4
- simtools/data_model/data_reader.py +0 -3
- simtools/data_model/metadata_collector.py +20 -12
- simtools/data_model/metadata_model.py +8 -124
- simtools/data_model/model_data_writer.py +81 -75
- simtools/data_model/schema.py +220 -0
- simtools/data_model/validate_data.py +79 -68
- simtools/db/db_handler.py +350 -492
- simtools/db/db_model_upload.py +139 -0
- simtools/dependencies.py +112 -0
- simtools/io_operations/hdf5_handler.py +54 -24
- simtools/layout/array_layout.py +38 -32
- simtools/model/array_model.py +13 -7
- simtools/model/model_parameter.py +55 -54
- simtools/model/site_model.py +2 -2
- simtools/production_configuration/calculate_statistical_errors_grid_point.py +119 -145
- simtools/production_configuration/event_scaler.py +9 -35
- simtools/production_configuration/generate_simulation_config.py +9 -44
- simtools/production_configuration/interpolation_handler.py +9 -15
- simtools/production_configuration/limits_calculation.py +202 -0
- simtools/reporting/docs_read_parameters.py +310 -0
- simtools/runners/corsika_simtel_runner.py +4 -4
- simtools/schemas/{integration_tests_config.metaschema.yml → application_workflow.metaschema.yml} +61 -27
- simtools/schemas/array_elements.yml +8 -0
- simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +39 -0
- simtools/schemas/input/single_pe_spectrum.schema.yml +38 -0
- simtools/schemas/model_parameter.metaschema.yml +103 -2
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +4 -1
- simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
- simtools/schemas/model_parameters/array_window.schema.yml +37 -0
- simtools/schemas/model_parameters/asum_clipping.schema.yml +0 -4
- simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
- simtools/schemas/model_parameters/correct_nsb_spectrum_to_telescope_altitude.schema.yml +1 -1
- simtools/schemas/model_parameters/corsika_cherenkov_photon_bunch_size.schema.yml +2 -0
- simtools/schemas/model_parameters/corsika_cherenkov_photon_wavelength_range.schema.yml +2 -0
- simtools/schemas/model_parameters/corsika_first_interaction_height.schema.yml +2 -0
- simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +4 -2
- simtools/schemas/model_parameters/corsika_iact_max_bunches.schema.yml +2 -0
- simtools/schemas/model_parameters/corsika_iact_split_auto.schema.yml +2 -0
- simtools/schemas/model_parameters/corsika_longitudinal_shower_development.schema.yml +2 -0
- simtools/schemas/model_parameters/corsika_particle_kinetic_energy_cutoff.schema.yml +2 -0
- simtools/schemas/model_parameters/corsika_starting_grammage.schema.yml +2 -0
- simtools/schemas/model_parameters/dsum_clipping.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_offset.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_pedsub.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_prescale.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_presum_max.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_shaping.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +0 -2
- simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +0 -2
- simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
- simtools/schemas/model_parameters/fadc_noise.schema.yml +3 -3
- simtools/schemas/model_parameters/fake_mirror_list.schema.yml +33 -0
- simtools/schemas/model_parameters/iobuf_maximum.schema.yml +1 -1
- simtools/schemas/model_parameters/iobuf_output_maximum.schema.yml +1 -1
- simtools/schemas/model_parameters/laser_photons.schema.yml +2 -2
- 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/min_photoelectrons.schema.yml +1 -1
- simtools/schemas/model_parameters/min_photons.schema.yml +1 -1
- simtools/schemas/model_parameters/random_generator.schema.yml +1 -1
- simtools/schemas/model_parameters/sampled_output.schema.yml +1 -1
- simtools/schemas/model_parameters/save_pe_with_amplitude.schema.yml +1 -1
- simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
- simtools/schemas/model_parameters/store_photoelectrons.schema.yml +1 -1
- simtools/schemas/model_parameters/tailcut_scale.schema.yml +1 -1
- simtools/schemas/production_configuration_metrics.schema.yml +68 -0
- simtools/schemas/production_tables.schema.yml +41 -0
- simtools/simtel/simtel_config_reader.py +1 -2
- simtools/simtel/simtel_config_writer.py +6 -8
- simtools/simtel/simtel_io_histogram.py +32 -68
- simtools/simtel/simtel_io_histograms.py +17 -34
- simtools/simtel/simulator_array.py +2 -1
- simtools/simtel/simulator_camera_efficiency.py +6 -3
- simtools/simtel/simulator_light_emission.py +5 -6
- simtools/simtel/simulator_ray_tracing.py +3 -4
- simtools/testing/configuration.py +2 -1
- simtools/testing/helpers.py +6 -13
- simtools/testing/validate_output.py +141 -47
- simtools/utils/general.py +114 -14
- simtools/utils/names.py +299 -157
- simtools/utils/value_conversion.py +17 -13
- simtools/version.py +2 -2
- simtools/visualization/legend_handlers.py +2 -0
- simtools/applications/db_add_model_parameters_from_repository_to_db.py +0 -176
- simtools/db/db_array_elements.py +0 -130
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/LICENSE +0 -0
- {gammasimtools-0.9.0.dist-info → gammasimtools-0.11.0.dist-info}/top_level.txt +0 -0
- /simtools/{camera_efficiency.py → camera/camera_efficiency.py} +0 -0
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Upload a simulation model (parameters and production tables) to the database."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import simtools.utils.general as gen
|
|
7
|
+
from simtools.utils import names
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def add_values_from_json_to_db(file, collection, db, db_name, file_prefix):
|
|
13
|
+
"""
|
|
14
|
+
Upload new model parameter from json files to db.
|
|
15
|
+
|
|
16
|
+
Parameters
|
|
17
|
+
----------
|
|
18
|
+
file : list
|
|
19
|
+
Json file to be uploaded to the DB.
|
|
20
|
+
collection : str
|
|
21
|
+
The DB collection to which to add the file.
|
|
22
|
+
db : DatabaseHandler
|
|
23
|
+
Database handler object.
|
|
24
|
+
db_name : str
|
|
25
|
+
Name of the database to be created.
|
|
26
|
+
file_prefix : str
|
|
27
|
+
Path to location of all additional files to be uploaded.
|
|
28
|
+
"""
|
|
29
|
+
par_dict = gen.collect_data_from_file(file_name=file)
|
|
30
|
+
logger.info(
|
|
31
|
+
f"Adding the following parameter to the DB: {par_dict['parameter']} "
|
|
32
|
+
f"version {par_dict['parameter_version']} "
|
|
33
|
+
f"(collection {collection} in database {db_name})"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
db.add_new_parameter(
|
|
37
|
+
db_name=db_name,
|
|
38
|
+
par_dict=par_dict,
|
|
39
|
+
collection_name=collection,
|
|
40
|
+
file_prefix=file_prefix,
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def add_model_parameters_to_db(args_dict, db):
|
|
45
|
+
"""
|
|
46
|
+
Read model parameters from a directory and upload them to the database.
|
|
47
|
+
|
|
48
|
+
Parameters
|
|
49
|
+
----------
|
|
50
|
+
args_dict : dict
|
|
51
|
+
Command line arguments.
|
|
52
|
+
db : DatabaseHandler
|
|
53
|
+
Database handler object.
|
|
54
|
+
"""
|
|
55
|
+
input_path = Path(args_dict["input_path"])
|
|
56
|
+
logger.info(f"Reading model parameters from repository path {input_path}")
|
|
57
|
+
array_elements = [d for d in input_path.iterdir() if d.is_dir()]
|
|
58
|
+
for element in array_elements:
|
|
59
|
+
collection = names.get_collection_name_from_array_element_name(element.name, False)
|
|
60
|
+
if collection == "Files":
|
|
61
|
+
logger.info("Files (tables) are uploaded with the corresponding model parameters")
|
|
62
|
+
continue
|
|
63
|
+
logger.info(f"Reading model parameters for {element.name} into collection {collection}")
|
|
64
|
+
files_to_insert = list(Path(element).rglob("*json"))
|
|
65
|
+
for file in files_to_insert:
|
|
66
|
+
add_values_from_json_to_db(
|
|
67
|
+
file=file,
|
|
68
|
+
collection=collection,
|
|
69
|
+
db=db,
|
|
70
|
+
db_name=args_dict["db_name"],
|
|
71
|
+
file_prefix=input_path / "Files",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def add_production_tables_to_db(args_dict, db):
|
|
76
|
+
"""
|
|
77
|
+
Read production tables from a directory and upload them to the database.
|
|
78
|
+
|
|
79
|
+
One dictionary per collection is prepared for each model version, containing
|
|
80
|
+
tables of all array elements, sites, and configuration parameters.
|
|
81
|
+
|
|
82
|
+
Parameters
|
|
83
|
+
----------
|
|
84
|
+
args_dict : dict
|
|
85
|
+
Command line arguments.
|
|
86
|
+
db : DatabaseHandler
|
|
87
|
+
Database handler object.
|
|
88
|
+
"""
|
|
89
|
+
input_path = Path(args_dict["input_path"])
|
|
90
|
+
logger.info(f"Reading production tables from repository path {input_path}")
|
|
91
|
+
|
|
92
|
+
for model in filter(Path.is_dir, input_path.iterdir()):
|
|
93
|
+
logger.info(f"Reading production tables for model version {model.name}")
|
|
94
|
+
model_dict = {}
|
|
95
|
+
for file in sorted(model.rglob("*json")):
|
|
96
|
+
_read_production_table(model_dict, file, model.name)
|
|
97
|
+
|
|
98
|
+
for collection, data in model_dict.items():
|
|
99
|
+
if not data["parameters"]:
|
|
100
|
+
logger.info(f"No production table for {collection} in model version {model.name}")
|
|
101
|
+
continue
|
|
102
|
+
logger.info(f"Adding production table for {collection} to the database")
|
|
103
|
+
db.add_production_table(
|
|
104
|
+
db_name=args_dict["db_name"],
|
|
105
|
+
production_table=data,
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _read_production_table(model_dict, file, model_name):
|
|
110
|
+
"""Read a single production table from file."""
|
|
111
|
+
array_element = file.stem
|
|
112
|
+
collection = names.get_collection_name_from_array_element_name(array_element, False)
|
|
113
|
+
model_dict.setdefault(
|
|
114
|
+
collection,
|
|
115
|
+
{
|
|
116
|
+
"collection": collection,
|
|
117
|
+
"model_version": model_name,
|
|
118
|
+
"parameters": {},
|
|
119
|
+
"design_model": {},
|
|
120
|
+
},
|
|
121
|
+
)
|
|
122
|
+
parameter_dict = gen.collect_data_from_file(file_name=file)
|
|
123
|
+
logger.info(f"Reading production table for {array_element} (collection {collection})")
|
|
124
|
+
try:
|
|
125
|
+
if array_element in ("configuration_corsika", "configuration_sim_telarray"):
|
|
126
|
+
model_dict[collection]["parameters"] = parameter_dict["parameters"]
|
|
127
|
+
else:
|
|
128
|
+
model_dict[collection]["parameters"][array_element] = parameter_dict["parameters"][
|
|
129
|
+
array_element
|
|
130
|
+
]
|
|
131
|
+
except KeyError as exc:
|
|
132
|
+
logger.error(f"KeyError: {exc}")
|
|
133
|
+
raise
|
|
134
|
+
try:
|
|
135
|
+
model_dict[collection]["design_model"][array_element] = parameter_dict["design_model"][
|
|
136
|
+
array_element
|
|
137
|
+
]
|
|
138
|
+
except KeyError:
|
|
139
|
+
pass
|
simtools/dependencies.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Simtools dependencies version management.
|
|
3
|
+
|
|
4
|
+
This modules provides two main functionalities:
|
|
5
|
+
|
|
6
|
+
- retrieve the versions of simtools dependencies (e.g., databases, sim_telarray, CORSIKA)
|
|
7
|
+
- provide space for future implementations of version management
|
|
8
|
+
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import logging
|
|
12
|
+
import os
|
|
13
|
+
import re
|
|
14
|
+
import subprocess
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
import simtools.utils.general as gen
|
|
18
|
+
from simtools.db.db_handler import DatabaseHandler
|
|
19
|
+
|
|
20
|
+
_logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_version_string(db_config=None):
|
|
24
|
+
"""Print the versions of the dependencies."""
|
|
25
|
+
return (
|
|
26
|
+
f"Database version: {get_database_version(db_config)}\n"
|
|
27
|
+
f"sim_telarray version: {get_sim_telarray_version()}\n"
|
|
28
|
+
f"CORSIKA version: {get_corsika_version()}\n"
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_database_version(db_config):
|
|
33
|
+
"""
|
|
34
|
+
Get the version of the simulation model data base used.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
db_config : dict
|
|
39
|
+
Dictionary containing the database configuration.
|
|
40
|
+
|
|
41
|
+
Returns
|
|
42
|
+
-------
|
|
43
|
+
str
|
|
44
|
+
Version of the simulation model data base used.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
if db_config is None:
|
|
48
|
+
return None
|
|
49
|
+
db = DatabaseHandler(db_config)
|
|
50
|
+
return db.mongo_db_config.get("db_simulation_model")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_sim_telarray_version():
|
|
54
|
+
"""
|
|
55
|
+
Get the version of the sim_telarray package using 'sim_telarray --version'.
|
|
56
|
+
|
|
57
|
+
Returns
|
|
58
|
+
-------
|
|
59
|
+
str
|
|
60
|
+
Version of the sim_telarray package.
|
|
61
|
+
"""
|
|
62
|
+
sim_telarray_path = os.getenv("SIMTOOLS_SIMTEL_PATH")
|
|
63
|
+
if sim_telarray_path is None:
|
|
64
|
+
_logger.warning("Environment variable SIMTOOLS_SIMTEL_PATH is not set.")
|
|
65
|
+
return None
|
|
66
|
+
sim_telarray_path = Path(sim_telarray_path) / "sim_telarray" / "bin" / "sim_telarray"
|
|
67
|
+
|
|
68
|
+
# expect stdout with e.g. a line 'Release: 2024.271.0 from 2024-09-27'
|
|
69
|
+
result = subprocess.run(
|
|
70
|
+
[sim_telarray_path, "--version"],
|
|
71
|
+
capture_output=True,
|
|
72
|
+
text=True,
|
|
73
|
+
check=False,
|
|
74
|
+
)
|
|
75
|
+
match = re.search(r"^Release:\s+(.+)", result.stdout, re.MULTILINE)
|
|
76
|
+
|
|
77
|
+
if match:
|
|
78
|
+
return match.group(1).split()[0]
|
|
79
|
+
raise ValueError(f"sim_telarray release not found in {result.stdout}")
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_corsika_version():
|
|
83
|
+
"""
|
|
84
|
+
Get the version of the corsika package.
|
|
85
|
+
|
|
86
|
+
Returns
|
|
87
|
+
-------
|
|
88
|
+
str
|
|
89
|
+
Version of the corsika package.
|
|
90
|
+
"""
|
|
91
|
+
try:
|
|
92
|
+
build_opts = get_build_options()
|
|
93
|
+
except (FileNotFoundError, TypeError):
|
|
94
|
+
_logger.warning("CORSIKA version not implemented yet.")
|
|
95
|
+
return None
|
|
96
|
+
return build_opts.get("corsika_version")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def get_build_options():
|
|
100
|
+
"""
|
|
101
|
+
Return CORSIKA / sim_telarray build options.
|
|
102
|
+
|
|
103
|
+
Expects a build_opts.yml file in the sim_telarray directory.
|
|
104
|
+
"""
|
|
105
|
+
try:
|
|
106
|
+
return gen.collect_data_from_file(
|
|
107
|
+
Path(os.getenv("SIMTOOLS_SIMTEL_PATH")) / "build_opts.yml"
|
|
108
|
+
)
|
|
109
|
+
except FileNotFoundError as exc:
|
|
110
|
+
raise FileNotFoundError("No build_opts.yml file found.") from exc
|
|
111
|
+
except TypeError as exc:
|
|
112
|
+
raise TypeError("SIMTOOLS_SIMTEL_PATH not defined.") from exc
|
|
@@ -41,40 +41,26 @@ def fill_hdf5_table(hist, x_bin_edges, y_bin_edges, x_label, y_label, meta_data)
|
|
|
41
41
|
meta_data: dict
|
|
42
42
|
Dictionary with the histogram metadata.
|
|
43
43
|
"""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
validate_histogram(hist, y_bin_edges)
|
|
45
|
+
|
|
46
|
+
meta_data["x_bin_edges"] = x_bin_edges
|
|
47
47
|
meta_data["x_bin_edges_unit"] = (
|
|
48
48
|
x_bin_edges.unit if isinstance(x_bin_edges, u.Quantity) else u.dimensionless_unscaled
|
|
49
49
|
)
|
|
50
|
-
|
|
51
50
|
if y_bin_edges is not None:
|
|
52
|
-
|
|
53
|
-
meta_data["y_bin_edges"] = sanitize_name(y_label)
|
|
54
|
-
names = [
|
|
55
|
-
f"{meta_data['y_bin_edges'].split('__')[0]}_{i}"
|
|
56
|
-
for i in range(len(y_bin_edges[:-1]))
|
|
57
|
-
]
|
|
58
|
-
else:
|
|
59
|
-
names = [
|
|
60
|
-
f"{meta_data['Title'].split('__')[0]}_{i}" for i in range(len(y_bin_edges[:-1]))
|
|
61
|
-
]
|
|
51
|
+
meta_data["y_bin_edges"] = y_bin_edges
|
|
62
52
|
meta_data["y_bin_edges_unit"] = (
|
|
63
53
|
y_bin_edges.unit if isinstance(y_bin_edges, u.Quantity) else u.dimensionless_unscaled
|
|
64
54
|
)
|
|
65
55
|
|
|
66
|
-
|
|
67
|
-
[hist[i, :] for i in range(len(y_bin_edges[:-1]))],
|
|
68
|
-
names=names,
|
|
69
|
-
meta=meta_data,
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
else:
|
|
56
|
+
if hist.ndim == 1:
|
|
73
57
|
if x_label is not None:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
else:
|
|
58
|
+
names = sanitize_name(x_label)
|
|
59
|
+
try:
|
|
77
60
|
names = meta_data["Title"]
|
|
61
|
+
except KeyError:
|
|
62
|
+
_logger.warning("Title not found in metadata.")
|
|
63
|
+
|
|
78
64
|
table = Table(
|
|
79
65
|
[
|
|
80
66
|
x_bin_edges[:-1],
|
|
@@ -83,9 +69,53 @@ def fill_hdf5_table(hist, x_bin_edges, y_bin_edges, x_label, y_label, meta_data)
|
|
|
83
69
|
names=(names, sanitize_name("Values")),
|
|
84
70
|
meta=meta_data,
|
|
85
71
|
)
|
|
72
|
+
else:
|
|
73
|
+
if y_label is not None:
|
|
74
|
+
names = [
|
|
75
|
+
f"{sanitize_name(y_label).split('__')[0]}_{i}" for i in range(len(y_bin_edges[:-1]))
|
|
76
|
+
]
|
|
77
|
+
try:
|
|
78
|
+
names = [
|
|
79
|
+
f"{(meta_data['Title']).split('__')[0]}_{sanitize_name(y_label)}_{i}"
|
|
80
|
+
for i in range(len(y_bin_edges[:-1]))
|
|
81
|
+
]
|
|
82
|
+
except KeyError:
|
|
83
|
+
_logger.warning("Title not found in metadata.")
|
|
84
|
+
names = [
|
|
85
|
+
f"{sanitize_name(y_label).split('__')[0]}_{i}" for i in range(len(y_bin_edges[:-1]))
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
table = Table(
|
|
89
|
+
[hist[i, :] for i in range(len(y_bin_edges[:-1]))],
|
|
90
|
+
names=names,
|
|
91
|
+
meta=meta_data,
|
|
92
|
+
)
|
|
93
|
+
|
|
86
94
|
return table
|
|
87
95
|
|
|
88
96
|
|
|
97
|
+
def validate_histogram(hist, y_bin_edges):
|
|
98
|
+
"""Validate histogram dimensions and y_bin_edges consistency.
|
|
99
|
+
|
|
100
|
+
Parameters
|
|
101
|
+
----------
|
|
102
|
+
hist (np.ndarray): The histogram array, expected to be 1D or 2D.
|
|
103
|
+
y_bin_edges (array-like or None): Bin edges for the second dimension (if applicable).
|
|
104
|
+
|
|
105
|
+
Raises
|
|
106
|
+
------
|
|
107
|
+
ValueError: If histogram dimensions are invalid or inconsistent with y_bin_edges.
|
|
108
|
+
"""
|
|
109
|
+
if hist.ndim not in (1, 2):
|
|
110
|
+
raise ValueError("Histogram must be either 1D or 2D.")
|
|
111
|
+
|
|
112
|
+
if hist.ndim == 1 and y_bin_edges is not None:
|
|
113
|
+
raise ValueError("y_bin_edges should be None for 1D histograms.")
|
|
114
|
+
|
|
115
|
+
if hist.ndim == 2 and y_bin_edges is None:
|
|
116
|
+
raise ValueError("y_bin_edges should not be None for 2D histograms.")
|
|
117
|
+
|
|
118
|
+
|
|
89
119
|
def read_hdf5(hdf5_file_name):
|
|
90
120
|
"""
|
|
91
121
|
Read a hdf5 output file.
|
simtools/layout/array_layout.py
CHANGED
|
@@ -9,7 +9,7 @@ import numpy as np
|
|
|
9
9
|
from astropy.table import QTable
|
|
10
10
|
|
|
11
11
|
import simtools.utils.general as gen
|
|
12
|
-
from simtools.data_model import data_reader
|
|
12
|
+
from simtools.data_model import data_reader, schema
|
|
13
13
|
from simtools.io_operations import io_handler
|
|
14
14
|
from simtools.layout.geo_coordinates import GeoCoordinates
|
|
15
15
|
from simtools.layout.telescope_position import TelescopePosition
|
|
@@ -386,7 +386,9 @@ class ArrayLayout:
|
|
|
386
386
|
with Path(file_name).open("r", encoding="utf-8") as file:
|
|
387
387
|
data = json.load(file)
|
|
388
388
|
|
|
389
|
-
position =
|
|
389
|
+
position = data["value"]
|
|
390
|
+
if isinstance(position, str):
|
|
391
|
+
position = gen.convert_string_to_list(position)
|
|
390
392
|
self.site = data.get("site", None)
|
|
391
393
|
|
|
392
394
|
table = QTable()
|
|
@@ -443,9 +445,11 @@ class ArrayLayout:
|
|
|
443
445
|
)
|
|
444
446
|
try:
|
|
445
447
|
tel_model = self._get_telescope_model(telescope_name)
|
|
446
|
-
except ValueError:
|
|
448
|
+
except ValueError: # telescope not found in the database revert to design model
|
|
447
449
|
tel_model = self._get_telescope_model(
|
|
448
|
-
names.
|
|
450
|
+
names.array_element_design_types(
|
|
451
|
+
names.get_array_element_type_from_name(telescope_name)
|
|
452
|
+
)[0]
|
|
449
453
|
)
|
|
450
454
|
|
|
451
455
|
for para in ("telescope_axis_height", "telescope_sphere_radius"):
|
|
@@ -579,7 +583,12 @@ class ArrayLayout:
|
|
|
579
583
|
|
|
580
584
|
return table
|
|
581
585
|
|
|
582
|
-
def export_one_telescope_as_json(
|
|
586
|
+
def export_one_telescope_as_json(
|
|
587
|
+
self,
|
|
588
|
+
crs_name,
|
|
589
|
+
parameter_version=None,
|
|
590
|
+
schema_version=None,
|
|
591
|
+
):
|
|
583
592
|
"""
|
|
584
593
|
Return a list containing a single telescope in simtools-DB-style json.
|
|
585
594
|
|
|
@@ -587,6 +596,8 @@ class ArrayLayout:
|
|
|
587
596
|
----------
|
|
588
597
|
crs_name: str
|
|
589
598
|
Name of coordinate system to be used for export.
|
|
599
|
+
schema_version: str
|
|
600
|
+
Version of the schema.
|
|
590
601
|
|
|
591
602
|
Returns
|
|
592
603
|
-------
|
|
@@ -596,43 +607,39 @@ class ArrayLayout:
|
|
|
596
607
|
table = self.export_telescope_list_table(crs_name)
|
|
597
608
|
if len(table) != 1:
|
|
598
609
|
raise ValueError("Only one telescope can be exported to json")
|
|
599
|
-
parameter_name =
|
|
610
|
+
parameter_name = value = None
|
|
600
611
|
if crs_name == "ground":
|
|
601
612
|
parameter_name = "array_element_position_ground"
|
|
602
|
-
|
|
603
|
-
[
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
]
|
|
608
|
-
)
|
|
613
|
+
value = [
|
|
614
|
+
table["position_x"][0].value,
|
|
615
|
+
table["position_y"][0].value,
|
|
616
|
+
table["position_z"][0].value,
|
|
617
|
+
]
|
|
609
618
|
elif crs_name == "utm":
|
|
610
619
|
parameter_name = "array_element_position_utm"
|
|
611
|
-
|
|
612
|
-
[
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
]
|
|
617
|
-
)
|
|
620
|
+
value = [
|
|
621
|
+
table["utm_east"][0].value,
|
|
622
|
+
table["utm_north"][0].value,
|
|
623
|
+
table["altitude"][0].value,
|
|
624
|
+
]
|
|
618
625
|
elif crs_name == "mercator":
|
|
619
626
|
parameter_name = "array_element_position_mercator"
|
|
620
|
-
|
|
621
|
-
[
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
)
|
|
627
|
+
value = [
|
|
628
|
+
table["latitude"][0].value,
|
|
629
|
+
table["longitude"][0].value,
|
|
630
|
+
table["altitude"][0].value,
|
|
631
|
+
]
|
|
632
|
+
|
|
627
633
|
return {
|
|
634
|
+
"schema_version": schema.get_model_parameter_schema_version(schema_version),
|
|
628
635
|
"parameter": parameter_name,
|
|
629
636
|
"instrument": table["telescope_name"][0],
|
|
630
637
|
"site": self.site,
|
|
631
|
-
"
|
|
632
|
-
"
|
|
638
|
+
"parameter_version": parameter_version,
|
|
639
|
+
"unique_id": None,
|
|
640
|
+
"value": value,
|
|
633
641
|
"unit": "m",
|
|
634
642
|
"type": "float64",
|
|
635
|
-
"applicable": True,
|
|
636
643
|
"file": False,
|
|
637
644
|
}
|
|
638
645
|
|
|
@@ -711,8 +718,7 @@ class ArrayLayout:
|
|
|
711
718
|
set(_telescope_list_from_name + _telescope_list_from_type)
|
|
712
719
|
)
|
|
713
720
|
self._logger.info(
|
|
714
|
-
f"Selected {len(self._telescope_list)} telescopes"
|
|
715
|
-
f" (from originally {_n_telescopes})"
|
|
721
|
+
f"Selected {len(self._telescope_list)} telescopes (from originally {_n_telescopes})"
|
|
716
722
|
)
|
|
717
723
|
except TypeError:
|
|
718
724
|
self._logger.info("No asset list provided, keeping all telescopes")
|
simtools/model/array_model.py
CHANGED
|
@@ -6,8 +6,8 @@ from pathlib import Path
|
|
|
6
6
|
import astropy.units as u
|
|
7
7
|
from astropy.table import QTable
|
|
8
8
|
|
|
9
|
-
from simtools.data_model import data_reader
|
|
10
|
-
from simtools.db import
|
|
9
|
+
from simtools.data_model import data_reader, schema
|
|
10
|
+
from simtools.db import db_handler
|
|
11
11
|
from simtools.io_operations import io_handler
|
|
12
12
|
from simtools.model.site_model import SiteModel
|
|
13
13
|
from simtools.model.telescope_model import TelescopeModel
|
|
@@ -290,7 +290,13 @@ class ArrayModel:
|
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
def _get_telescope_position_parameter(
|
|
293
|
-
self,
|
|
293
|
+
self,
|
|
294
|
+
telescope_name: str,
|
|
295
|
+
site: str,
|
|
296
|
+
x: u.Quantity,
|
|
297
|
+
y: u.Quantity,
|
|
298
|
+
z: u.Quantity,
|
|
299
|
+
parameter_version: str | None = None,
|
|
294
300
|
) -> dict:
|
|
295
301
|
"""
|
|
296
302
|
Return dictionary with telescope position parameters (following DB model database format).
|
|
@@ -314,16 +320,17 @@ class ArrayModel:
|
|
|
314
320
|
Dict with telescope position parameters.
|
|
315
321
|
"""
|
|
316
322
|
return {
|
|
323
|
+
"schema_version": schema.get_model_parameter_schema_version(),
|
|
317
324
|
"parameter": "array_element_position_ground",
|
|
318
325
|
"instrument": telescope_name,
|
|
319
326
|
"site": site,
|
|
320
|
-
"
|
|
327
|
+
"parameter_version": parameter_version,
|
|
328
|
+
"unique_id": None,
|
|
321
329
|
"value": general.convert_list_to_string(
|
|
322
330
|
[x.to("m").value, y.to("m").value, z.to("m").value]
|
|
323
331
|
),
|
|
324
332
|
"unit": "m",
|
|
325
333
|
"type": "float64",
|
|
326
|
-
"applicable": True,
|
|
327
334
|
"file": False,
|
|
328
335
|
}
|
|
329
336
|
|
|
@@ -367,9 +374,8 @@ class ArrayModel:
|
|
|
367
374
|
dict
|
|
368
375
|
Dict with array elements.
|
|
369
376
|
"""
|
|
370
|
-
all_elements =
|
|
377
|
+
all_elements = self.db.get_array_elements_of_type(
|
|
371
378
|
array_element_type=array_element_type,
|
|
372
|
-
db=self.db,
|
|
373
379
|
model_version=self.model_version,
|
|
374
380
|
collection="telescopes",
|
|
375
381
|
)
|