gammasimtools 0.8.2__py3-none-any.whl → 0.10.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 (122) hide show
  1. {gammasimtools-0.8.2.dist-info → gammasimtools-0.10.0.dist-info}/METADATA +4 -4
  2. {gammasimtools-0.8.2.dist-info → gammasimtools-0.10.0.dist-info}/RECORD +119 -105
  3. {gammasimtools-0.8.2.dist-info → gammasimtools-0.10.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.8.2.dist-info → gammasimtools-0.10.0.dist-info}/entry_points.txt +4 -1
  5. simtools/_version.py +2 -2
  6. simtools/applications/calculate_trigger_rate.py +15 -38
  7. simtools/applications/convert_all_model_parameters_from_simtel.py +9 -28
  8. simtools/applications/convert_geo_coordinates_of_array_elements.py +54 -53
  9. simtools/applications/convert_model_parameter_from_simtel.py +2 -2
  10. simtools/applications/db_add_file_to_db.py +1 -2
  11. simtools/applications/db_add_simulation_model_from_repository_to_db.py +110 -0
  12. simtools/applications/db_add_value_from_json_to_db.py +2 -11
  13. simtools/applications/db_development_tools/write_array_elements_positions_to_repository.py +6 -6
  14. simtools/applications/db_get_array_layouts_from_db.py +3 -1
  15. simtools/applications/db_get_file_from_db.py +11 -12
  16. simtools/applications/db_get_parameter_from_db.py +44 -32
  17. simtools/applications/derive_mirror_rnda.py +10 -1
  18. simtools/applications/derive_photon_electron_spectrum.py +99 -0
  19. simtools/applications/derive_psf_parameters.py +1 -1
  20. simtools/applications/generate_array_config.py +18 -22
  21. simtools/applications/generate_regular_arrays.py +24 -21
  22. simtools/applications/generate_simtel_array_histograms.py +11 -48
  23. simtools/applications/plot_array_layout.py +3 -1
  24. simtools/applications/plot_tabular_data.py +84 -0
  25. simtools/applications/production_generate_simulation_config.py +25 -7
  26. simtools/applications/production_scale_events.py +3 -4
  27. simtools/applications/simulate_light_emission.py +2 -2
  28. simtools/applications/simulate_prod.py +25 -60
  29. simtools/applications/simulate_prod_htcondor_generator.py +95 -0
  30. simtools/applications/submit_data_from_external.py +12 -4
  31. simtools/applications/submit_model_parameter_from_external.py +8 -6
  32. simtools/applications/validate_camera_efficiency.py +3 -3
  33. simtools/applications/validate_camera_fov.py +3 -7
  34. simtools/applications/validate_cumulative_psf.py +3 -7
  35. simtools/applications/validate_file_using_schema.py +38 -24
  36. simtools/applications/validate_optics.py +3 -4
  37. simtools/{camera_efficiency.py → camera/camera_efficiency.py} +1 -4
  38. simtools/camera/single_photon_electron_spectrum.py +168 -0
  39. simtools/configuration/commandline_parser.py +14 -13
  40. simtools/configuration/configurator.py +6 -19
  41. simtools/constants.py +10 -3
  42. simtools/corsika/corsika_config.py +8 -7
  43. simtools/corsika/corsika_histograms.py +1 -1
  44. simtools/data_model/data_reader.py +0 -3
  45. simtools/data_model/metadata_collector.py +21 -4
  46. simtools/data_model/metadata_model.py +8 -111
  47. simtools/data_model/model_data_writer.py +18 -64
  48. simtools/data_model/schema.py +213 -0
  49. simtools/data_model/validate_data.py +73 -51
  50. simtools/db/db_handler.py +395 -790
  51. simtools/db/db_model_upload.py +139 -0
  52. simtools/io_operations/hdf5_handler.py +54 -24
  53. simtools/io_operations/legacy_data_handler.py +61 -0
  54. simtools/job_execution/htcondor_script_generator.py +133 -0
  55. simtools/job_execution/job_manager.py +77 -50
  56. simtools/layout/array_layout.py +33 -28
  57. simtools/model/array_model.py +13 -7
  58. simtools/model/camera.py +4 -2
  59. simtools/model/model_parameter.py +61 -63
  60. simtools/model/site_model.py +3 -3
  61. simtools/production_configuration/calculate_statistical_errors_grid_point.py +119 -144
  62. simtools/production_configuration/event_scaler.py +7 -17
  63. simtools/production_configuration/generate_simulation_config.py +5 -32
  64. simtools/production_configuration/interpolation_handler.py +8 -11
  65. simtools/ray_tracing/mirror_panel_psf.py +47 -27
  66. simtools/runners/corsika_runner.py +14 -3
  67. simtools/runners/corsika_simtel_runner.py +3 -1
  68. simtools/runners/runner_services.py +3 -3
  69. simtools/runners/simtel_runner.py +27 -8
  70. simtools/schemas/input/MST_mirror_2f_measurements.schema.yml +39 -0
  71. simtools/schemas/input/single_pe_spectrum.schema.yml +38 -0
  72. simtools/schemas/integration_tests_config.metaschema.yml +23 -3
  73. simtools/schemas/model_parameter.metaschema.yml +95 -2
  74. simtools/schemas/model_parameter_and_data_schema.metaschema.yml +2 -0
  75. simtools/schemas/model_parameters/array_element_position_utm.schema.yml +1 -1
  76. simtools/schemas/model_parameters/array_window.schema.yml +37 -0
  77. simtools/schemas/model_parameters/asum_clipping.schema.yml +0 -4
  78. simtools/schemas/model_parameters/channels_per_chip.schema.yml +1 -1
  79. simtools/schemas/model_parameters/corsika_iact_io_buffer.schema.yml +2 -2
  80. simtools/schemas/model_parameters/dsum_clipping.schema.yml +0 -2
  81. simtools/schemas/model_parameters/dsum_ignore_below.schema.yml +0 -2
  82. simtools/schemas/model_parameters/dsum_offset.schema.yml +0 -2
  83. simtools/schemas/model_parameters/dsum_pedsub.schema.yml +0 -2
  84. simtools/schemas/model_parameters/dsum_pre_clipping.schema.yml +0 -2
  85. simtools/schemas/model_parameters/dsum_prescale.schema.yml +0 -2
  86. simtools/schemas/model_parameters/dsum_presum_max.schema.yml +0 -2
  87. simtools/schemas/model_parameters/dsum_presum_shift.schema.yml +0 -2
  88. simtools/schemas/model_parameters/dsum_shaping.schema.yml +0 -2
  89. simtools/schemas/model_parameters/dsum_shaping_renormalize.schema.yml +0 -2
  90. simtools/schemas/model_parameters/dsum_threshold.schema.yml +0 -2
  91. simtools/schemas/model_parameters/dsum_zero_clip.schema.yml +0 -2
  92. simtools/schemas/model_parameters/effective_focal_length.schema.yml +31 -1
  93. simtools/schemas/model_parameters/fadc_compensate_pedestal.schema.yml +1 -1
  94. simtools/schemas/model_parameters/fadc_lg_compensate_pedestal.schema.yml +1 -1
  95. simtools/schemas/model_parameters/fadc_noise.schema.yml +3 -3
  96. simtools/schemas/model_parameters/fake_mirror_list.schema.yml +33 -0
  97. simtools/schemas/model_parameters/laser_photons.schema.yml +2 -2
  98. simtools/schemas/model_parameters/secondary_mirror_degraded_reflection.schema.yml +1 -1
  99. simtools/schemas/production_configuration_metrics.schema.yml +68 -0
  100. simtools/schemas/production_tables.schema.yml +41 -0
  101. simtools/simtel/simtel_config_writer.py +5 -6
  102. simtools/simtel/simtel_io_histogram.py +32 -67
  103. simtools/simtel/simtel_io_histograms.py +15 -30
  104. simtools/simtel/simtel_table_reader.py +410 -0
  105. simtools/simtel/simulator_array.py +2 -1
  106. simtools/simtel/simulator_camera_efficiency.py +11 -4
  107. simtools/simtel/simulator_light_emission.py +5 -3
  108. simtools/simtel/simulator_ray_tracing.py +2 -2
  109. simtools/simulator.py +80 -33
  110. simtools/testing/configuration.py +12 -8
  111. simtools/testing/helpers.py +9 -16
  112. simtools/testing/validate_output.py +152 -68
  113. simtools/utils/general.py +149 -12
  114. simtools/utils/names.py +25 -21
  115. simtools/utils/value_conversion.py +9 -1
  116. simtools/visualization/plot_tables.py +106 -0
  117. simtools/visualization/visualize.py +43 -5
  118. simtools/applications/db_add_model_parameters_from_repository_to_db.py +0 -184
  119. simtools/db/db_array_elements.py +0 -130
  120. simtools/db/db_from_repo_handler.py +0 -106
  121. {gammasimtools-0.8.2.dist-info → gammasimtools-0.10.0.dist-info}/LICENSE +0 -0
  122. {gammasimtools-0.8.2.dist-info → gammasimtools-0.10.0.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/python3
2
2
 
3
3
  r"""
4
- Generate simulation configuration and run simulations (if required).
4
+ Generate simulation configuration and run simulations.
5
5
 
6
6
  Multipipe scripts will be produced as part of this application.
7
7
  Allows to run array layout simulation including shower and detector simulations
@@ -31,7 +31,7 @@ r"""
31
31
  Zenith angle in degrees.
32
32
  nshow (int, optional)
33
33
  Number of showers to simulate.
34
- The Number of simulated events depends on the number of times a shower is re-used in the
34
+ The Number of simulated events depends on the number of times a shower is reused in the
35
35
  telescope simulation. The number provided here is before any reuse factors.
36
36
  start_run (int, required)
37
37
  Start run number such that the actual run number will be 'start_run' + 'run'.
@@ -43,9 +43,9 @@ r"""
43
43
  The location of the output directories corsika-data and simtel-data.
44
44
  the label is added to the data_directory, such that the output
45
45
  will be written to data_directory/label/simtel-data.
46
- pack_for_grid_register (bool, optional)
46
+ pack_for_grid_register (str, optional)
47
47
  Set whether to prepare a tarball for registering the output files on the grid.
48
- The files are written to the output_path/directory_for_grid_upload directory.
48
+ The files are written to the specified directory.
49
49
  log_level (str, optional)
50
50
  Log level to print.
51
51
 
@@ -68,9 +68,6 @@ r"""
68
68
  """
69
69
 
70
70
  import logging
71
- import shutil
72
- import tarfile
73
- from pathlib import Path
74
71
 
75
72
  import simtools.utils.general as gen
76
73
  from simtools.configuration import configurator
@@ -106,10 +103,10 @@ def _parse(description=None):
106
103
  )
107
104
  config.parser.add_argument(
108
105
  "--pack_for_grid_register",
109
- help="Set whether to prepare a tarball for registering the output files on the grid.",
110
- action="store_true",
106
+ help="Directory for a tarball for registering the output files on the grid.",
107
+ type=str,
111
108
  required=False,
112
- default=False,
109
+ default=None,
113
110
  )
114
111
  config.parser.add_argument(
115
112
  "--save_file_lists",
@@ -137,49 +134,11 @@ def _parse(description=None):
137
134
  return config.initialize(
138
135
  db_config=True,
139
136
  job_submission=True,
140
- simulation_model=["site", "layout", "telescope"],
137
+ simulation_model=["site", "layout", "telescope", "model_version"],
141
138
  simulation_configuration={"software": None, "corsika_configuration": ["all"]},
142
139
  )
143
140
 
144
141
 
145
- def pack_for_register(logger, simulator, args_dict):
146
- """
147
- Pack the output files for registering on the grid.
148
-
149
- Parameters
150
- ----------
151
- logger: logging.Logger
152
- Logger object.
153
- simulator: Simulator
154
- Simulator object.
155
-
156
- """
157
- logger.info("Packing the output files for registering on the grid")
158
- output_files = simulator.get_file_list(file_type="output")
159
- log_files = simulator.get_file_list(file_type="log")
160
- histogram_files = simulator.get_file_list(file_type="hist")
161
- tar_file_name = Path(log_files[0]).name.replace("log.gz", "log_hist.tar.gz")
162
- directory_for_grid_upload = Path(args_dict.get("output_path")).joinpath(
163
- "directory_for_grid_upload"
164
- )
165
- directory_for_grid_upload.mkdir(parents=True, exist_ok=True)
166
- tar_file_name = directory_for_grid_upload.joinpath(tar_file_name)
167
-
168
- with tarfile.open(tar_file_name, "w:gz") as tar:
169
- files_to_tar = log_files[:1] + histogram_files[:1]
170
- for file_to_tar in files_to_tar:
171
- tar.add(file_to_tar, arcname=Path(file_to_tar).name)
172
-
173
- for file_to_move in [*output_files]:
174
- source_file = Path(file_to_move)
175
- destination_file = directory_for_grid_upload / source_file.name
176
- # Note that this will overwrite previous files which exist in the directory
177
- # It should be fine for normal production since each run is on a separate node
178
- # so no files are expected there.
179
- shutil.move(source_file, destination_file)
180
- logger.info(f"Output files for the grid placed in {directory_for_grid_upload!s}")
181
-
182
-
183
142
  def main(): # noqa: D103
184
143
  args_dict, db_config = _parse(description="Run simulations for productions")
185
144
 
@@ -192,17 +151,23 @@ def main(): # noqa: D103
192
151
 
193
152
  simulator.simulate()
194
153
 
195
- logger.info(
196
- f"Production run is complete for primary {args_dict['primary']} showers "
197
- f"coming from {args_dict['azimuth_angle']} azimuth and zenith angle of "
198
- f"{args_dict['zenith_angle']} at the {args_dict['site']} site, "
199
- f"using the {args_dict['model_version']} simulation model."
200
- )
201
-
202
- if args_dict["pack_for_grid_register"]:
203
- pack_for_register(logger, simulator, args_dict)
204
- if args_dict["save_file_lists"]:
205
- simulator.save_file_lists()
154
+ if simulator.submit_engine == "local":
155
+ logger.info(
156
+ f"Production run complete for primary {args_dict['primary']} showers "
157
+ f"from {args_dict['azimuth_angle']} azimuth and {args_dict['zenith_angle']} zenith "
158
+ f"at {args_dict['site']} site, using {args_dict['model_version']} model."
159
+ )
160
+ if args_dict.get("pack_for_grid_register"):
161
+ simulator.pack_for_register(args_dict["pack_for_grid_register"])
162
+ if args_dict["save_file_lists"]:
163
+ simulator.save_file_lists()
164
+ else:
165
+ logger.info("Production run submitted to the workload manager")
166
+ if args_dict["pack_for_grid_register"] or args_dict["save_file_lists"]:
167
+ logger.warning(
168
+ "Packing for grid register or saving file lists not supported for "
169
+ f"{simulator.submit_engine}."
170
+ )
206
171
 
207
172
 
208
173
  if __name__ == "__main__":
@@ -0,0 +1,95 @@
1
+ #!/usr/bin/python3
2
+
3
+ r"""
4
+ Generate a run script and submit file for HT Condor job submission of a simulation production.
5
+
6
+ This tool facilitates the submission of multiple simulations to the HT Condor batch system,
7
+ enabling:
8
+
9
+ - Execution of simulations using the "simtools-simulate-prod" application.
10
+ - 'number_of_runs' jobs are submitted to the HT Condor batch system.
11
+ - Utilization of an Apptainer image containing the SimPipe simulation software and tools.
12
+ - Packaging of data and histogram files, and writing them to a specified directory.
13
+
14
+ This tool is intended for use in an HT Condor environment. Jobs run in a container universe
15
+ using the Apptainer image specified in the command line ('--apptainer_image'). Output is written
16
+ to the 'output_path' directory, with 'simtools-output' and 'logs' subdirectories.
17
+
18
+ Requirements for the 'simtools-simulate-prod-htcondor-generator' application:
19
+
20
+ - Availability of an Apptainer image 'simtools-prod' (obtainable from the package registry on
21
+ GitHub, e.g., via 'apptainer pull --force docker://ghcr.io/gammasim/simtools-prod:latest').
22
+ - Environment parameters required to run CORSIKA and sim_telarray, as well as DB access
23
+ credentials. These should be listed similarly to a '.env' file and copied to
24
+ 'output_path/env.txt'. Ensure that the path to the simulation software is correctly set to
25
+ 'SIMTOOLS_SIMTEL_PATH=/workdir/sim_telarray'.
26
+
27
+
28
+ Command line arguments
29
+ ----------------------
30
+ output_path (str, required)
31
+ Directory where the output and the simulation data files will be written.
32
+ apptainer_image (str, optional)
33
+ Apptainer image to use for the simulation (full path).
34
+ priority (int, optional)
35
+ Job priority (default: 1).
36
+
37
+ (all other command line arguments are identical to those of :ref:`simulate_prod`).
38
+
39
+ """
40
+
41
+ import logging
42
+
43
+ import simtools.utils.general as gen
44
+ from simtools.configuration import configurator
45
+ from simtools.job_execution import htcondor_script_generator
46
+
47
+
48
+ def _parse(description=None):
49
+ """
50
+ Parse command line configuration.
51
+
52
+ Parameters
53
+ ----------
54
+ description: str
55
+ Application description.
56
+
57
+ Returns
58
+ -------
59
+ CommandLineParser
60
+ Command line parser object.
61
+
62
+ """
63
+ config = configurator.Configurator(description=description)
64
+ config.parser.add_argument(
65
+ "--apptainer_image",
66
+ help="Apptainer image to use for the simulation (full path).",
67
+ type=str,
68
+ required=False,
69
+ )
70
+ config.parser.add_argument(
71
+ "--priority",
72
+ help="Job priority.",
73
+ type=int,
74
+ required=False,
75
+ default=1,
76
+ )
77
+ return config.initialize(
78
+ db_config=False,
79
+ job_submission=False,
80
+ simulation_model=["site", "layout", "telescope", "model_version"],
81
+ simulation_configuration={"software": None, "corsika_configuration": ["all"]},
82
+ )
83
+
84
+
85
+ def main(): # noqa: D103
86
+ args_dict, _ = _parse(description="Prepare simulations production for HT Condor job submission")
87
+
88
+ logger = logging.getLogger()
89
+ logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
90
+
91
+ htcondor_script_generator.generate_submission_script(args_dict)
92
+
93
+
94
+ if __name__ == "__main__":
95
+ main()
@@ -24,7 +24,7 @@ r"""
24
24
  simtools-submit-data-from-external \\
25
25
  --input_meta ./tests/resources/MLTdata-preproduction.meta.yml \\
26
26
  --input ./tests/resources/MLTdata-preproduction.ecsv \\
27
- --schema ./tests/resources/schema_MST_mirror_2f_measurements.yml \\
27
+ --schema src/simtools/schemas/input/MST_mirror_2f_measurements.schema.yml \\
28
28
  --output_file TEST-submit_data_from_external.ecsv
29
29
 
30
30
  Expected final print-out message:
@@ -83,6 +83,12 @@ def _parse(label, description):
83
83
  type=str,
84
84
  required=False,
85
85
  )
