gammasimtools 0.12.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 (81) hide show
  1. {gammasimtools-0.12.0.dist-info → gammasimtools-0.13.0.dist-info}/METADATA +1 -1
  2. {gammasimtools-0.12.0.dist-info → gammasimtools-0.13.0.dist-info}/RECORD +64 -77
  3. {gammasimtools-0.12.0.dist-info → gammasimtools-0.13.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.12.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/constants.py +7 -0
  20. simtools/data_model/metadata_collector.py +159 -61
  21. simtools/data_model/model_data_writer.py +11 -55
  22. simtools/data_model/schema.py +2 -1
  23. simtools/data_model/validate_data.py +5 -3
  24. simtools/db/db_handler.py +115 -31
  25. simtools/model/model_parameter.py +0 -31
  26. simtools/production_configuration/derive_corsika_limits.py +260 -0
  27. simtools/production_configuration/extract_mc_event_data.py +253 -0
  28. simtools/ray_tracing/mirror_panel_psf.py +1 -1
  29. simtools/reporting/docs_read_parameters.py +164 -91
  30. simtools/schemas/metadata.metaschema.yml +7 -6
  31. simtools/schemas/model_parameter.metaschema.yml +0 -4
  32. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +13 -5
  33. simtools/schemas/model_parameters/array_coordinates.schema.yml +1 -1
  34. simtools/schemas/model_parameters/array_layouts.schema.yml +3 -0
  35. simtools/schemas/model_parameters/asum_shaping.schema.yml +1 -1
  36. simtools/schemas/model_parameters/atmospheric_profile.schema.yml +1 -1
  37. simtools/schemas/model_parameters/camera_config_file.schema.yml +1 -1
  38. simtools/schemas/model_parameters/camera_degraded_map.schema.yml +1 -1
  39. simtools/schemas/model_parameters/camera_filter.schema.yml +1 -1
  40. simtools/schemas/model_parameters/dsum_shaping.schema.yml +1 -1
  41. simtools/schemas/model_parameters/fadc_dev_pedestal.schema.yml +1 -1
  42. simtools/schemas/model_parameters/fadc_lg_dev_pedestal.schema.yml +1 -1
  43. simtools/schemas/model_parameters/fadc_lg_max_sum.schema.yml +3 -3
  44. simtools/schemas/model_parameters/fadc_max_sum.schema.yml +3 -3
  45. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +1 -1
  46. simtools/schemas/model_parameters/lightguide_efficiency_vs_incidence_angle.schema.yml +1 -1
  47. simtools/schemas/model_parameters/lightguide_efficiency_vs_wavelength.schema.yml +1 -1
  48. simtools/schemas/model_parameters/mirror_list.schema.yml +1 -1
  49. simtools/schemas/model_parameters/nsb_reference_spectrum.schema.yml +1 -1
  50. simtools/schemas/model_parameters/nsb_skymap.schema.yml +1 -1
  51. simtools/schemas/model_parameters/primary_mirror_degraded_map.schema.yml +1 -1
  52. simtools/schemas/model_parameters/primary_mirror_segmentation.schema.yml +1 -1
  53. simtools/schemas/model_parameters/secondary_mirror_degraded_map.schema.yml +1 -1
  54. simtools/schemas/model_parameters/secondary_mirror_segmentation.schema.yml +1 -1
  55. simtools/schemas/plot_configuration.metaschema.yml +162 -0
  56. simtools/schemas/production_tables.schema.yml +1 -1
  57. simtools/simtel/simtel_config_reader.py +85 -34
  58. simtools/simtel/simtel_table_reader.py +4 -0
  59. simtools/utils/general.py +50 -9
  60. simtools/utils/names.py +7 -2
  61. simtools/visualization/plot_tables.py +25 -20
  62. simtools/visualization/visualize.py +71 -23
  63. simtools/_dev_version/__init__.py +0 -9
  64. simtools/applications/__init__.py +0 -0
  65. simtools/configuration/__init__.py +0 -0
  66. simtools/corsika/__init__.py +0 -0
  67. simtools/data_model/__init__.py +0 -0
  68. simtools/db/__init__.py +0 -0
  69. simtools/io_operations/__init__.py +0 -0
  70. simtools/job_execution/__init__.py +0 -0
  71. simtools/layout/__init__.py +0 -0
  72. simtools/model/__init__.py +0 -0
  73. simtools/production_configuration/limits_calculation.py +0 -202
  74. simtools/ray_tracing/__init__.py +0 -0
  75. simtools/runners/__init__.py +0 -0
  76. simtools/simtel/__init__.py +0 -0
  77. simtools/testing/__init__.py +0 -0
  78. simtools/utils/__init__.py +0 -0
  79. simtools/visualization/__init__.py +0 -0
  80. {gammasimtools-0.12.0.dist-info → gammasimtools-0.13.0.dist-info}/LICENSE +0 -0
  81. {gammasimtools-0.12.0.dist-info → gammasimtools-0.13.0.dist-info}/top_level.txt +0 -0
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 np.issubdtype(dtype, np.bool_) and reference_dtype in ("boolean", "bool"):
700
- return True
728
+ if reference_dtype in ("boolean", "bool"):
729
+ return _is_valid_boolean_type(dtype, value)
701
730
 
702
- if np.issubdtype(dtype, np.integer) and (
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
- if np.issubdtype(dtype, np.floating) and np.issubdtype(reference_dtype, np.floating):
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
- return _validate_name(array_element_name.split("-")[0], array_elements())
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:
@@ -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
- table = legacy_data_handler.read_legacy_data_as_table(
54
- _config["file_name"], _config["type"]
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, [_config["column_x"], _config["column_y"]]
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
- if "telescope" in table_config:
89
- model = TelescopeModel(
90
- site=table_config["site"],
91
- telescope_name=table_config["telescope"],
92
- model_version=table_config["model_version"],
93
- mongo_db_config=db_config,
94
- )
95
- else:
96
- model = SiteModel(
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):
@@ -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