gammasimtools 0.22.0__py3-none-any.whl → 0.23.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 (114) hide show
  1. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/METADATA +2 -1
  2. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/RECORD +114 -112
  3. simtools/_version.py +2 -2
  4. simtools/application_control.py +118 -0
  5. simtools/applications/calculate_incident_angles.py +17 -22
  6. simtools/applications/convert_all_model_parameters_from_simtel.py +28 -43
  7. simtools/applications/convert_geo_coordinates_of_array_elements.py +26 -45
  8. simtools/applications/convert_model_parameter_from_simtel.py +21 -41
  9. simtools/applications/db_add_file_to_db.py +12 -13
  10. simtools/applications/db_add_simulation_model_from_repository_to_db.py +20 -33
  11. simtools/applications/db_add_value_from_json_to_db.py +28 -23
  12. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +19 -34
  13. simtools/applications/db_generate_compound_indexes.py +11 -13
  14. simtools/applications/db_get_array_layouts_from_db.py +19 -39
  15. simtools/applications/db_get_file_from_db.py +15 -17
  16. simtools/applications/db_get_parameter_from_db.py +33 -35
  17. simtools/applications/db_inspect_databases.py +10 -11
  18. simtools/applications/db_upload_model_repository.py +13 -31
  19. simtools/applications/derive_ctao_array_layouts.py +16 -21
  20. simtools/applications/derive_mirror_rnda.py +9 -14
  21. simtools/applications/derive_photon_electron_spectrum.py +7 -10
  22. simtools/applications/derive_psf_parameters.py +13 -20
  23. simtools/applications/derive_trigger_rates.py +6 -9
  24. simtools/applications/docs_produce_array_element_report.py +22 -23
  25. simtools/applications/docs_produce_calibration_reports.py +26 -24
  26. simtools/applications/docs_produce_model_parameter_reports.py +15 -22
  27. simtools/applications/docs_produce_simulation_configuration_report.py +21 -22
  28. simtools/applications/generate_array_config.py +14 -33
  29. simtools/applications/generate_corsika_histograms.py +22 -43
  30. simtools/applications/generate_default_metadata.py +15 -36
  31. simtools/applications/generate_regular_arrays.py +11 -15
  32. simtools/applications/generate_simtel_event_data.py +23 -33
  33. simtools/applications/maintain_simulation_model_add_production.py +12 -19
  34. simtools/applications/maintain_simulation_model_compare_productions.py +10 -12
  35. simtools/applications/maintain_simulation_model_verify_production_tables.py +8 -11
  36. simtools/applications/merge_tables.py +14 -23
  37. simtools/applications/plot_array_layout.py +77 -54
  38. simtools/applications/plot_simtel_events.py +11 -13
  39. simtools/applications/plot_tabular_data.py +17 -38
  40. simtools/applications/plot_tabular_data_for_model_parameter.py +16 -23
  41. simtools/applications/print_version.py +14 -42
  42. simtools/applications/production_derive_corsika_limits.py +5 -9
  43. simtools/applications/production_derive_statistics.py +12 -25
  44. simtools/applications/production_generate_grid.py +20 -48
  45. simtools/applications/production_merge_corsika_limits.py +17 -21
  46. simtools/applications/run_application.py +12 -32
  47. simtools/applications/simulate_flasher.py +21 -25
  48. simtools/applications/simulate_illuminator.py +7 -14
  49. simtools/applications/simulate_pedestals.py +13 -13
  50. simtools/applications/simulate_prod.py +21 -33
  51. simtools/applications/simulate_prod_htcondor_generator.py +11 -25
  52. simtools/applications/submit_array_layouts.py +15 -18
  53. simtools/applications/submit_data_from_external.py +18 -34
  54. simtools/applications/submit_model_parameter_from_external.py +27 -40
  55. simtools/applications/validate_camera_efficiency.py +23 -21
  56. simtools/applications/validate_camera_fov.py +21 -26
  57. simtools/applications/validate_cumulative_psf.py +27 -35
  58. simtools/applications/validate_file_using_schema.py +15 -33
  59. simtools/applications/validate_optics.py +26 -32
  60. simtools/camera/camera_efficiency.py +0 -2
  61. simtools/configuration/commandline_parser.py +32 -4
  62. simtools/configuration/configurator.py +0 -5
  63. simtools/corsika/corsika_config.py +0 -5
  64. simtools/data_model/data_reader.py +0 -2
  65. simtools/data_model/metadata_collector.py +0 -2
  66. simtools/data_model/model_data_writer.py +0 -2
  67. simtools/data_model/validate_data.py +0 -2
  68. simtools/db/db_handler.py +0 -2
  69. simtools/io/hdf5_handler.py +0 -5
  70. simtools/io/legacy_data_handler.py +0 -5
  71. simtools/job_execution/job_manager.py +0 -3
  72. simtools/layout/array_layout.py +0 -2
  73. simtools/layout/telescope_position.py +0 -2
  74. simtools/model/array_model.py +2 -4
  75. simtools/model/calibration_model.py +0 -2
  76. simtools/model/camera.py +0 -2
  77. simtools/model/mirrors.py +0 -2
  78. simtools/model/model_parameter.py +30 -7
  79. simtools/model/model_utils.py +0 -5
  80. simtools/model/site_model.py +0 -2
  81. simtools/model/telescope_model.py +0 -2
  82. simtools/production_configuration/calculate_statistical_uncertainties_grid_point.py +0 -2
  83. simtools/production_configuration/derive_production_statistics.py +0 -2
  84. simtools/production_configuration/interpolation_handler.py +0 -2
  85. simtools/ray_tracing/psf_analysis.py +0 -2
  86. simtools/ray_tracing/ray_tracing.py +0 -2
  87. simtools/reporting/docs_auto_report_generator.py +108 -0
  88. simtools/reporting/docs_read_parameters.py +1 -7
  89. simtools/runners/corsika_runner.py +0 -2
  90. simtools/runners/corsika_simtel_runner.py +0 -2
  91. simtools/runners/simtel_runner.py +0 -2
  92. simtools/schemas/model_parameters/transit_time_random.schema.yml +29 -0
  93. simtools/simtel/simtel_config_reader.py +0 -2
  94. simtools/simtel/simtel_config_writer.py +31 -13
  95. simtools/simtel/simtel_io_metadata.py +3 -3
  96. simtools/simtel/simulator_array.py +9 -21
  97. simtools/simtel/simulator_camera_efficiency.py +0 -2
  98. simtools/simtel/simulator_light_emission.py +1 -3
  99. simtools/simtel/simulator_ray_tracing.py +0 -2
  100. simtools/simulator.py +0 -5
  101. simtools/testing/assertions.py +2 -2
  102. simtools/testing/configuration.py +17 -4
  103. simtools/utils/general.py +5 -13
  104. simtools/utils/geometry.py +0 -5
  105. simtools/utils/names.py +1 -13
  106. simtools/version.py +61 -0
  107. simtools/visualization/plot_array_layout.py +129 -23
  108. simtools/visualization/plot_incident_angles.py +0 -2
  109. simtools/visualization/plot_simtel_events.py +0 -11
  110. simtools/visualization/visualize.py +0 -12
  111. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/WHEEL +0 -0
  112. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/entry_points.txt +0 -0
  113. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/licenses/LICENSE +0 -0
  114. {gammasimtools-0.22.0.dist-info → gammasimtools-0.23.0.dist-info}/top_level.txt +0 -0
