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.
Files changed (83) hide show
  1. {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/METADATA +1 -1
  2. {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/RECORD +66 -79
  3. {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/entry_points.txt +2 -1
  5. simtools/_version.py +2 -2
  6. simtools/applications/convert_all_model_parameters_from_simtel.py +77 -88
  7. simtools/applications/convert_geo_coordinates_of_array_elements.py +1 -1
  8. simtools/applications/db_get_parameter_from_db.py +52 -22
  9. simtools/applications/derive_photon_electron_spectrum.py +1 -1
  10. simtools/applications/docs_produce_array_element_report.py +1 -10
  11. simtools/applications/docs_produce_model_parameter_reports.py +4 -17
  12. simtools/applications/plot_tabular_data.py +14 -2
  13. simtools/applications/{production_derive_limits.py → production_derive_corsika_limits.py} +20 -8
  14. simtools/applications/production_extract_mc_event_data.py +125 -0
  15. simtools/applications/run_application.py +9 -10
  16. simtools/applications/submit_data_from_external.py +1 -1
  17. simtools/applications/submit_model_parameter_from_external.py +2 -1
  18. simtools/camera/single_photon_electron_spectrum.py +6 -2
  19. simtools/configuration/commandline_parser.py +1 -1
  20. simtools/constants.py +7 -0
  21. simtools/data_model/metadata_collector.py +159 -61
  22. simtools/data_model/model_data_writer.py +11 -55
  23. simtools/data_model/schema.py +2 -1
  24. simtools/data_model/validate_data.py +5 -3
  25. simtools/db/db_handler.py +119 -33
  26. simtools/model/model_parameter.py +0 -31
  27. simtools/production_configuration/derive_corsika_limits.py +260 -0
  28. simtools/production_configuration/extract_mc_event_data.py +253 -0
  29. simtools/ray_tracing/mirror_panel_psf.py +1 -1
  30. simtools/reporting/docs_read_parameters.py +164 -91
  31. simtools/schemas/metadata.metaschema.yml +7 -6
  32. simtools/schemas/model_parameter.metaschema.yml +0 -4
  33. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +13 -5
  34. simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
  35. simtools/schemas/model_parameters/array_layouts.schema.yml +3 -0
  36. simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
  37. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +1 -1
  38. simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
  39. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
  40. simtools/schemas/model_parameters/camera_filter.schema.yml +1 -1
  41. simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
  42. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
  43. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
  44. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +3 -3
  45. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +3 -3
  46. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  47. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
  48. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +1 -1
  49. simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
  50. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
  51. simtools/schemas/model_parameters/nsb_skymap.schema.yml +1 -1
  52. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +1 -1
  53. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
  54. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
  55. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
  56. simtools/schemas/plot_configuration.metaschema.yml +162 -0
  57. simtools/schemas/production_tables.schema.yml +1 -1
  58. simtools/simtel/simtel_config_reader.py +85 -34
  59. simtools/simtel/simtel_table_reader.py +4 -0
  60. simtools/utils/general.py +50 -9
  61. simtools/utils/names.py +7 -2
  62. simtools/utils/value_conversion.py +6 -4
  63. simtools/visualization/plot_tables.py +25 -20
  64. simtools/visualization/visualize.py +71 -23
  65. simtools/_dev_version/__init__.py +0 -9
  66. simtools/applications/__init__.py +0 -0
  67. simtools/configuration/__init__.py +0 -0
  68. simtools/corsika/__init__.py +0 -0
  69. simtools/data_model/__init__.py +0 -0
  70. simtools/db/__init__.py +0 -0
  71. simtools/io_operations/__init__.py +0 -0
  72. simtools/job_execution/__init__.py +0 -0
  73. simtools/layout/__init__.py +0 -0
  74. simtools/model/__init__.py +0 -0
  75. simtools/production_configuration/limits_calculation.py +0 -202
  76. simtools/ray_tracing/__init__.py +0 -0
  77. simtools/runners/__init__.py +0 -0
  78. simtools/simtel/__init__.py +0 -0
  79. simtools/testing/__init__.py +0 -0
  80. simtools/utils/__init__.py +0 -0
  81. simtools/visualization/__init__.py +0 -0
  82. {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/LICENSE +0 -0
  83. {gammasimtools-0.11.0.dist-info → gammasimtools-0.13.0.dist-info}/top_level.txt +0 -0
@@ -144,22 +144,23 @@ def _add_unit(title, array):
144
144
  str
145
145
  Title with units.
146
146
  """
147
- unit = ""
148
- if isinstance(array, u.Quantity):
149
- unit = str(array[0].unit)
150
- if len(unit) > 0:
151
- unit = f" [{unit}]"
152
- if re.search(r"\d", unit):
153
- unit = re.sub(r"(\d)", r"^\1", unit)
154
- unit = unit.replace("[", r"$[").replace("]", r"]$")
155
- if "[" in title and "]" in title:
156
- _logger.warning(
157
- "Tried to add a unit from astropy.unit, "
158
- "but axis already has an explicit unit. Left axis title as is."
159
- )
160
- unit = ""
147
+ if title and "[" in title and "]" in title:
148
+ _logger.warning(
149
+ "Tried to add a unit from astropy.unit, "
150
+ "but axis already has an explicit unit. Left axis title as is."
151
+ )
152
+ return title
153
+
154
+ if not isinstance(array, u.Quantity) or not str(array[0].unit):
155
+ return title
161
156
 
162
- return f"{title}{unit}"
157
+ unit = str(array[0].unit)
158
+ unit_str = f" [{unit}]"
159
+ if re.search(r"\d", unit_str):
160
+ unit_str = re.sub(r"(\d)", r"^\1", unit_str)
161
+ unit_str = unit_str.replace("[", r"[$").replace("]", r"$]")
162
+
163
+ return f"{title}{unit_str}"
163
164
 
164
165
 
165
166
  def set_style(palette="default", big_plot=False):
@@ -418,27 +419,74 @@ def setup_plot(kwargs, plot_ratio, plot_difference):
418
419
  return fig, ax1, gs
419
420
 
420
421
 
422
+ def _plot_error_plots(kwargs, data_now, x_col, y_col, x_err_col, y_err_col, color):
423
+ """Plot error plots."""
424
+ if kwargs.get("error_type") == "fill_between" and y_err_col:
425
+ plt.fill_between(
426
+ data_now[x_col],
427
+ data_now[y_col] - data_now[y_err_col],
428
+ data_now[y_col] + data_now[y_err_col],
429
+ alpha=0.2,
430
+ color=color,
431
+ )
432
+
433
+ if kwargs.get("error_type") == "errorbar" and (x_err_col or y_err_col):
434
+ plt.errorbar(
435
+ data_now[x_col],
436
+ data_now[y_col],
437
+ xerr=data_now[x_err_col] if x_err_col else None,
438
+ yerr=data_now[y_err_col] if y_err_col else None,
439
+ fmt=".",
440
+ color=color,
441
+ )
442
+
443
+
444
+ def _get_data_columns(data_now):
445
+ """Return data columns depending on availability."""
446
+ columns = data_now.dtype.names
447
+ assert len(columns) >= 2, "Input array must have at least two columns with titles."
448
+ x_col, y_col = columns[:2]
449
+ if len(columns) == 3:
450
+ x_err_col = None
451
+ y_err_col = columns[2]
452
+ elif len(columns) == 4:
453
+ x_err_col = columns[2]
454
+ y_err_col = columns[3]
455
+ else:
456
+ x_err_col = None
457
+ y_err_col = None
458
+ return x_col, y_col, x_err_col, y_err_col
459
+
460
+
421
461
  def plot_main_data(data_dict, kwargs, plot_args):
422
462
  """Plot the main data."""
423
463
  for label, data_now in data_dict.items():
424
- assert len(data_now.dtype.names) == 2, "Input array must have two columns with titles."
425
- x_column_name, y_column_name = data_now.dtype.names[0], data_now.dtype.names[1]
426
- x_title = kwargs["xtitle"] if kwargs.get("xtitle") else x_column_name
427
- y_title = kwargs["ytitle"] if kwargs.get("ytitle") else y_column_name
428
- x_title_unit = _add_unit(x_title, data_now[x_column_name])
429
- y_title_unit = _add_unit(y_title, data_now[y_column_name])
430
- plt.plot(data_now[x_column_name], data_now[y_column_name], label=label, **plot_args)
464
+ x_col, y_col, x_err_col, y_err_col = _get_data_columns(data_now)
465
+
466
+ x_title = kwargs.get("xtitle", x_col)
467
+ y_title = kwargs.get("ytitle", y_col)
468
+
469
+ x_title_unit = _add_unit(x_title, data_now[x_col])
470
+ y_title_unit = _add_unit(y_title, data_now[y_col])
471
+
472
+ (line,) = plt.plot(data_now[x_col], data_now[y_col], label=label, **plot_args)
473
+ color = line.get_color()
474
+
475
+ _plot_error_plots(kwargs, data_now, x_col, y_col, x_err_col, y_err_col, color)
431
476
 
432
477
  plt.xscale(kwargs["xscale"])
433
478
  plt.yscale(kwargs["yscale"])
434
479
  plt.xlim(kwargs["xlim"])
435
480
  plt.ylim(kwargs["ylim"])
436
481
  plt.ylabel(y_title_unit)
482
+
437
483
  if not (kwargs["plot_ratio"] or kwargs["plot_difference"]):
438
484
  plt.xlabel(x_title_unit)
485
+
439
486
  if kwargs["title"]:
440
487
  plt.title(kwargs["title"], y=1.02)
441
- if "_default" not in list(data_dict.keys()) and not kwargs["no_legend"]:
488
+
489
+ if "_default" not in data_dict and not kwargs["no_legend"]:
442
490
  plt.legend()
443
491
 
444
492
 
@@ -1,9 +0,0 @@
1
- # Try to use setuptools_scm to get the current version; this is only used
2
- # in development installations from the git repository.
3
- # see src/simtools/version.py for details
4
- try:
5
- from setuptools_scm import get_version
6
-
7
- version = get_version(root="../../..", relative_to=__file__)
8
- except Exception as e:
9
- raise ImportError(f"setuptools_scm broken or not installed: {e}")
File without changes
File without changes
File without changes
File without changes
simtools/db/__init__.py DELETED
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -1,202 +0,0 @@
1
- """Calculate the thresholds for energy, radial distance, and viewcone."""
2
-
3
- import astropy.units as u
4
- import numpy as np
5
-
6
-
7
- class LimitCalculator:
8
- """
9
- Compute thresholds/limits for energy, radial distance, and viewcone.
10
-
11
- Histograms are generated with simtools-generate-simtel-array-histograms with --hdf5 flag.
12
-
13
- Event data is read from the generated HDF5 file from the following tables:
14
- - angle_to_observing_position__triggered_showers_ for the viewcone limit.
15
- - event_weight__ra3d__log10_e__ for the energy and radial distance limit.
16
-
17
-
18
- Parameters
19
- ----------
20
- event_data_file : list of astropy.table.Table
21
- The list of tables containing the event data.
22
- """
23
-
24
- def __init__(self, event_data_file_tables):
25
- """
26
- Initialize the LimitCalculator with the given event data file.
27
-
28
- Parameters
29
- ----------
30
- event_data_file : list of astropy.table.Table
31
- The list of tables containing the event data.
32
- """
33
- self.angle_to_observing_position__triggered_showers_ = None
34
- self.event_weight__ra3d__log10_e__ = None
35
-
36
- for table in event_data_file_tables:
37
- if (
38
- "Title" in table.meta
39
- and table.meta["Title"] == "angle_to_observing_position__triggered_showers_"
40
- ):
41
- self.angle_to_observing_position__triggered_showers_ = table
42
- elif "Title" in table.meta and table.meta["Title"] == "event_weight__ra3d__log10_e__":
43
- self.event_weight__ra3d__log10_e__ = table
44
-
45
- def _compute_limits(
46
- self, event_weight_array, bin_edges, loss_fraction, axis=0, limit_type="lower"
47
- ):
48
- """
49
- Compute the limits based on the loss fraction.
50
-
51
- Parameters
52
- ----------
53
- event_weight_array : np.ndarray
54
- Array of event weights.
55
- bin_edges : np.ndarray
56
- Array of bin edges.
57
- loss_fraction : float
58
- Fraction of events to be lost.
59
- axis : int, optional
60
- Axis along which to sum the event weights. Default is 0.
61
- limit_type : str, optional
62
- Type of limit ('lower' or 'upper'). Default is 'lower'.
63
-
64
- Returns
65
- -------
66
- int
67
- Bin index where the threshold is reached.
68
- float
69
- Bin edge value corresponding to the threshold.
70
- """
71
- projection = np.sum(event_weight_array, axis=axis)
72
- bin_edge_value = None
73
- cumulative_sum = None
74
- if limit_type == "upper":
75
- cumulative_sum = np.cumsum(projection)
76
-
77
- elif limit_type == "lower":
78
- cumulative_sum = np.cumsum(projection[::-1])
79
-
80
- total_events = np.sum(projection)
81
- threshold = (1 - loss_fraction) * total_events
82
- bin_index = np.searchsorted(cumulative_sum, threshold)
83
- if limit_type == "upper":
84
- bin_edge_value = bin_edges[bin_index]
85
- elif limit_type == "lower":
86
- bin_edge_value = bin_edges[-bin_index]
87
- return bin_index, bin_edge_value
88
-
89
- def get_bin_edges_and_units(self, table, axis="x"):
90
- """
91
- Extract bin edges and units from the table metadata.
92
-
93
- Parameters
94
- ----------
95
- table : astropy.table.Table
96
- Table containing the event data.
97
-
98
- Returns
99
- -------
100
- tuple
101
- Tuple containing the bin edges and their units.
102
- """
103
- bin_edges = table.meta[f"{axis}_bin_edges"]
104
- try:
105
- bin_edges_unit = table.meta[f"{axis}_bin_edges_unit"]
106
- except KeyError:
107
- bin_edges_unit = ""
108
- return bin_edges, bin_edges_unit
109
-
110
- def compute_lower_energy_limit(self, loss_fraction):
111
- """
112
- Compute the lower energy limit in TeV based on the event loss fraction.
113
-
114
- Parameters
115
- ----------
116
- loss_fraction : float
117
- Fraction of events to be lost.
118
-
119
- Returns
120
- -------
121
- astropy.units.Quantity
122
- Lower energy limit.
123
- """
124
- event_weight_array = np.column_stack(
125
- [
126
- self.event_weight__ra3d__log10_e__[name]
127
- for name in self.event_weight__ra3d__log10_e__.dtype.names
128
- ]
129
- )
130
- bin_edges, bin_edges_unit = self.get_bin_edges_and_units(
131
- self.event_weight__ra3d__log10_e__, axis="y"
132
- )
133
- if bin_edges_unit == "":
134
- bin_edges_unit = "TeV"
135
- _, lower_bin_edge_value = self._compute_limits(
136
- event_weight_array, bin_edges, loss_fraction, axis=0, limit_type="lower"
137
- )
138
- return (10**lower_bin_edge_value) * u.Unit(bin_edges_unit)
139
-
140
- def compute_upper_radial_distance(self, loss_fraction):
141
- """
142
- Compute the upper radial distance based on the event loss fraction.
143
-
144
- Parameters
145
- ----------
146
- loss_fraction : float
147
- Fraction of events to be lost.
148
-
149
- Returns
150
- -------
151
- astropy.units.Quantity
152
- Upper radial distance in m.
153
- """
154
- event_weight_array = np.column_stack(
155
- [
156
- self.event_weight__ra3d__log10_e__[name]
157
- for name in self.event_weight__ra3d__log10_e__.dtype.names
158
- ]
159
- )
160
- bin_edges, bin_edges_unit = self.get_bin_edges_and_units(
161
- self.event_weight__ra3d__log10_e__, axis="x"
162
- )
163
- if bin_edges_unit == "":
164
- bin_edges_unit = "m"
165
- _, upper_bin_edge_value = self._compute_limits(
166
- event_weight_array, bin_edges, loss_fraction, axis=1, limit_type="upper"
167
- )
168
- return upper_bin_edge_value * u.Unit(bin_edges_unit)
169
-
170
- def compute_viewcone(self, loss_fraction):
171
- """
172
- Compute the viewcone based on the event loss fraction.
173
-
174
- Parameters
175
- ----------
176
- loss_fraction : float
177
- Fraction of events to be lost.
178
-
179
- Returns
180
- -------
181
- astropy.units.Quantity
182
- Viewcone radius in degrees.
183
- """
184
- angle_to_observing_position__triggered_showers = np.column_stack(
185
- [
186
- self.angle_to_observing_position__triggered_showers_[name]
187
- for name in self.angle_to_observing_position__triggered_showers_.dtype.names
188
- ]
189
- )
190
- bin_edges, bin_edges_unit = self.get_bin_edges_and_units(
191
- self.angle_to_observing_position__triggered_showers_, axis="x"
192
- )
193
- if bin_edges_unit == "":
194
- bin_edges_unit = "deg"
195
- _, upper_bin_edge_value = self._compute_limits(
196
- angle_to_observing_position__triggered_showers,
197
- bin_edges,
198
- loss_fraction,
199
- axis=0,
200
- limit_type="upper",
201
- )
202
- return upper_bin_edge_value * u.Unit(bin_edges_unit)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes