gammasimtools 0.8.2__py3-none-any.whl → 0.9.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 (65) hide show
  1. {gammasimtools-0.8.2.dist-info → gammasimtools-0.9.0.dist-info}/METADATA +3 -3
  2. {gammasimtools-0.8.2.dist-info → gammasimtools-0.9.0.dist-info}/RECORD +64 -59
  3. {gammasimtools-0.8.2.dist-info → gammasimtools-0.9.0.dist-info}/WHEEL +1 -1
  4. {gammasimtools-0.8.2.dist-info → gammasimtools-0.9.0.dist-info}/entry_points.txt +2 -0
  5. simtools/_version.py +2 -2
  6. simtools/applications/convert_all_model_parameters_from_simtel.py +1 -1
  7. simtools/applications/convert_geo_coordinates_of_array_elements.py +8 -9
  8. simtools/applications/convert_model_parameter_from_simtel.py +1 -1
  9. simtools/applications/db_add_model_parameters_from_repository_to_db.py +2 -10
  10. simtools/applications/db_add_value_from_json_to_db.py +1 -9
  11. simtools/applications/db_get_array_layouts_from_db.py +3 -1
  12. simtools/applications/db_get_parameter_from_db.py +1 -1
  13. simtools/applications/derive_mirror_rnda.py +10 -1
  14. simtools/applications/derive_psf_parameters.py +1 -1
  15. simtools/applications/generate_array_config.py +1 -5
  16. simtools/applications/generate_regular_arrays.py +9 -6
  17. simtools/applications/plot_array_layout.py +3 -1
  18. simtools/applications/plot_tabular_data.py +84 -0
  19. simtools/applications/production_scale_events.py +1 -2
  20. simtools/applications/simulate_light_emission.py +2 -2
  21. simtools/applications/simulate_prod.py +24 -59
  22. simtools/applications/simulate_prod_htcondor_generator.py +95 -0
  23. simtools/applications/submit_data_from_external.py +1 -1
  24. simtools/applications/validate_camera_efficiency.py +1 -1
  25. simtools/applications/validate_camera_fov.py +3 -7
  26. simtools/applications/validate_cumulative_psf.py +3 -7
  27. simtools/applications/validate_file_using_schema.py +31 -21
  28. simtools/applications/validate_optics.py +3 -4
  29. simtools/camera_efficiency.py +1 -4
  30. simtools/configuration/commandline_parser.py +7 -13
  31. simtools/configuration/configurator.py +6 -19
  32. simtools/data_model/metadata_collector.py +18 -0
  33. simtools/data_model/metadata_model.py +18 -5
  34. simtools/data_model/model_data_writer.py +1 -1
  35. simtools/data_model/validate_data.py +67 -10
  36. simtools/db/db_handler.py +92 -315
  37. simtools/io_operations/legacy_data_handler.py +61 -0
  38. simtools/job_execution/htcondor_script_generator.py +133 -0
  39. simtools/job_execution/job_manager.py +77 -50
  40. simtools/model/camera.py +4 -2
  41. simtools/model/model_parameter.py +40 -10
  42. simtools/model/site_model.py +1 -1
  43. simtools/ray_tracing/mirror_panel_psf.py +47 -27
  44. simtools/runners/corsika_runner.py +14 -3
  45. simtools/runners/runner_services.py +3 -3
  46. simtools/runners/simtel_runner.py +27 -8
  47. simtools/schemas/integration_tests_config.metaschema.yml +15 -5
  48. simtools/schemas/model_parameter.metaschema.yml +90 -2
  49. simtools/schemas/model_parameters/effective_focal_length.schema.yml +31 -1
  50. simtools/simtel/simtel_table_reader.py +410 -0
  51. simtools/simtel/simulator_camera_efficiency.py +6 -4
  52. simtools/simtel/simulator_light_emission.py +2 -2
  53. simtools/simtel/simulator_ray_tracing.py +1 -2
  54. simtools/simulator.py +80 -33
  55. simtools/testing/configuration.py +12 -8
  56. simtools/testing/helpers.py +5 -5
  57. simtools/testing/validate_output.py +26 -26
  58. simtools/utils/general.py +50 -3
  59. simtools/utils/names.py +2 -2
  60. simtools/utils/value_conversion.py +9 -1
  61. simtools/visualization/plot_tables.py +106 -0
  62. simtools/visualization/visualize.py +43 -5
  63. simtools/db/db_from_repo_handler.py +0 -106
  64. {gammasimtools-0.8.2.dist-info → gammasimtools-0.9.0.dist-info}/LICENSE +0 -0
  65. {gammasimtools-0.8.2.dist-info → gammasimtools-0.9.0.dist-info}/top_level.txt +0 -0
simtools/db/db_handler.py CHANGED
@@ -2,16 +2,19 @@
2
2
 
3
3
  import logging
4
4
  import re
5
+ from importlib.resources import files
5
6
  from pathlib import Path
6
7
  from threading import Lock
7
8
 
8
9
  import gridfs
10
+ import jsonschema
9
11
  from bson.objectid import ObjectId
10
12
  from packaging.version import Version
11
13
  from pymongo import ASCENDING, MongoClient
12
14
  from pymongo.errors import BulkWriteError
13
15
 
14
- from simtools.db import db_array_elements, db_from_repo_handler
16
+ from simtools.data_model import validate_data
17
+ from simtools.db import db_array_elements
15
18
  from simtools.io_operations import io_handler
16
19
  from simtools.utils import names, value_conversion
17
20
 
@@ -24,6 +27,35 @@ logging.getLogger("pymongo").setLevel(logging.WARNING)
24
27
  # The above comment is because pylint does not know that DatabaseHandler.db_client is subscriptable
25
28
 
26
29
 
30
+ jsonschema_db_dict = {
31
+ "$schema": "https://json-schema.org/draft/2020-12/schema#",
32
+ "type": "object",
33
+ "description": "MongoDB configuration",
34
+ "properties": {
35
+ "db_server": {"type": "string", "description": "DB server address"},
36
+ "db_api_port": {
37
+ "type": "integer",
38
+ "minimum": 1,
39
+ "maximum": 65535,
40
+ "default": 27017,
41
+ "description": "Port to use",
42
+ },
43
+ "db_api_user": {"type": "string", "description": "API username"},
44
+ "db_api_pw": {"type": "string", "description": "Password for the API user"},
45
+ "db_api_authentication_database": {
46
+ "type": "string",
47
+ "default": "admin",
48
+ "description": "DB with user info (optional)",
49
+ },
50
+ "db_simulation_model": {
51
+ "type": "string",
52
+ "description": "Name of simulation model database",
53
+ },
54
+ },
55
+ "required": ["db_server", "db_api_port", "db_api_user", "db_api_pw", "db_simulation_model"],
56
+ }
57
+
58
+
27
59
  class DatabaseHandler:
28
60
  """
29
61
  DatabaseHandler provides the interface to the DB.
@@ -31,13 +63,7 @@ class DatabaseHandler:
31
63
  Parameters
32
64
  ----------
33
65
  mongo_db_config: dict
34
- Dictionary with the MongoDB configuration with the following entries:
35
- "db_server" - DB server address
36
- "db_api_port" - Port to use
37
- "db_api_user" - API username
38
- "db_api_pw" - Password for the API user
39
- "db_api_authentication_database" - DB with user info (optional, default is "admin")
40
- "db_simulation_model" - Name of simulation model database
66
+ Dictionary with the MongoDB configuration (see jsonschema_db_dict for details).
41
67
  """
42
68
 
43
69
  DB_CTA_SIMULATION_MODEL_DESCRIPTIONS = "CTA-Simulation-Model-Descriptions"
