gammasimtools 0.16.0__py3-none-any.whl → 0.18.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.16.0.dist-info → gammasimtools-0.18.0.dist-info}/METADATA +5 -2
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/RECORD +82 -74
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/WHEEL +1 -1
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/entry_points.txt +4 -1
- simtools/_version.py +2 -2
- simtools/applications/db_add_simulation_model_from_repository_to_db.py +10 -1
- simtools/applications/derive_ctao_array_layouts.py +5 -5
- simtools/applications/derive_mirror_rnda.py +1 -1
- simtools/applications/generate_simtel_event_data.py +128 -46
- simtools/applications/merge_tables.py +102 -0
- simtools/applications/plot_array_layout.py +145 -258
- simtools/applications/plot_tabular_data.py +12 -1
- simtools/applications/plot_tabular_data_for_model_parameter.py +103 -0
- simtools/applications/production_derive_corsika_limits.py +78 -225
- simtools/applications/production_derive_statistics.py +77 -43
- simtools/applications/simulate_light_emission.py +1 -0
- simtools/applications/simulate_prod.py +30 -18
- simtools/applications/simulate_prod_htcondor_generator.py +0 -1
- simtools/applications/submit_array_layouts.py +93 -0
- simtools/applications/verify_simulation_model_production_tables.py +52 -0
- simtools/camera/camera_efficiency.py +3 -3
- simtools/configuration/commandline_parser.py +30 -35
- simtools/configuration/configurator.py +0 -4
- simtools/constants.py +2 -0
- simtools/corsika/corsika_config.py +17 -12
- simtools/corsika/primary_particle.py +46 -13
- simtools/data_model/metadata_collector.py +7 -3
- simtools/data_model/schema.py +15 -1
- simtools/db/db_handler.py +16 -11
- simtools/db/db_model_upload.py +2 -2
- simtools/io_operations/io_handler.py +2 -2
- simtools/io_operations/io_table_handler.py +345 -0
- simtools/job_execution/htcondor_script_generator.py +2 -2
- simtools/job_execution/job_manager.py +7 -121
- simtools/layout/array_layout_utils.py +389 -0
- simtools/model/array_model.py +10 -1
- simtools/model/model_repository.py +134 -0
- simtools/production_configuration/{calculate_statistical_errors_grid_point.py → calculate_statistical_uncertainties_grid_point.py} +101 -112
- simtools/production_configuration/derive_corsika_limits.py +239 -111
- simtools/production_configuration/derive_corsika_limits_grid.py +232 -0
- simtools/production_configuration/derive_production_statistics.py +57 -26
- simtools/production_configuration/derive_production_statistics_handler.py +70 -37
- simtools/production_configuration/interpolation_handler.py +296 -94
- simtools/ray_tracing/ray_tracing.py +7 -6
- simtools/reporting/docs_read_parameters.py +104 -62
- simtools/resources/array-element-ids.json +126 -0
- simtools/runners/corsika_simtel_runner.py +4 -1
- simtools/runners/runner_services.py +5 -4
- simtools/schemas/model_parameter_and_data_schema.metaschema.yml +5 -1
- simtools/schemas/model_parameters/atmospheric_profile.schema.yml +41 -0
- simtools/schemas/model_parameters/atmospheric_transmission.schema.yml +43 -0
- simtools/schemas/model_parameters/camera_filter.schema.yml +10 -0
- simtools/schemas/model_parameters/camera_filter_incidence_angle.schema.yml +10 -0
- simtools/schemas/model_parameters/discriminator_pulse_shape.schema.yml +31 -0
- simtools/schemas/model_parameters/dsum_threshold.schema.yml +41 -0
- simtools/schemas/model_parameters/fadc_pulse_shape.schema.yml +12 -0
- simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +10 -0
- simtools/schemas/model_parameters/mirror_reflectivity.schema.yml +10 -0
- simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +12 -0
- simtools/schemas/model_parameters/pm_photoelectron_spectrum.schema.yml +19 -0
- simtools/schemas/model_parameters/quantum_efficiency.schema.yml +10 -0
- simtools/schemas/plot_configuration.metaschema.yml +46 -57
- simtools/schemas/production_configuration_metrics.schema.yml +2 -2
- simtools/simtel/simtel_config_writer.py +34 -14
- simtools/simtel/simtel_io_event_reader.py +301 -194
- simtools/simtel/simtel_io_event_writer.py +237 -221
- simtools/simtel/simtel_io_file_info.py +9 -4
- simtools/simtel/simtel_io_metadata.py +119 -8
- simtools/simtel/simulator_array.py +2 -2
- simtools/simtel/simulator_light_emission.py +79 -34
- simtools/simtel/simulator_ray_tracing.py +2 -2
- simtools/simulator.py +101 -68
- simtools/testing/validate_output.py +4 -1
- simtools/utils/general.py +1 -3
- simtools/utils/names.py +76 -7
- simtools/visualization/plot_array_layout.py +242 -0
- simtools/visualization/plot_pixels.py +680 -0
- simtools/visualization/plot_tables.py +81 -2
- simtools/visualization/visualize.py +3 -219
- simtools/applications/production_generate_simulation_config.py +0 -152
- simtools/layout/ctao_array_layouts.py +0 -172
- simtools/production_configuration/generate_simulation_config.py +0 -158
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/licenses/LICENSE +0 -0
- {gammasimtools-0.16.0.dist-info → gammasimtools-0.18.0.dist-info}/top_level.txt +0 -0
- /simtools/{schemas → resources}/array_elements.yml +0 -0
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
"""Plot array elements for a layout."""
|
|
3
|
+
|
|
4
|
+
from collections import Counter
|
|
5
|
+
|
|
6
|
+
import astropy.units as u
|
|
7
|
+
import matplotlib.patches as mpatches
|
|
8
|
+
import matplotlib.pyplot as plt
|
|
9
|
+
from astropy.table import Column
|
|
10
|
+
from matplotlib.collections import PatchCollection
|
|
11
|
+
|
|
12
|
+
from simtools.utils import geometry as transf
|
|
13
|
+
from simtools.utils import names
|
|
14
|
+
from simtools.visualization import legend_handlers as leg_h
|
|
15
|
+
|
|
16
|
+
__all__ = ["get_telescope_patch", "plot_array_layout"]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def plot_array_layout(
|
|
20
|
+
telescopes,
|
|
21
|
+
show_tel_label=False,
|
|
22
|
+
axes_range=None,
|
|
23
|
+
marker_scaling=1.0,
|
|
24
|
+
background_telescopes=None,
|
|
25
|
+
):
|
|
26
|
+
"""
|
|
27
|
+
Plot telescope array layout.
|
|
28
|
+
|
|
29
|
+
Parameters
|
|
30
|
+
----------
|
|
31
|
+
telescopes : Table
|
|
32
|
+
Telescope data table.
|
|
33
|
+
show_tel_label : bool
|
|
34
|
+
Show telescope labels (default False).
|
|
35
|
+
axes_range : float or None
|
|
36
|
+
Axis range, auto if None.
|
|
37
|
+
marker_scaling : float
|
|
38
|
+
Marker size scale factor.
|
|
39
|
+
background_telescopes : Table or None
|
|
40
|
+
Optional background telescope table.
|
|
41
|
+
|
|
42
|
+
Returns
|
|
43
|
+
-------
|
|
44
|
+
fig : Figure
|
|
45
|
+
Matplotlib figure object.
|
|
46
|
+
"""
|
|
47
|
+
fig, ax = plt.subplots(1)
|
|
48
|
+
|
|
49
|
+
patches, plot_range = get_patches(ax, telescopes, show_tel_label, axes_range, marker_scaling)
|
|
50
|
+
|
|
51
|
+
if background_telescopes is not None:
|
|
52
|
+
bg_patches, bg_range = get_patches(
|
|
53
|
+
ax, background_telescopes, False, axes_range, marker_scaling
|
|
54
|
+
)
|
|
55
|
+
ax.add_collection(PatchCollection(bg_patches, match_original=True, alpha=0.1))
|
|
56
|
+
if axes_range is None:
|
|
57
|
+
plot_range = max(plot_range, bg_range)
|
|
58
|
+
|
|
59
|
+
update_legend(ax, telescopes)
|
|
60
|
+
finalize_plot(ax, patches, "Easting [m]", "Northing [m]", plot_range)
|
|
61
|
+
|
|
62
|
+
return fig
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def get_patches(ax, telescopes, show_tel_label, axes_range, marker_scaling):
|
|
66
|
+
"""
|
|
67
|
+
Get plot patches and axis range.
|
|
68
|
+
|
|
69
|
+
Returns
|
|
70
|
+
-------
|
|
71
|
+
patches : list
|
|
72
|
+
List of telescope patches.
|
|
73
|
+
axes_range : float
|
|
74
|
+
Calculated or input axis range.
|
|
75
|
+
"""
|
|
76
|
+
pos_x, pos_y = get_positions(telescopes)
|
|
77
|
+
telescopes["pos_x_rotated"] = Column(pos_x)
|
|
78
|
+
telescopes["pos_y_rotated"] = Column(pos_y)
|
|
79
|
+
|
|
80
|
+
patches, radii = create_patches(telescopes, marker_scaling, show_tel_label, ax)
|
|
81
|
+
|
|
82
|
+
if axes_range:
|
|
83
|
+
return patches, axes_range
|
|
84
|
+
|
|
85
|
+
r = max(radii).value
|
|
86
|
+
max_x = max(abs(pos_x.min().value), abs(pos_x.max().value)) + r
|
|
87
|
+
max_y = max(abs(pos_y.min().value), abs(pos_y.max().value)) + r
|
|
88
|
+
updated_axes_range = max(max_x, max_y) * 1.1
|
|
89
|
+
|
|
90
|
+
return patches, updated_axes_range
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@u.quantity_input(x=u.m, y=u.m, radius=u.m)
|
|
94
|
+
def get_telescope_patch(name, x, y, radius):
|
|
95
|
+
"""
|
|
96
|
+
Create patch for a telescope.
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
patch : Patch
|
|
101
|
+
Circle or rectangle patch.
|
|
102
|
+
"""
|
|
103
|
+
tel_obj = leg_h.TelescopeHandler()
|
|
104
|
+
tel_type = names.get_array_element_type_from_name(name)
|
|
105
|
+
x, y, r = x.to(u.m), y.to(u.m), radius.to(u.m)
|
|
106
|
+
|
|
107
|
+
if tel_type == "SCTS":
|
|
108
|
+
return mpatches.Rectangle(
|
|
109
|
+
((x - r / 2).value, (y - r / 2).value),
|
|
110
|
+
width=r.value,
|
|
111
|
+
height=r.value,
|
|
112
|
+
fill=False,
|
|
113
|
+
color=tel_obj.colors_dict[tel_type],
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
return mpatches.Circle(
|
|
117
|
+
(x.value, y.value),
|
|
118
|
+
radius=r.value,
|
|
119
|
+
fill=tel_type.startswith("MST"),
|
|
120
|
+
color=tel_obj.colors_dict[tel_type],
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def get_positions(telescopes):
|
|
125
|
+
"""
|
|
126
|
+
Get X/Y positions depending on coordinate system.
|
|
127
|
+
|
|
128
|
+
For ground coordinates, rotates the positions by 90 degrees.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
x_rot, y_rot : Quantity
|
|
133
|
+
Position coordinates.
|
|
134
|
+
"""
|
|
135
|
+
if "position_x" in telescopes.colnames:
|
|
136
|
+
x, y = telescopes["position_x"], telescopes["position_y"]
|
|
137
|
+
locale_rotate_angle = 90 * u.deg
|
|
138
|
+
elif "utm_east" in telescopes.colnames:
|
|
139
|
+
x, y = telescopes["utm_east"], telescopes["utm_north"]
|
|
140
|
+
locale_rotate_angle = 0 * u.deg
|
|
141
|
+
else:
|
|
142
|
+
raise ValueError("Missing required position columns.")
|
|
143
|
+
|
|
144
|
+
return transf.rotate(x, y, locale_rotate_angle) if locale_rotate_angle != 0 else (x, y)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def create_patches(telescopes, scale, show_label, ax):
|
|
148
|
+
"""
|
|
149
|
+
Create telescope patches and labels.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
patches : list
|
|
154
|
+
Shape patches.
|
|
155
|
+
radii : list
|
|
156
|
+
Telescope radii.
|
|
157
|
+
"""
|
|
158
|
+
patches, radii = [], []
|
|
159
|
+
fontsize, scale_factor = (4, 2) if len(telescopes) > 30 else (8, 1)
|
|
160
|
+
|
|
161
|
+
for tel in telescopes:
|
|
162
|
+
name = get_telescope_name(tel)
|
|
163
|
+
radius = get_sphere_radius(tel)
|
|
164
|
+
radii.append(radius)
|
|
165
|
+
tel_type = names.get_array_element_type_from_name(name)
|
|
166
|
+
|
|
167
|
+
patches.append(
|
|
168
|
+
get_telescope_patch(
|
|
169
|
+
tel_type,
|
|
170
|
+
tel["pos_x_rotated"],
|
|
171
|
+
tel["pos_y_rotated"],
|
|
172
|
+
scale_factor * radius * scale,
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
if show_label:
|
|
177
|
+
ax.text(
|
|
178
|
+
tel["pos_x_rotated"].value,
|
|
179
|
+
tel["pos_y_rotated"].value + scale_factor * radius.value,
|
|
180
|
+
name,
|
|
181
|
+
ha="center",
|
|
182
|
+
va="bottom",
|
|
183
|
+
fontsize=fontsize,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
return patches, radii
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def get_telescope_name(tel):
|
|
190
|
+
"""
|
|
191
|
+
Get telescope name.
|
|
192
|
+
|
|
193
|
+
Returns
|
|
194
|
+
-------
|
|
195
|
+
name : str
|
|
196
|
+
Telescope name or fallback identifier.
|
|
197
|
+
"""
|
|
198
|
+
if "telescope_name" in tel.colnames:
|
|
199
|
+
return tel["telescope_name"]
|
|
200
|
+
if "asset_code" in tel.colnames and "sequence_number" in tel.colnames:
|
|
201
|
+
return f"{tel['asset_code']}-{tel['sequence_number']}"
|
|
202
|
+
return f"tel_{tel.index}"
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def get_sphere_radius(tel):
|
|
206
|
+
"""
|
|
207
|
+
Get telescope sphere radius.
|
|
208
|
+
|
|
209
|
+
Returns
|
|
210
|
+
-------
|
|
211
|
+
radius : Quantity
|
|
212
|
+
Radius with units.
|
|
213
|
+
"""
|
|
214
|
+
return tel["sphere_radius"] if "sphere_radius" in tel.colnames else 10.0 * u.m
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def update_legend(ax, telescopes):
|
|
218
|
+
"""Add legend for telescope types and counts."""
|
|
219
|
+
names_list = [get_telescope_name(tel) for tel in telescopes]
|
|
220
|
+
types = [names.get_array_element_type_from_name(n) for n in names_list]
|
|
221
|
+
counts = Counter(types)
|
|
222
|
+
|
|
223
|
+
objs, labels = [], []
|
|
224
|
+
for t in names.get_list_of_array_element_types():
|
|
225
|
+
if counts[t]:
|
|
226
|
+
objs.append(leg_h.all_telescope_objects[t]())
|
|
227
|
+
labels.append(f"{t} ({counts[t]})")
|
|
228
|
+
|
|
229
|
+
handler_map = {k: v() for k, v in leg_h.legend_handler_map.items()}
|
|
230
|
+
ax.legend(objs, labels, handler_map=handler_map, prop={"size": 11}, loc="best")
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def finalize_plot(ax, patches, x_title, y_title, axes_range):
|
|
234
|
+
"""Finalize plot appearance and limits."""
|
|
235
|
+
ax.add_collection(PatchCollection(patches, match_original=True))
|
|
236
|
+
ax.set(xlabel=x_title, ylabel=y_title)
|
|
237
|
+
ax.tick_params(labelsize=8)
|
|
238
|
+
ax.axis("square")
|
|
239
|
+
if axes_range:
|
|
240
|
+
ax.set_xlim(-axes_range, axes_range)
|
|
241
|
+
ax.set_ylim(-axes_range, axes_range)
|
|
242
|
+
plt.tight_layout()
|