86
+ config.parser.add_argument(
87
+ "--ignore_metadata",
88
+ help="Ignore metadata",
89
+ action="store_true",
90
+ required=False,
91
+ )
86
92
  return config.initialize(output=True)
87
93
 
88
94
 
@@ -95,16 +101,18 @@ def main(): # noqa: D103
95
101
  logger = logging.getLogger()
96
102
  logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
97
103
 
98
- _metadata = MetadataCollector(args_dict=args_dict)
104
+ _metadata = None if args_dict.get("ignore_metadata") else MetadataCollector(args_dict)
99
105
 
100
106
  data_validator = validate_data.DataValidator(
101
- schema_file=_metadata.get_data_model_schema_file_name(),
107
+ schema_file=(
108
+ _metadata.get_data_model_schema_file_name() if _metadata else args_dict.get("schema")
109
+ ),
102
110
  data_file=args_dict["input"],
103
111
  )
104
112
 
105
113
  writer.ModelDataWriter.dump(
106
114
  args_dict=args_dict,
107
- metadata=_metadata.top_level_meta,
115
+ metadata=_metadata.get_top_level_metadata() if _metadata else None,
108
116
  product_data=data_validator.validate_and_transform(),
109
117
  )
110
118
 
@@ -16,8 +16,8 @@ r"""
16
16
  instrument name.
17
17
  site (str)
18
18
  site location.
19
- model_version (str)
20
- Model version.
19
+ parameter_version (str)
20
+ Parameter version.
21
21
  input_meta (str, optional)
22
22
  input meta data file (yml format)
23
23
 
@@ -33,7 +33,7 @@ r"""
33
33
  --value 2 \\
34
34
  --instrument LSTN-design \\
35
35
  --site North \\
36
- --model_version 6.0.0 \\
36
+ --parameter_version 0.1.0 \\
37
37
  --input_meta num_gains.metadata.yml
38
38
 
39
39
  """
@@ -70,7 +70,9 @@ def _parse(label, description):
70
70
  )
71
71
  config.parser.add_argument("--instrument", type=str, required=True, help="Instrument name")
72
72
  config.parser.add_argument("--site", type=str, required=True, help="Site location")
73
- config.parser.add_argument("--model_version", type=str, required=True, help="Model version")
73
+ config.parser.add_argument(
74
+ "--parameter_version", type=str, required=True, help="Parameter version"
75
+ )
74
76
 
75
77
  config.parser.add_argument(
76
78
  "--value",
@@ -102,7 +104,7 @@ def main(): # noqa: D103
102
104
  logger.setLevel(gen.get_log_level_from_user(args_dict["log_level"]))
103
105
 
104
106
  output_path = (
105
- Path(args_dict["output_path"]) / args_dict["model_version"] / args_dict["instrument"]
107
+ Path(args_dict["output_path"]) / args_dict["parameter_version"] / args_dict["instrument"]
106
108
  if args_dict.get("output_path")
107
109
  else None
108
110
  )
@@ -110,7 +112,7 @@ def main(): # noqa: D103
110
112
  parameter_name=args_dict["parameter"],
111
113
  value=args_dict["value"],
112
114
  instrument=args_dict["instrument"],
113
- model_version=args_dict["model_version"],
115
+ parameter_version=args_dict["parameter_version"],
114
116
  output_file=Path(args_dict["parameter"]).with_suffix(".json"),
115
117
  output_path=output_path,
116
118
  use_plain_output_path=args_dict.get("use_plain_output_path"),
@@ -47,7 +47,7 @@ import logging
47
47
  from pathlib import Path
48
48
 
49
49
  import simtools.utils.general as gen
50
- from simtools.camera_efficiency import CameraEfficiency
50
+ from simtools.camera.camera_efficiency import CameraEfficiency
51
51
  from simtools.configuration import configurator
52
52
 
53
53
 
@@ -86,7 +86,7 @@ def _parse(label):
86
86
  )
87
87
  _args_dict, _db_config = config.initialize(
88
88
  db_config=True,
89
- simulation_model="telescope",
89
+ simulation_model=["telescope", "model_version"],
90
90
  simulation_configuration={"corsika_configuration": ["zenith_angle", "azimuth_angle"]},
91
91
  )
92
92
  if _args_dict["site"] is None or _args_dict["telescope"] is None:
@@ -106,7 +106,7 @@ def main(): # noqa: D103
106
106
  ce = CameraEfficiency(
107
107
  db_config=_db_config,
108
108
  simtel_path=args_dict["simtel_path"],
109
- label=label,
109
+ label=args_dict.get("label", label),
110
110
  config_data=args_dict,
111
111
  )
112
112
  ce.simulate()
@@ -54,7 +54,7 @@ import simtools.utils.general as gen
54
54
  from simtools.configuration import configurator
55
55
  from simtools.io_operations import io_handler
56
56
  from simtools.model.telescope_model import TelescopeModel
57
- from simtools.visualization import plot_camera
57
+ from simtools.visualization import plot_camera, visualize
58
58
 
59
59
 
60
60
  def _parse():
@@ -83,7 +83,7 @@ def _parse():
83
83
  ),
84
84
  default=50,
85
85
  )
86
- return config.initialize(db_config=True, simulation_model="telescope")
86
+ return config.initialize(db_config=True, simulation_model=["telescope", "model_version"])
87
87
 
88
88
 
89
89
  def main(): # noqa: D103
@@ -133,11 +133,7 @@ def main(): # noqa: D103
133
133
  ) from exc
134
134
  fig = plot_camera.plot_pixel_layout(camera, args_dict["camera_in_sky_coor"], pixel_ids_to_print)
135
135
  plot_file_prefix = output_dir.joinpath(f"{label}_{tel_model.name}_pixel_layout")
136
- for suffix in ["pdf", "png"]:
137
- file_name = f"{plot_file_prefix!s}.{suffix}"
138
- fig.savefig(file_name, format=suffix, bbox_inches="tight")
139
- print(f"\nSaved camera plot in {file_name}\n")
140
- fig.clf()
136
+ visualize.save_figure(fig, f"{plot_file_prefix!s}", log_title="camera")
141
137
 
142
138
 
143
139
  if __name__ == "__main__":
@@ -110,7 +110,7 @@ def _parse(label):
110
110
  help="Data file name with the measured PSF vs radius [cm]",
111
111
  type=str,
112
112
  )
113
- return config.initialize(db_config=True, simulation_model="telescope")
113
+ return config.initialize(db_config=True, simulation_model=["telescope", "model_version"])
114
114
 
115
115
 
116
116
  def load_data(datafile):
@@ -182,9 +182,7 @@ def main(): # noqa: D103
182
182
 
183
183
  plot_file_name = label + "_" + tel_model.name + "_cumulative_PSF"
184
184
  plot_file = output_dir.joinpath(plot_file_name)
185
- for f in ["pdf", "png"]:
186
- plt.savefig(str(plot_file) + "." + f, format=f, bbox_inches="tight")
187
- fig.clf()
185
+ visualize.save_figure(fig, plot_file)
188
186
 
189
187
  # Plotting image
190
188
  data_to_plot = im.get_image_data()
@@ -195,9 +193,7 @@ def main(): # noqa: D103
195
193
 
196
194
  plot_file_name = label + "_" + tel_model.name + "_image"
197
195
  plot_file = output_dir.joinpath(plot_file_name)
198
- for f in ["pdf", "png"]:
199
- fig.savefig(str(plot_file) + "." + f, format=f, bbox_inches="tight")
200
- fig.clf()
196
+ visualize.save_figure(fig, plot_file)
201
197
 
202
198
 
203
199
  if __name__ == "__main__":
@@ -33,12 +33,13 @@ r"""
33
33
  """
34
34
 
35
35
  import logging
36
- from importlib.resources import files
36
+ import re
37
37
  from pathlib import Path
38
38
 
39
39
  import simtools.utils.general as gen
40
40
  from simtools.configuration import configurator
41
- from simtools.data_model import metadata_collector, metadata_model, validate_data
41
+ from simtools.constants import MODEL_PARAMETER_SCHEMA_PATH
42
+ from simtools.data_model import metadata_collector, schema, validate_data
42
43
 
43
44
 
44
45
  def _parse(label, description):
@@ -62,13 +63,12 @@ def _parse(label, description):
62
63
  group = config.parser.add_mutually_exclusive_group(required=True)
63
64
  group.add_argument("--file_name", help="File to be validated")
64
65
  group.add_argument(
65
- "--model_parameters_directory",
66
+ "--file_directory",
66
67
  help=(
67
- "Directory with json files with model parameters to be validated."
68
- "All *.json files in the directory will be validated."
69
- "Schema files will be taken from simtools/schemas/model_parameters/."
70
- "Note that in this case the data_type argument is ignored"
71
- "and data_type=model_parameter is always used."
68
+ "Directory with json files to be validated. "
69
+ "If no schema file is provided, the assumption is that model "
70
+ "parameters are validated and the schema files are taken from "
71
+ f"{MODEL_PARAMETER_SCHEMA_PATH}."
72
72
  ),
73
73
  )
74
74
  config.parser.add_argument("--schema", help="Json schema file", required=False)
@@ -114,33 +114,47 @@ def _get_schema_file_name(args_dict, data_dict=None):
114
114
  return schema_file
115
115
 
116
116
 
117
- def validate_schema(args_dict, logger):
117
+ def _get_json_file_list(file_directory=None, file_name=None):
118
+ """Return list of json files in a directory."""
119
+ file_list = []
120
+ if file_directory is not None:
121
+ file_list = list(Path(file_directory).rglob("*.json"))
122
+ if not file_list:
123
+ raise FileNotFoundError(f"No files found in {file_directory}")
124
+ elif file_name is not None:
125
+ file_list = [file_name]
126
+
127
+ return file_list
128
+
129
+
130
+ def validate_dict_using_schema(args_dict, logger):
118
131
  """