@@ -24,14 +24,13 @@ Runtime < 10 s.
24
24
  simtools-generate-regular-arrays --site=North
25
25
  """
26
26
 
27
- import logging
28
27
  from pathlib import Path
29
28
 
30
29
  import astropy.units as u
31
30
  from astropy.table import QTable
32
31
 
33
32
  import simtools.data_model.model_data_writer as writer
34
- import simtools.utils.general as gen
33
+ from simtools.application_control import get_application_label, startup_application
35
34
  from simtools.configuration import configurator
36
35
  from simtools.utils import names
37
36
 
@@ -42,7 +41,7 @@ telescope_distance = {"LST": 57.5 * u.m, "MST": 70 * u.m, "SST": 80 * u.m}
42
41
 
43
42
  def _parse():
44
43
  config = configurator.Configurator(
45
- label=Path(__file__).stem,
44
+ label=get_application_label(__file__),
46
45
  description=(
47
46
  "Generate a regular array of telescope and save as astropy table.\n"
48
47
  "Default telescope distances for 4 telescope square arrays are: \n"
@@ -58,18 +57,15 @@ def _parse():
58
57
 
59
58
  def main():
60
59
  """Create layout array files (ecsv) of regular arrays."""
61
- args_dict, _ = _parse()
60
+ app_context = startup_application(_parse)
62
61
 
63
- logger = logging.getLogger()
64
- logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
65
-
66
- if args_dict["site"] == "South":
62
+ if app_context.args["site"] == "South":
67
63
  array_list = ["1SST", "4SST", "1MST", "4MST", "1LST", "4LST"]
68
64
  else:
69
65
  array_list = ["1MST", "4MST", "1LST", "4LST"]
70
66
 
71
67
  for array_name in array_list:
72
- logger.info(f"Processing array {array_name}")
68
+ app_context.logger.info(f"Processing array {array_name}")
73
69
 
74
70
  tel_name, pos_x, pos_y, pos_z = [], [], [], []
75
71
  tel_size = array_name[1:4]
@@ -78,7 +74,7 @@ def main():
78
74
  if array_name[0] == "1":
79
75
  tel_name.append(
80
76
  names.generate_array_element_name_from_type_site_id(
81
- tel_size, args_dict["site"], "01"
77
+ tel_size, app_context.args["site"], "01"
82
78
  )
83
79
  )
84
80
  pos_x.append(0 * u.m)
@@ -89,14 +85,14 @@ def main():
89
85
  for i in range(1, 5):
90
86
  tel_name.append(
91
87
  names.generate_array_element_name_from_type_site_id(
92
- tel_size, args_dict["site"], f"0{i}"
88
+ tel_size, app_context.args["site"], f"0{i}"
93
89
  )
94
90
  )
95
91
  pos_x.append(telescope_distance[tel_size] * (-1) ** (i // 2))
96
92
  pos_y.append(telescope_distance[tel_size] * (-1) ** (i % 2))
97
93
  pos_z.append(0 * u.m)
98
94
 
99
- table = QTable(meta={"array_name": array_name, "site": args_dict["site"]})
95
+ table = QTable(meta={"array_name": array_name, "site": app_context.args["site"]})
100
96
  table["telescope_name"] = tel_name
101
97
  table["position_x"] = pos_x
102
98
  table["position_y"] = pos_y
@@ -104,14 +100,14 @@ def main():
104
100
  table.sort("telescope_name")
105
101
  table.pprint()
106
102
 
107
- output_file = args_dict.get("output_file")
103
+ output_file = app_context.args.get("output_file")
108
104
  if output_file:
109
105
  output_path = Path(output_file)
110
106
  output_file = output_path.with_name(
111
- f"{output_path.stem}-{args_dict['site']}-{array_name}{output_path.suffix}"
107
+ f"{output_path.stem}-{app_context.args['site']}-{array_name}{output_path.suffix}"
112
108
  )
113
109
  writer.ModelDataWriter.dump(
114
- args_dict=args_dict,
110
+ args_dict=app_context.args,
115
111
  output_file=output_file,
116
112
  metadata=None,
117
113
  product_data=table,
@@ -124,26 +124,24 @@ To read a reduced event data file, use the following command reading on of the t
124
124
 
125
125
  """
126
126
 
127
- import logging
128
127
  from pathlib import Path
129
128
 
130
- import simtools.utils.general as gen
129
+ from simtools.application_control import get_application_label, startup_application
131
130
  from simtools.configuration import configurator
132
131
  from simtools.data_model.metadata_collector import MetadataCollector
133
132
  from simtools.io import io_handler, table_handler
134
133
  from simtools.simtel.simtel_io_event_writer import SimtelIOEventDataWriter
135
134
 
136
135
 
137
- def _parse(label, description):
138
- """
139
- Parse command line arguments.
140
-
141
- Returns
142
- -------
143
- dict
144
- Parsed command-line arguments.
145
- """
146
- config = configurator.Configurator(label=label, description=description)
136
+ def _parse():
137
+ """Parse command line arguments."""
138
+ config = configurator.Configurator(
139
+ label=get_application_label(__file__),
140
+ description=(
141
+ "Process files and store reduced dataset with event information, "
142
+ "array information and triggered telescopes."
143
+ ),
144
+ )
147
145
 
148
146
  config.parser.add_argument(
149
147
  "--input",
@@ -163,36 +161,28 @@ def _parse(label, description):
163
161
  return config.initialize(db_config=False, output=True)
164
162
 
165
163
 
166
- def main(): # noqa: D103
167
- label = Path(__file__).stem
168
-
169
- args_dict, _ = _parse(
170
- label=label,
171
- description=(
172
- "Process files and store reduced dataset with event information, "
173
- "array information and triggered telescopes."
174
- ),
175
- )
176
-
177
- logger = logging.getLogger()
178
- logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
179
- logger.info(f"Loading input files from: {args_dict['input']}")
164
+ def main():
165
+ """Generate a reduced dataset of event data from output of telescope simulations."""
166
+ app_context = startup_application(_parse, setup_io_handler=False)
167
+ app_context.logger.info(f"Loading input files from: {app_context.args['input']}")
180
168
 
181
- input_pattern = Path(args_dict["input"])
169
+ input_pattern = Path(app_context.args["input"])
182
170
  files = list(input_pattern.parent.glob(input_pattern.name))
183
171
  if not files:
184
- logger.warning("No matching input files found.")
172
+ app_context.logger.warning("No matching input files found.")
185
173
  return
186
174
 
187
- output_filepath = io_handler.IOHandler().get_output_file(args_dict["output_file"])
188
- generator = SimtelIOEventDataWriter(files, args_dict["max_files"])
175
+ output_filepath = io_handler.IOHandler().get_output_file(app_context.args["output_file"])
176
+ generator = SimtelIOEventDataWriter(files, app_context.args["max_files"])
189
177
  tables = generator.process_files()
190
178
  table_handler.write_tables(tables, output_filepath, overwrite_existing=True)
191
- MetadataCollector.dump(args_dict=args_dict, output_file=output_filepath.with_suffix(".yml"))
179
+ MetadataCollector.dump(
180
+ args_dict=app_context.args, output_file=output_filepath.with_suffix(".yml")
181
+ )
192
182
 
193
- if args_dict["print_dataset_information"] > 0:
183
+ if app_context.args["print_dataset_information"] > 0:
194
184
  for table in tables:
195
- table.pprint(max_lines=args_dict["print_dataset_information"], max_width=-1)
185
+ table.pprint(max_lines=app_context.args["print_dataset_information"], max_width=-1)
196
186
 
197
187
 
198
188
  if __name__ == "__main__":
@@ -31,24 +31,19 @@ The following example applies a patch update with changes defined in a YAML file
31
31
 
32
32
  """
33
33
 
34
- import logging
35
34
  from pathlib import Path
36
35
 
37
- import simtools.utils.general as gen
36
+ from simtools.application_control import get_application_label, startup_application
38
37
  from simtools.configuration import configurator
39
38
  from simtools.model import model_repository
40
39
 
41
40
 
42
- def _parse(label, description):
43
- """
44
- Parse command line arguments.
45
-
46
- Returns
47
- -------
48
- dict
49
- Parsed command-line arguments.
50
- """
51
- config = configurator.Configurator(label=label, description=description)
41
+ def _parse():
42
+ """Parse command line arguments."""
43
+ config = configurator.Configurator(
44
+ label=get_application_label(__file__),
45
+ description="Generate a new simulation model production",
46
+ )
52
47
  config.parser.add_argument(
53
48
  "--simulation_models_path",
54
49
  type=str,
@@ -65,15 +60,13 @@ def _parse(label, description):
65
60
  return config.initialize(db_config=False, output=False)
66
61
 
67
62
 
68
- def main(): # noqa: D103
69
- label = Path(__file__).stem
70
- args_dict, _ = _parse(label=label, description="Generate a new simulation model production")
71
- logger = logging.getLogger()
72
- logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
63
+ def main():
64
+ """Generate a new simulation model production."""
65
+ app_context = startup_application(_parse)
73
66
 
74
67
  model_repository.generate_new_production(
75
- modifications=args_dict["modifications"],
76
- simulation_models_path=Path(args_dict["simulation_models_path"]),
68
+ modifications=app_context.args["modifications"],
69
+ simulation_models_path=Path(app_context.args["simulation_models_path"]),
77
70
  )
78
71
 
79
72
 
@@ -13,17 +13,20 @@ Example
13
13
 
14
14
  """
15
15
 
16
- import logging
17
16
  from pathlib import Path
18
17
 
19
18
  import simtools.utils.general as gen
19
+ from simtools.application_control import get_application_label, startup_application
20
20
  from simtools.configuration import configurator
21
21
  from simtools.io import ascii_handler
22
22
 
23
23
 
24
- def _parse(label, description):
24
+ def _parse():
25
25
  """Parse command line arguments."""
26
- config = configurator.Configurator(label=label, description=description)
26
+ config = configurator.Configurator(
27
+ label=get_application_label(__file__),
28
+ description="Compare two directories with model production tables in JSON format.",
29
+ )
27
30
  config.parser.add_argument(
28
31
  "--directory_1",
29
32
  type=str,
@@ -82,16 +85,11 @@ def _compare_json_dirs(dir1, dir2, ignore_key="model_version"):
82
85
  print(f"Missing in dir1: {rel_path}")
83
86
 
84
87
 
85
- def main(): # noqa: D103
86
- label = Path(__file__).stem
87
- args_dict, _ = _parse(
88
- label=label,
89
- description=("Compare two directories with model production tables in JSON format."),
90
- )
91
- logger = logging.getLogger()
92
- logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
88
+ def main():
89
+ """Compare two directories with model production tables in JSON format."""
90
+ app_context = startup_application(_parse, setup_io_handler=False)
93
91
 
94
- _compare_json_dirs(Path(args_dict["directory_1"]), Path(args_dict["directory_2"]))
92
+ _compare_json_dirs(Path(app_context.args["directory_1"]), Path(app_context.args["directory_2"]))
95
93
 
96
94
 
97
95
  if __name__ == "__main__":
@@ -17,21 +17,20 @@ Example
17
17
 
18
18
  """
19
19
 
20
- import logging
21
-
20
+ from simtools.application_control import get_application_label, startup_application
22
21
  from simtools.configuration import configurator
23
22
  from simtools.model import model_repository
24
- from simtools.utils import general as gen
25
23
 
26
24
 
27
25
  def _parse():
28
- """Parse command line arguments."""
26
+ """Parse command line configuration."""
29
27
  config = configurator.Configurator(
28
+ label=get_application_label(__file__),
30
29
  description=(
31
30
  "Verify simulation model production tables and model parameters for completeness. "
32
31
  "This application checks that all model parameters defined in the production tables "
33
32
  "exist in the simulation models repository."
34
- )
33
+ ),
35
34
  )
36
35
  config.parser.add_argument(
37
36
  "--simulation_models_path",
@@ -42,14 +41,12 @@ def _parse():
42
41
  return config.initialize(db_config=False, output=False, paths=False)
43
42
 
44
43
 
45
- def main(): # noqa: D103
46
- args_dict, _ = _parse()
47
-
48
- logger = logging.getLogger()
49
- logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
44
+ def main():
45
+ """Verify simulation model production tables."""
46
+ app_context = startup_application(_parse)
50
47
 
51
48
  if not model_repository.verify_simulation_model_production_tables(
52
- simulation_models_path=args_dict["simulation_models_path"]
49
+ simulation_models_path=app_context.args["simulation_models_path"]
53
50
  ):
54
51
  raise RuntimeError(
55
52
  "Verification failed: Some model parameters are missing in the repository."
@@ -36,24 +36,20 @@ Merge tables from two files generated with 'simtools-generate-simtel-event-data'
36
36
 
37
37
  """
38
38
 
39
- import logging
40
39
  from pathlib import Path
41
40
 
42
41
  import simtools.utils.general as gen
42
+ from simtools.application_control import get_application_label, startup_application
43
43
  from simtools.configuration import configurator
44
44
  from simtools.io import io_handler, table_handler
45
45
 
46
46
 
47
- def _parse(label, description):
48
- """
49
- Parse command line arguments.
50
-
51
- Returns
52
- -------
53
- dict
54
- Parsed command-line arguments.
55
- """
56
- config = configurator.Configurator(label=label, description=description)
47
+ def _parse():
48
+ """Parse command line arguments."""
49
+ config = configurator.Configurator(
50
+ label=get_application_label(__file__),
51
+ description="Merge tables from multiple input files into single tables.",
52
+ )
57
53
 
58
54
  input_group = config.parser.add_mutually_exclusive_group(required=True)
59
55
  input_group.add_argument(
@@ -72,28 +68,23 @@ def _parse(label, description):
72
68
  return config.initialize(db_config=False, output=True)
73
69
 
74
70
 
75
- def main(): # noqa: D103
76
- label = Path(__file__).stem
71
+ def main():
72
+ """Merge tables from multiple input files into single tables."""
73
+ app_context = startup_application(_parse)
77
74
 
78
- args_dict, _ = _parse(
79
- label=label,
80
- description=("Merge tables from multiple input files into single tables."),
81
- )
82
- logger = logging.getLogger()
83
- logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
84
- logger.info(f"Loading input files: {args_dict['input_files']}")
75
+ app_context.logger.info(f"Loading input files: {app_context.args['input_files']}")
85
76
 
86
77
  # accept fits.gz files (.gz)
87
78
  input_files = gen.get_list_of_files_from_command_line(
88
- args_dict["input_files"], [".hdf5", ".gz"]
79
+ app_context.args["input_files"], [".hdf5", ".gz"]
89
80
  )
90
81
 
91
82
  output_path = io_handler.IOHandler().get_output_directory()
92
- output_filepath = Path(output_path).joinpath(f"{args_dict['output_file']}")
83
+ output_filepath = Path(output_path).joinpath(f"{app_context.args['output_file']}")
93
84
 
94
85
  table_handler.merge_tables(
95
86
  input_files,
96
- input_table_names=args_dict["table_names"],
87
+ input_table_names=app_context.args["table_names"],
97
88
  output_file=output_filepath,
98
89
  )
99
90
 
@@ -56,6 +56,12 @@ axes_range : float, optional
56
56
  Range of the both axes in meters.
57
57
  marker_scaling : float, optional.
58
58
  Scaling factor for plotting of array elements, optional.
59
+ grayed_out_array_elements : list, optional
60
+ List of array elements to plot as gray circles.
61
+ highlighted_array_elements : list, optional
62
+ List of array elements to plot with red circles around them.
63
+ legend_location : str, optional
64
+ Location of the legend (default "best").
59
65
 
60
66
  Examples
61
67
  --------
@@ -97,41 +103,39 @@ Plot all layouts for the North site and model version 6.0.0:
97
103
  .. code-block:: console
98
104
 
99
105
  simtools-plot-array-layout --site North --plot_all_layouts --model_version=6.0.0
100
- """
101
106
 
102
- import logging
103
- from pathlib import Path
107
+ Plot layout with some telescopes grayed out and others highlighted:
108
+
109
+ .. code-block:: console
110
+
111
+ simtools-plot-array-layout --site North
112
+ --array_layout_name alpha
113
+ --model_version=6.0.0
114
+ --grayed_out_array_elements LSTN-01 LSTN-02
115
+ --highlighted_array_elements MSTN-01 MSTN-02
116
+ --legend_location "upper right"
117
+ """
104
118
 
105
119
  import matplotlib as mpl
106
120
  import matplotlib.pyplot as plt
107
121
 
108
122
  import simtools.layout.array_layout_utils as layout_utils
109
- import simtools.utils.general as gen
123
+ from simtools.application_control import get_application_label, startup_application
110
124
  from simtools.configuration import configurator
111
- from simtools.io import io_handler
112
125
  from simtools.visualization import visualize
113
126
  from simtools.visualization.plot_array_layout import plot_array_layout
114
127
 
115
128
 
116
- def _parse(label, description, usage=None):
117
- """
118
- Parse command line configuration.
119
-
120
- Parameters
121
- ----------
122
- label : str
123
- Label describing the application.
124
- description : str
125
- Description of the application.
126
- usage : str
127
- Example on how to use the application.
128
-
129
- Returns
130
- -------
131
- CommandLineParser
132
- Command line parser object.
133
- """
134
- config = configurator.Configurator(label=label, description=description, usage=usage)
129
+ def _parse():
130
+ """Parse command line configuration."""
131
+ config = configurator.Configurator(
132
+ label=get_application_label(__file__),
133
+ description="Plots array layout.",
134
+ usage=(
135
+ "Use '--array_layout_name plot_all' to plot all layouts for the given site "
136
+ "and model version."
137
+ ),
138
+ )
135
139
 
136
140
  config.parser.add_argument(
137
141
  "--figure_name",
@@ -176,6 +180,33 @@ def _parse(label, description, usage=None):
176
180
  required=False,
177
181
  default=None,
178
182
  )
183
+ config.parser.add_argument(
184
+ "--grayed_out_array_elements",
185
+ help="List of array elements to plot as gray circles.",
186
+ type=str,
187
+ nargs="*",
188
+ required=False,
189
+ default=None,
190
+ )
191
+ config.parser.add_argument(
192
+ "--highlighted_array_elements",
193
+ help="List of array elements to plot with red circles around them.",
194
+ type=str,
195
+ nargs="*",
196
+ required=False,
197
+ default=None,
198
+ )
199
+ config.parser.add_argument(
200
+ "--legend_location",
201
+ help=(
202
+ "Location of the legend (e.g., 'best', 'upper right', 'upper left', "
203
+ "'lower left', 'lower right', 'right', 'center left', 'center right', "
204
+ "'lower center', 'upper center', 'center')."
205
+ ),
206
+ type=str,
207
+ required=False,
208
+ default="best",
209
+ )
179
210
  return config.initialize(
180
211
  db_config=True,
181
212
  simulation_model=[
@@ -199,8 +230,8 @@ def read_layouts(args_dict, db_config, logger):
199
230
  Dictionary with command line arguments.
200
231
  db_config : dict
201
232
  Database configuration.
202
- logger : logging.Logger
203
- Logger instance.
233
+ logger : logging.app_context.logger
234
+ app_context.logger instance.
204
235
 
205
236
  Returns
206
237
  -------
@@ -248,28 +279,17 @@ def read_layouts(args_dict, db_config, logger):
248
279
 
249
280
  def main():
250
281
  """Plot array layout application."""
251
- label = Path(__file__).stem
252
- args_dict, db_config = _parse(
253
- label,
254
- (
255
- "Plots array layout."
256
- "Use '--array_layout_name plot_all' to plot all layouts for the given site "
257
- "and model version."
258
- ),
259
- )
260
- logger = logging.getLogger()
261
- logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
262
- io_handler_instance = io_handler.IOHandler()
282
+ app_context = startup_application(_parse)
263
283
 
264
- layouts = read_layouts(args_dict, db_config, logger)
284
+ layouts = read_layouts(app_context.args, app_context.db_config, app_context.logger)
265
285
 
266
- if args_dict.get("array_layout_name_background"):
286
+ if app_context.args.get("array_layout_name_background"):
267
287
  background_layout = layout_utils.get_array_layouts_from_db(
268
- args_dict["array_layout_name_background"],
269
- args_dict["site"],
270
- args_dict["model_version"],
271
- db_config,
272
- args_dict["coordinate_system"],
288
+ app_context.args["array_layout_name_background"],
289
+ app_context.args["site"],
290
+ app_context.args["model_version"],
291
+ app_context.db_config,
292
+ app_context.args["coordinate_system"],
273
293
  )["array_elements"]
274
294
  else:
275
295
  background_layout = None
@@ -278,28 +298,31 @@ def main():
278
298
  for layout in layouts:
279
299
  fig_out = plot_array_layout(
280
300
  telescopes=layout["array_elements"],
281
- show_tel_label=args_dict["show_labels"],
282
- axes_range=args_dict["axes_range"],
283
- marker_scaling=args_dict["marker_scaling"],
301
+ show_tel_label=app_context.args["show_labels"],
302
+ axes_range=app_context.args["axes_range"],
303
+ marker_scaling=app_context.args["marker_scaling"],
284
304
  background_telescopes=background_layout,
305
+ grayed_out_elements=app_context.args["grayed_out_array_elements"],
306
+ highlighted_elements=app_context.args["highlighted_array_elements"],
307
+ legend_location=app_context.args["legend_location"],
285
308
  )
286
309
  site_string = ""
287
310
  if layout.get("site") is not None:
288
311
  site_string = f"_{layout['site']}"
289
- elif args_dict["site"] is not None:
290
- site_string = f"_{args_dict['site']}"
312
+ elif app_context.args["site"] is not None:
313
+ site_string = f"_{app_context.args['site']}"
291
314
  coordinate_system_string = (
292
- f"_{args_dict['coordinate_system']}"
293
- if args_dict["coordinate_system"] not in layout["name"]
315
+ f"_{app_context.args['coordinate_system']}"
316
+ if app_context.args["coordinate_system"] not in layout["name"]
294
317
  else ""
295
318
  )
296
- plot_file_name = args_dict["figure_name"] or (
319
+ plot_file_name = app_context.args["figure_name"] or (
297
320
  f"array_layout_{layout['name']}{site_string}{coordinate_system_string}"
298
321
  )
299
322
 
300
323
  visualize.save_figure(
301
324
  fig_out,
302
- io_handler_instance.get_output_directory() / plot_file_name,
325
+ app_context.io_handler.get_output_directory() / plot_file_name,
303
326
  dpi=400,
304
327
  )
305
328
  plt.close()
@@ -76,19 +76,18 @@ Examples
76
76
 
77
77
  """
78
78
 
79
- import logging
80
79
  from pathlib import Path
81
80
 
82
81
  import simtools.utils.general as gen
82
+ from simtools.application_control import get_application_label, startup_application
83
83
  from simtools.configuration import configurator
84
- from simtools.io import io_handler
85
84
  from simtools.visualization.plot_simtel_events import PLOT_CHOICES, generate_and_save_plots
86
85
 
87
86
 
88
- def _parse(label: str):
87
+ def _parse():
89
88
  """Parse command line configuration."""
90
89
  config = configurator.Configurator(
91
- label=label,
90
+ label=get_application_label(__file__),
92
91
  description=(
93
92
  "Create diagnostic plots from sim_telarray files using simtools visualization."
94
93
  ),
@@ -178,17 +177,16 @@ def _parse(label: str):
178
177
 
179
178
  def main():
180
179
  """Generate plots from sim_telarray files."""
181
- label = Path(__file__).stem
182
- args, _db = _parse(label)
180
+ app_context = startup_application(_parse)
183
181
 
184
- logger = logging.getLogger()
185
- logger.setLevel(gen.get_log_level_from_user(args.get("log_level", "INFO")))
182
+ simtel_files = [
183
+ Path(p).expanduser() for p in gen.ensure_iterable(app_context.args["simtel_files"])
184
+ ]
185
+ plots = list(gen.ensure_iterable(app_context.args.get("plots")))
186
186
 
187
- ioh = io_handler.IOHandler()
188
- simtel_files = [Path(p).expanduser() for p in gen.ensure_iterable(args["simtel_files"])]
189
- plots = list(gen.ensure_iterable(args.get("plots")))
190
-
191
- generate_and_save_plots(simtel_files=simtel_files, plots=plots, args=args, ioh=ioh)
187
+ generate_and_save_plots(
188
+ simtel_files=simtel_files, plots=plots, args=app_context.args, ioh=app_context.io_handler
189
+ )
192
190
 
193
191
 
194
192
  if __name__ == "__main__":