@@ -56,7 +82,7 @@ class DatabaseHandler:
56
82
  """Initialize the DatabaseHandler class."""
57
83
  self._logger = logging.getLogger(__name__)
58
84
 
59
- self.mongo_db_config = mongo_db_config
85
+ self.mongo_db_config = self._validate_mongo_db_config(mongo_db_config)
60
86
  self.io_handler = io_handler.IOHandler()
61
87
  self.list_of_collections = {}
62
88
 
@@ -70,6 +96,16 @@ class DatabaseHandler:
70
96
  with lock:
71
97
  DatabaseHandler.db_client = self._open_mongo_db()
72
98
 
99
+ def _validate_mongo_db_config(self, mongo_db_config):
100
+ """Validate the MongoDB configuration."""
101
+ if mongo_db_config is None or all(value is None for value in mongo_db_config.values()):
102
+ return None
103
+ try:
104
+ jsonschema.validate(instance=mongo_db_config, schema=jsonschema_db_dict)
105
+ return mongo_db_config
106
+ except jsonschema.exceptions.ValidationError as err:
107
+ raise ValueError("Invalid MongoDB configuration") from err
108
+
73
109
  def _open_mongo_db(self):
74
110
  """
75
111
  Open a connection to MongoDB and return the client to read/write to the DB with.
@@ -83,25 +119,21 @@ class DatabaseHandler:
83
119
  KeyError
84
120
  If the DB configuration is invalid
85
121
  """
86
- try:
87
- direct_connection = self.mongo_db_config["db_server"] in (
88
- "localhost",
89
- "simtools-mongodb",
90
- )
91
- return MongoClient(
92
- self.mongo_db_config["db_server"],
93
- port=self.mongo_db_config["db_api_port"],
94
- username=self.mongo_db_config["db_api_user"],
95
- password=self.mongo_db_config["db_api_pw"],
96
- authSource=self.mongo_db_config.get("db_api_authentication_database", "admin"),
97
- directConnection=direct_connection,
98
- ssl=not direct_connection,
99
- tlsallowinvalidhostnames=True,
100
- tlsallowinvalidcertificates=True,
101
- )
102
- except KeyError:
103
- self._logger.error("Invalid setting of DB configuration")
104
- raise
122
+ direct_connection = self.mongo_db_config["db_server"] in (
123
+ "localhost",
124
+ "simtools-mongodb",
125
+ )
126
+ return MongoClient(
127
+ self.mongo_db_config["db_server"],
128
+ port=self.mongo_db_config["db_api_port"],
129
+ username=self.mongo_db_config["db_api_user"],
130
+ password=self.mongo_db_config["db_api_pw"],
131
+ authSource=self.mongo_db_config.get("db_api_authentication_database", "admin"),
132
+ directConnection=direct_connection,
133
+ ssl=not direct_connection,
134
+ tlsallowinvalidhostnames=True,
135
+ tlsallowinvalidcertificates=True,
136
+ )
105
137
 
106
138
  def _find_latest_simulation_model_db(self):
107
139
  """
@@ -207,15 +239,6 @@ class DatabaseHandler:
207
239
  only_applicable=only_applicable,
208
240
  )
209
241
  )
210
- if self.mongo_db_config.get("db_simulation_model_url", None) is not None:
211
- pars = db_from_repo_handler.update_model_parameters_from_repo(
212
- parameters=pars,
213
- site=_site,
214
- parameter_collection=collection,
215
- array_element_name=array_element,
216
- model_version=_model_version,
217
- db_simulation_model_url=self.mongo_db_config.get("db_simulation_model_url"),
218
- )
219
242
  DatabaseHandler.model_parameters_cached[_array_elements_cache_key] = pars
220
243
 
221
244
  return pars
@@ -278,7 +301,7 @@ class DatabaseHandler:
278
301
  Parameters
279
302
  ----------
280
303
  parameters: dict
281
- Dict of model parameters
304
+ Dict of model parameters.
282
305
  dest: str or Path
283
306
  Location where to write the files to.
284
307
 
@@ -296,10 +319,6 @@ class DatabaseHandler:
296
319
  continue
297
320
  file = self._get_file_mongo_db(self._get_db_name(), info["value"])
298
321
  self._write_file_from_mongo_to_disk(self._get_db_name(), dest, file)
299
- if self.mongo_db_config.get("db_simulation_model_url", None) is not None:
300
- self._logger.warning(
301
- "Exporting model files from simulation model repository not yet implemented"
302
- )
303
322
 
304
323
  @staticmethod
305
324
  def _is_file(value):
@@ -406,24 +425,14 @@ class DatabaseHandler:
406
425
  except KeyError:
407
426
  pass
408
427
 
409
- _pars = self._get_site_parameters_mongo_db(
410
- _db_name,
411
- _site,
412
- _model_version,
413
- only_applicable,
414
- )
415
- # update simulation model using repository
416
- if self.mongo_db_config.get("db_simulation_model_url", None) is not None:
417
- _pars = db_from_repo_handler.update_model_parameters_from_repo(
418
- parameters=_pars,
419
- site=_site,
420
- array_element_name=None,
421
- parameter_collection="site",
422
- model_version=_model_version,
423
- db_simulation_model_url=self.mongo_db_config.get("db_simulation_model_url", None),
428
+ DatabaseHandler.site_parameters_cached[_site_cache_key] = (
429
+ self._get_site_parameters_mongo_db(
430
+ _db_name,
431
+ _site,
432
+ _model_version,
433
+ only_applicable,
424
434
  )
425
-
426
- DatabaseHandler.site_parameters_cached[_site_cache_key] = _pars
435
+ )
427
436
  return DatabaseHandler.site_parameters_cached[_site_cache_key]
428
437
 
429
438
  def _get_site_parameters_mongo_db(self, db_name, site, model_version, only_applicable=False):
@@ -653,7 +662,7 @@ class DatabaseHandler:
653
662
  Copy a full array element configuration to a new array element name.
654
663
 
655
664
  Only a specific version is copied.
656
- (This function should be rarely used, probably only during "construction".)
665
+ This function should be rarely used and is intended to simplify unit tests.
657
666
 
658
667
  Parameters
659
668
  ----------
@@ -710,298 +719,66 @@ class DatabaseHandler:
710
719
  except BulkWriteError as exc:
711
720
  raise BulkWriteError(str(exc.details)) from exc
712
721
 
713
- def copy_documents(self, db_name, collection, query, db_to_copy_to, collection_to_copy_to=None):
714
- """
715
- Copy the documents matching to "query" to the DB "db_to_copy_to".
716
-
717
- The documents are copied to the same collection as in "db_name".
718
- (This function should be rarely used, probably only during "construction".)
719
-
720
- Parameters
721
- ----------
722
- db_name: str
723
- the name of the DB to copy from
724
- collection: str
725
- the name of the collection to copy from
726
- query: dict
727
- A dictionary with a query to search for documents to copy.
728
- For example, the query below would copy all entries of version 6.0.0
729
- from telescope LSTN-01 to "db_to_copy_to".
730
-
731
- .. code-block:: python
732
-
733
- query = {
734
- "instrument": "LSTN-01",
735
- "version": "6.0.0",
736
- }
737
- db_to_copy_to: str
738
- The name of the DB to copy to.
739
-
740
- Raises
741
- ------
742
- BulkWriteError
743
-
744
- """
745
- db_name = self._get_db_name(db_name)
746
-
747
- _collection = self.get_collection(db_name, collection)
748
- if collection_to_copy_to is None:
749
- collection_to_copy_to = collection
750
- db_entries = []
751
-
752
- for post in _collection.find(query):
753
- post.pop("_id", None)
754
- db_entries.append(post)
755
-
756
- self._logger.info(
757
- f"Copying documents matching the following query {query}\nto {db_to_copy_to}"
758
- )
759
- _collection = self.get_collection(db_to_copy_to, collection_to_copy_to)
760
- try:
761
- _collection.insert_many(db_entries)
762
- except BulkWriteError as exc:
763
- raise BulkWriteError(str(exc.details)) from exc
764
-
765
- def delete_query(self, db_name, collection, query):
766
- """
767
- Delete all entries from the DB which correspond to the provided query.
768
-
769
- (This function should be rarely used, if at all.)
770
-
771
- Parameters
772
- ----------
773
- db_name: str
774
- the name of the DB
775
- collection: str
776
- the name of the collection to copy from
777
- query: dict
778
- A dictionary listing the fields/values to delete.
779
- For example, the query below would delete the entire version 6.0.0
780
- from telescope LSTN-01.
781
-
782
- .. code-block:: python
783
-
784
- query = {
785
- "instrument": "LSTN-01",
786
- "version": "6.0.0",
787
- }
788
-
789
- """
790
- _collection = self.get_collection(db_name, collection)
791
-
792
- if "version" in query:
793
- query["version"] = self.model_version(query["version"])
794
-
795
- self._logger.info(f"Deleting {_collection.count_documents(query)} entries from {db_name}")
796
-
797
- _collection.delete_many(query)
798
-
799
- def update_parameter_field(
800
- self,
801
- db_name,
802
- model_version,
803
- parameter,
804
- field,
805
- new_value,
806
- array_element_name=None,
807
- site=None,
808
- collection_name="telescopes",
809
- ):
810
- """
811
- Update a parameter field value for a specific array element/version.
812
-
813
- This function only modifies the value of one of the following
814
- DB entries: Applicable, units, Type, items, minimum, maximum.
815
- These type of changes should be very rare. However they can
816
- be done without changing the Object ID of the entry since
817
- they are generally "harmless".
818
-
819
- Parameters
820
- ----------
821
- db_name: str
822
- the name of the DB
823
- model_version: str
824
- Which model version to update
825
- parameter: str
826
- Which parameter to update
827
- field: str
828
- Field to update (only options are Applicable, units, Type, items, minimum, maximum).
829
- If the field does not exist, it will be added.
830
- new_value: type identical to the original field type
831
- The new value to set to the field given in "field".
832
- array_element_name: str
833
- Which array element to update, if None then update a site parameter
834
- site: str, North or South
835
- Update a site parameter (the array_element_name argument must be None)
836
- collection_name: str
837
- The name of the collection in which to update the parameter.
838
-
839
- Raises
840
- ------
841
- ValueError
842
- if field not in allowed fields
843
-
844
- """
845
- db_name = self._get_db_name(db_name)
846
- allowed_fields = ["applicable", "unit", "type", "items", "minimum", "maximum"]
847
- if field not in allowed_fields:
848
- raise ValueError(f"The field {field} must be one of {', '.join(allowed_fields)}")
849
-
850
- collection = self.get_collection(db_name, collection_name)
851
- _model_version = self.model_version(model_version, db_name)
852
-
853
- query = {
854
- "version": _model_version,
855
- "parameter": parameter,
856
- }
857
- if array_element_name is not None:
858
- query["instrument"] = array_element_name
859
- logger_info = f"instrument {array_element_name}"
860
- elif site is not None and site in names.site_names():
861
- query["site"] = site
862
- logger_info = f"site {site}"
863
- else:
864
- raise ValueError("You need to specify an array element or a site.")
865
-
866
- par_entry = collection.find_one(query)
867
- if par_entry is None:
868
- self._logger.warning(
869
- f"The query {query} did not return any results. I will not make any changes."
870
- )
871
- return
872
-
873
- if field in par_entry:
874
- old_field_value = par_entry[field]
875
-
876
- if old_field_value == new_value:
877
- self._logger.warning(
878
- f"The value of the field {field} is already {new_value}. No changes necessary"
879
- )
880
- return
881
-
882
- self._logger.info(
883
- f"For {logger_info}, version {_model_version}, parameter {parameter}, "
884
- f"replacing field {field} value from {old_field_value} to {new_value}"
885
- )
886
- else:
887
- self._logger.info(
888
- f"For {logger_info}, version {_model_version}, parameter {parameter}, "
889
- f"the field {field} does not exist, adding it"
890
- )
891
-
892
- query_update = {"$set": {field: new_value}}
893
- collection.update_one(query, query_update)
894
-
895
- self._reset_parameter_cache(
896
- site=(
897
- site
898
- if site is not None
899
- else names.get_site_from_array_element_name(array_element_name)
900
- ),
901
- array_element_name=array_element_name,
902
- model_version=_model_version,
903
- )
904
-
905
722
  def add_new_parameter(
906
723
  self,
907
724
  db_name,
908
- version,
909
- parameter,
910
- value,
911
- array_element_name=None,
912
- site=None,
725
+ par_dict,
913
726
  collection_name="telescopes",
914
727
  file_prefix=None,
915
- **kwargs,
916
728
  ):
917
729
  """
918
- Add a parameter value for a specific array element.
730
+ Add a parameter dictionary for a specific array element to the DB.
919
731
 
920
- A new document will be added to the DB,
921
- with all fields taken from the input parameters.
732
+ A new document will be added to the DB, with all fields taken from the input parameters.
733
+ Parameter dictionaries are validated before submission using the corresponding schema.
922
734
 
923
735
  Parameters
924
736
  ----------
925
737
  db_name: str
926
738
  the name of the DB
927
- version: str
928
- The version of the new parameter value
929
- parameter: str
930
- Which parameter to add
931
- value: can be any type, preferably given in kwargs
932
- The value to set for the new parameter
933
- array_element_name: str
934
- The name of the array element to add a parameter to
935
- (only used if collection_name is not "sites").
936
- site: str
937
- Site name; ignored if collection_name is "telescopes".
739
+ par_dict: dict
740
+ dictionary with parameter data
938
741
  collection_name: str
939
742
  The name of the collection to add a parameter to.
940
743
  file_prefix: str or Path
941
744
  where to find files to upload to the DB
942
- kwargs: dict
943
- Any additional fields to add to the parameter
944
-
945
- Raises
946
- ------
947
- ValueError
948
- If key to collection_name is not valid.
949
-
950
745
  """
746
+ data_validator = validate_data.DataValidator(
747
+ schema_file=files("simtools")
748
+ / f"schemas/model_parameters/{par_dict['parameter']}.schema.yml",
749
+ data_dict=par_dict,
750
+ check_exact_data_type=False,
751
+ )
752
+ par_dict = data_validator.validate_and_transform(is_model_parameter=True)
753
+
951
754
  db_name = self._get_db_name(db_name)
952
755
  collection = self.get_collection(db_name, collection_name)
953
756
 
954
- db_entry = {}
955
- if any(
956
- key in collection_name
957
- for key in ["telescopes", "calibration_devices", "configuration_sim_telarray"]
958
- ):
959
- db_entry["instrument"] = names.validate_array_element_name(array_element_name)
960
- elif "sites" in collection_name:
961
- db_entry["instrument"] = names.validate_site_name(site)
962
- elif "configuration_corsika" in collection_name:
963
- db_entry["instrument"] = None
964
- else:
965
- raise ValueError(f"Cannot add parameter to collection {collection_name}")
966
-
967
- db_entry["version"] = version
968
- db_entry["parameter"] = parameter
969
- if site is not None:
970
- db_entry["site"] = names.validate_site_name(site)
971
-
972
- _base_value, _base_unit, _base_type = value_conversion.get_value_unit_type(
973
- value=value, unit_str=kwargs.get("unit", None)
757
+ par_dict["value"], _base_unit, _ = value_conversion.get_value_unit_type(
758
+ value=par_dict["value"], unit_str=par_dict.get("unit", None)
974
759
  )
975
- db_entry["value"] = _base_value
976
- if _base_unit is not None:
977
- db_entry["unit"] = _base_unit
978
- db_entry["type"] = kwargs["type"] if "type" in kwargs else _base_type
760
+ par_dict["unit"] = _base_unit if _base_unit else None
979
761
 
980
762
  files_to_add_to_db = set()
981
- db_entry["file"] = False
982
- if self._is_file(value):
983
- db_entry["file"] = True
763
+ if par_dict["file"] and par_dict["value"]:
984
764
  if file_prefix is None:
985
765
  raise FileNotFoundError(
986
766
  "The location of the file to upload, "
987
- f"corresponding to the {parameter} parameter, must be provided."
767
+ f"corresponding to the {par_dict['parameter']} parameter, must be provided."
988
768
  )
989
- file_path = Path(file_prefix).joinpath(value)
769
+ file_path = Path(file_prefix).joinpath(par_dict["value"])
990
770
  files_to_add_to_db.add(f"{file_path}")
991
771
 
992
- kwargs.pop("type", None)
993
- db_entry.update(kwargs)
994
-
995
772
  self._logger.info(
996
- f"Will add the following entry to DB {db_name} and collection {db_name}:\n{db_entry}"
773
+ f"Adding a new entry to DB {db_name} and collection {db_name}:\n{par_dict}"
997
774
  )
775
+ collection.insert_one(par_dict)
998
776
 
999
- collection.insert_one(db_entry)
1000
777
  for file_to_insert_now in files_to_add_to_db:
1001
778
  self._logger.info(f"Will also add the file {file_to_insert_now} to the DB")
1002
779
  self.insert_file_to_db(file_to_insert_now, db_name)
1003
780
 
1004
- self._reset_parameter_cache(site, array_element_name, version)
781
+ self._reset_parameter_cache(par_dict["site"], par_dict["instrument"], par_dict["version"])
1005
782
 
1006
783
  def _get_db_name(self, db_name=None):
1007
784
  """
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/python3
2
+ """Reading of legacy data files (expect that this will be obsolete in future)."""
3
+
4
+ import logging
5
+
6
+ from astropy.table import Table
7
+
8
+ __all__ = [
9
+ "read_legacy_data_as_table",
10
+ "read_legacy_lst_single_pe",
11
+ ]
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def read_legacy_data_as_table(file_path, file_type):
17
+ """
18
+ Read legacy data file.
19
+
20
+ Parameters
21
+ ----------
22
+ file_path: Path
23
+ Path to the legacy data file.
24
+ file_type: str
25
+ Type of legacy data file.
26
+
27
+ Returns
28
+ -------
29
+ Table
30
+ Astropy table.
31
+
32
+ Raises
33
+ ------
34
+ ValueError
35
+ If unsupported legacy data file type.
36
+ """
37
+ logger.debug(f"Reading legacy data file of type {file_type} from {file_path}")
38
+
39
+ try:
40
+ return globals()[f"read_{file_type}"](file_path)
41
+ except KeyError as exc:
42
+ raise ValueError(f"Unsupported legacy data file type: {file_type}") from exc
43
+
44
+
45
+ def read_legacy_lst_single_pe(file_path):
46
+ """
47
+ Read LST single pe file (in legacy data format).
48
+
49
+ File contains two columns: amplitude (in units of single p.e) and response.
50
+
51
+ Parameters
52
+ ----------
53
+ file_path: Path
54
+ Path to the legacy data file.
55
+
56
+ Returns
57
+ -------
58
+ Table
59
+ Astropy table.
60
+ """
61
+ return Table.read(file_path, format="ascii.csv", names=("amplitude", "response"))