119
- Validate a schema file given in yaml or json format.
132
+ Validate a schema file (or several files) given in yaml or json format.
120
133
 
121
134
  Schema is either given as command line argument, read from the meta_schema_url or from
122
135
  the metadata section of the data dictionary.
123
136
 
124
137
  """
125
- try:
126
- data = gen.collect_data_from_file(file_name=args_dict["file_name"])
127
- except FileNotFoundError as exc:
128
- logger.error(f"Error reading schema file from {args_dict['file_name']}")
129
- raise exc
130
- metadata_model.validate_schema(data, _get_schema_file_name(args_dict, data))
131
- logger.info(f"Successful validation of schema file {args_dict['file_name']}")
138
+ for file_name in _get_json_file_list(
139
+ args_dict.get("file_directory"), args_dict.get("file_name")
140
+ ):
141
+ try:
142
+ data = gen.collect_data_from_file(file_name=file_name)
143
+ except FileNotFoundError as exc:
144
+ logger.error(f"Error reading schema file from {file_name}")
145
+ raise exc
146
+ schema.validate_dict_using_schema(data, _get_schema_file_name(args_dict, data))
147
+ logger.info(f"Successful validation of file {file_name}")
132
148
 
133
149
 
134
150
  def validate_data_files(args_dict, logger):
135
151
  """Validate data files."""
136
- model_parameters_directory = args_dict.get("model_parameters_directory")
137
- if model_parameters_directory is not None:
152
+ if args_dict.get("file_directory") is not None:
138
153
  tmp_args_dict = {}
139
- for file_name in Path(model_parameters_directory).rglob("*.json"):
154
+ for file_name in _get_json_file_list(args_dict.get("file_directory")):
140
155
  tmp_args_dict["file_name"] = file_name
141
- schema_file = (
142
- files("simtools") / "schemas/model_parameters" / f"{file_name.stem}.schema.yml"
143
- )
156
+ parameter_name = re.sub(r"-\d+\.\d+\.\d+", "", file_name.stem)
157
+ schema_file = schema.get_model_parameter_schema_file(f"{parameter_name}")
144
158
  tmp_args_dict["schema"] = schema_file
145
159
  tmp_args_dict["data_type"] = "model_parameter"
146
160
  tmp_args_dict["require_exact_data_type"] = args_dict["require_exact_data_type"]
@@ -182,7 +196,7 @@ def main(): # noqa: D103
182
196
  if args_dict["data_type"].lower() == "metadata":
183
197
  validate_metadata(args_dict, logger)
184
198
  elif args_dict["data_type"].lower() == "schema":
185
- validate_schema(args_dict, logger)
199
+ validate_dict_using_schema(args_dict, logger)
186
200
  else:
187
201
  validate_data_files(args_dict, logger)
188
202
 
@@ -78,6 +78,7 @@ from simtools.configuration import configurator
78
78
  from simtools.io_operations import io_handler
79
79
  from simtools.model.telescope_model import TelescopeModel
80
80
  from simtools.ray_tracing.ray_tracing import RayTracing
81
+ from simtools.visualization import visualize
81
82
 
82
83
 
83
84
  def _parse(label):
@@ -114,7 +115,7 @@ def _parse(label):
114
115
  help="Produce a multiple pages pdf file with the image plots.",
115
116
  action="store_true",
116
117
  )
117
- return config.initialize(db_config=True, simulation_model=["telescope"])
118
+ return config.initialize(db_config=True, simulation_model=["telescope", "model_version"])
118
119
 
119
120
 
120
121
  def main(): # noqa: D103
@@ -171,9 +172,7 @@ def main(): # noqa: D103
171
172
 
172
173
  plot_file_name = "_".join((label, tel_model.name, key))
173
174
  plot_file = output_dir.joinpath(plot_file_name)
174
- plt.savefig(str(plot_file) + ".pdf", format="pdf", bbox_inches="tight")
175
- plt.savefig(str(plot_file) + ".png", format="png", bbox_inches="tight")
176
- plt.clf()
175
+ visualize.save_figure(plt, plot_file)
177
176
 
178
177
  # Plotting images
179
178
  if args_dict["plot_images"]:
@@ -514,7 +514,4 @@ class CameraEfficiency:
514
514
  plot_file = self.output_dir.joinpath(
515
515
  self.label + "_" + self.telescope_model.name + "_" + plot_title
516
516
  )
517
- for f in ["pdf", "png"]:
518
- fig.savefig(str(plot_file) + "." + f, format=f, bbox_inches="tight")
519
- self._logger.info(f"Plotted {plot_title} efficiency in {plot_file}")
520
- fig.clf()
517
+ visualize.save_figure(fig, plot_file, log_title=f"{plot_title} efficiency")