ctao-calibpipe 0.3.0rc2__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 (105) hide show
  1. calibpipe/__init__.py +5 -0
  2. calibpipe/_dev_version/__init__.py +9 -0
  3. calibpipe/_version.py +34 -0
  4. calibpipe/atmosphere/__init__.py +1 -0
  5. calibpipe/atmosphere/atmosphere_containers.py +109 -0
  6. calibpipe/atmosphere/meteo_data_handlers.py +485 -0
  7. calibpipe/atmosphere/models/README.md +14 -0
  8. calibpipe/atmosphere/models/__init__.py +1 -0
  9. calibpipe/atmosphere/models/macobac.ecsv +23 -0
  10. calibpipe/atmosphere/models/reference_MDPs/__init__.py +1 -0
  11. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_intermediate.ecsv +8 -0
  12. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_summer.ecsv +8 -0
  13. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-north_winter.ecsv +8 -0
  14. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-south_summer.ecsv +8 -0
  15. calibpipe/atmosphere/models/reference_MDPs/ref_density_at_15km_ctao-south_winter.ecsv +8 -0
  16. calibpipe/atmosphere/models/reference_atmospheres/__init__.py +1 -0
  17. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_intermediate.ecsv +73 -0
  18. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_summer.ecsv +73 -0
  19. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-north_winter.ecsv +73 -0
  20. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-south_summer.ecsv +73 -0
  21. calibpipe/atmosphere/models/reference_atmospheres/reference_atmo_model_v0_ctao-south_winter.ecsv +73 -0
  22. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/__init__.py +1 -0
  23. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_intermediate.ecsv +857 -0
  24. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_summer.ecsv +857 -0
  25. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-north_winter.ecsv +857 -0
  26. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-south_summer.ecsv +857 -0
  27. calibpipe/atmosphere/models/reference_rayleigh_scattering_profiles/reference_rayleigh_extinction_profile_v0_ctao-south_winter.ecsv +857 -0
  28. calibpipe/atmosphere/templates/request_templates/__init__.py +1 -0
  29. calibpipe/atmosphere/templates/request_templates/copernicus.json +11 -0
  30. calibpipe/atmosphere/templates/request_templates/gdas.json +12 -0
  31. calibpipe/core/__init__.py +39 -0
  32. calibpipe/core/common_metadata_containers.py +198 -0
  33. calibpipe/core/exceptions.py +87 -0
  34. calibpipe/database/__init__.py +24 -0
  35. calibpipe/database/adapter/__init__.py +23 -0
  36. calibpipe/database/adapter/adapter.py +80 -0
  37. calibpipe/database/adapter/database_containers/__init__.py +63 -0
  38. calibpipe/database/adapter/database_containers/atmosphere.py +199 -0
  39. calibpipe/database/adapter/database_containers/common_metadata.py +150 -0
  40. calibpipe/database/adapter/database_containers/container_map.py +59 -0
  41. calibpipe/database/adapter/database_containers/observatory.py +61 -0
  42. calibpipe/database/adapter/database_containers/table_version_manager.py +39 -0
  43. calibpipe/database/adapter/database_containers/throughput.py +30 -0
  44. calibpipe/database/adapter/database_containers/version_control.py +17 -0
  45. calibpipe/database/connections/__init__.py +28 -0
  46. calibpipe/database/connections/calibpipe_database.py +60 -0
  47. calibpipe/database/connections/postgres_utils.py +97 -0
  48. calibpipe/database/connections/sql_connection.py +103 -0
  49. calibpipe/database/connections/user_confirmation.py +19 -0
  50. calibpipe/database/interfaces/__init__.py +71 -0
  51. calibpipe/database/interfaces/hashable_row_data.py +54 -0
  52. calibpipe/database/interfaces/queries.py +180 -0
  53. calibpipe/database/interfaces/sql_column_info.py +67 -0
  54. calibpipe/database/interfaces/sql_metadata.py +6 -0
  55. calibpipe/database/interfaces/sql_table_info.py +131 -0
  56. calibpipe/database/interfaces/table_handler.py +333 -0
  57. calibpipe/database/interfaces/types.py +96 -0
  58. calibpipe/telescope/throughput/containers.py +66 -0
  59. calibpipe/tests/conftest.py +274 -0
  60. calibpipe/tests/data/atmosphere/molecular_atmosphere/__init__.py +0 -0
  61. calibpipe/tests/data/atmosphere/molecular_atmosphere/contemporary_MDP.ecsv +34 -0
  62. calibpipe/tests/data/atmosphere/molecular_atmosphere/macobac.csv +852 -0
  63. calibpipe/tests/data/atmosphere/molecular_atmosphere/macobac.ecsv +23 -0
  64. calibpipe/tests/data/atmosphere/molecular_atmosphere/merged_file.ecsv +1082 -0
  65. calibpipe/tests/data/atmosphere/molecular_atmosphere/meteo_data_copernicus.ecsv +1082 -0
  66. calibpipe/tests/data/atmosphere/molecular_atmosphere/meteo_data_gdas.ecsv +66 -0
  67. calibpipe/tests/data/atmosphere/molecular_atmosphere/observatory_configurations.json +71 -0
  68. calibpipe/tests/data/utils/__init__.py +0 -0
  69. calibpipe/tests/data/utils/meteo_data_winter_and_summer.ecsv +12992 -0
  70. calibpipe/tests/test_conftest_data.py +200 -0
  71. calibpipe/tests/unittests/array/test_cross_calibration.py +412 -0
  72. calibpipe/tests/unittests/atmosphere/astral_testing.py +107 -0
  73. calibpipe/tests/unittests/atmosphere/test_meteo_data_handler.py +775 -0
  74. calibpipe/tests/unittests/atmosphere/test_molecular_atmosphere.py +327 -0
  75. calibpipe/tests/unittests/database/test_table_handler.py +163 -0
  76. calibpipe/tests/unittests/database/test_types.py +38 -0
  77. calibpipe/tests/unittests/telescope/camera/test_calculate_camcalib_coefficients.py +456 -0
  78. calibpipe/tests/unittests/telescope/camera/test_produce_camcalib_test_data.py +37 -0
  79. calibpipe/tests/unittests/telescope/throughput/test_muon_throughput_calibrator.py +693 -0
  80. calibpipe/tests/unittests/test_bootstrap_db.py +79 -0
  81. calibpipe/tests/unittests/utils/test_observatory.py +309 -0
  82. calibpipe/tools/atmospheric_base_tool.py +78 -0
  83. calibpipe/tools/atmospheric_model_db_loader.py +181 -0
  84. calibpipe/tools/basic_tool_with_db.py +38 -0
  85. calibpipe/tools/camcalib_test_data.py +374 -0
  86. calibpipe/tools/camera_calibrator.py +462 -0
  87. calibpipe/tools/contemporary_mdp_producer.py +87 -0
  88. calibpipe/tools/init_db.py +37 -0
  89. calibpipe/tools/macobac_calculator.py +82 -0
  90. calibpipe/tools/molecular_atmospheric_model_producer.py +197 -0
  91. calibpipe/tools/muon_throughput_calculator.py +219 -0
  92. calibpipe/tools/observatory_data_db_loader.py +71 -0
  93. calibpipe/tools/reference_atmospheric_model_selector.py +201 -0
  94. calibpipe/tools/telescope_cross_calibration_calculator.py +721 -0
  95. calibpipe/utils/__init__.py +10 -0
  96. calibpipe/utils/observatory.py +486 -0
  97. calibpipe/utils/observatory_containers.py +26 -0
  98. calibpipe/version.py +24 -0
  99. ctao_calibpipe-0.3.0rc2.dist-info/METADATA +92 -0
  100. ctao_calibpipe-0.3.0rc2.dist-info/RECORD +105 -0
  101. ctao_calibpipe-0.3.0rc2.dist-info/WHEEL +5 -0
  102. ctao_calibpipe-0.3.0rc2.dist-info/entry_points.txt +12 -0
  103. ctao_calibpipe-0.3.0rc2.dist-info/licenses/AUTHORS.md +13 -0
  104. ctao_calibpipe-0.3.0rc2.dist-info/licenses/LICENSE +21 -0
  105. ctao_calibpipe-0.3.0rc2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,199 @@
1
+ """Atmospheric SQL table info."""
2
+
3
+ from sqlalchemy.schema import ForeignKeyConstraint
4
+
5
+ from ....atmosphere.atmosphere_containers import (
6
+ AtmosphericModelContainer,
7
+ MacobacContainer,
8
+ MolecularAtmosphericProfileContainer,
9
+ MolecularAtmosphericProfileMetaContainer,
10
+ MolecularDensityContainer,
11
+ RayleighExtinctionContainer,
12
+ SelectedAtmosphericModelContainer,
13
+ )
14
+ from ...interfaces.sql_column_info import SQLColumnInfo
15
+ from ...interfaces.sql_metadata import sql_metadata
16
+ from ...interfaces.sql_table_info import SQLTableInfo
17
+ from ...interfaces.types import (
18
+ ArrayF1D,
19
+ ArrayF2D,
20
+ Boolean,
21
+ Date,
22
+ Float,
23
+ Integer,
24
+ String,
25
+ )
26
+ from .container_map import ContainerMap
27
+
28
+ atmospheric_model_sql_info = SQLTableInfo(
29
+ table_name="AtmosphericModel",
30
+ metadata=sql_metadata,
31
+ columns=[
32
+ SQLColumnInfo("start", Date),
33
+ SQLColumnInfo("stop", Date),
34
+ SQLColumnInfo("version", String, primary_key=True),
35
+ SQLColumnInfo("current", Boolean),
36
+ SQLColumnInfo("season", String),
37
+ SQLColumnInfo("name_Observatory", String, nullable=False),
38
+ SQLColumnInfo("version_Observatory", Integer, nullable=False),
39
+ ],
40
+ constraints=[
41
+ ForeignKeyConstraint(
42
+ ["name_Observatory", "version_Observatory"],
43
+ ["Observatory.name", "Observatory.version"],
44
+ )
45
+ ],
46
+ )
47
+
48
+ mdp_sql_info = SQLTableInfo(
49
+ table_name="MolecularDensity",
50
+ metadata=sql_metadata,
51
+ columns=[
52
+ SQLColumnInfo("season", String),
53
+ SQLColumnInfo("density", Float, unit="1/cm^3"),
54
+ SQLColumnInfo("version", String, primary_key=True),
55
+ ],
56
+ constraints=[
57
+ ForeignKeyConstraint(
58
+ [
59
+ "version",
60
+ ],
61
+ [
62
+ "AtmosphericModel.version",
63
+ ],
64
+ )
65
+ ],
66
+ )
67
+
68
+ map_meta_sql_info = SQLTableInfo(
69
+ table_name="MolecularAtmosphericProfileMeta",
70
+ metadata=sql_metadata,
71
+ columns=[
72
+ SQLColumnInfo("data_assimilation_system", String),
73
+ SQLColumnInfo("dataset", String),
74
+ SQLColumnInfo("description", String),
75
+ SQLColumnInfo("version", String, primary_key=True),
76
+ ],
77
+ constraints=[
78
+ ForeignKeyConstraint(
79
+ [
80
+ "version",
81
+ ],
82
+ [
83
+ "AtmosphericModel.version",
84
+ ],
85
+ )
86
+ ],
87
+ )
88
+
89
+ map_sql_info = SQLTableInfo(
90
+ table_name="MolecularAtmosphericProfile",
91
+ metadata=sql_metadata,
92
+ columns=[
93
+ SQLColumnInfo("altitude", ArrayF1D, unit="km"),
94
+ SQLColumnInfo("pressure", ArrayF1D, unit="hPa"),
95
+ SQLColumnInfo("temperature", ArrayF1D, unit="K"),
96
+ SQLColumnInfo("partial_water_pressure", ArrayF1D),
97
+ SQLColumnInfo("refractive_index_m_1", ArrayF1D),
98
+ SQLColumnInfo("atmospheric_density", ArrayF1D, unit="g/cm^3"),
99
+ SQLColumnInfo("atmospheric_thickness", ArrayF1D, unit="g/cm^2"),
100
+ SQLColumnInfo("version", String, primary_key=True),
101
+ ],
102
+ constraints=[
103
+ ForeignKeyConstraint(
104
+ [
105
+ "version",
106
+ ],
107
+ [
108
+ "AtmosphericModel.version",
109
+ ],
110
+ )
111
+ ],
112
+ )
113
+
114
+ macobac_sql_info = SQLTableInfo(
115
+ table_name="MACOBAC",
116
+ metadata=sql_metadata,
117
+ columns=[
118
+ SQLColumnInfo("co2_concentration", Float, unit="ppm"),
119
+ SQLColumnInfo("estimation_date", Date),
120
+ SQLColumnInfo("version", String, primary_key=True),
121
+ ],
122
+ constraints=[
123
+ ForeignKeyConstraint(
124
+ [
125
+ "version",
126
+ ],
127
+ [
128
+ "AtmosphericModel.version",
129
+ ],
130
+ )
131
+ ],
132
+ )
133
+
134
+ rayleigh_extinction_sql_info = SQLTableInfo(
135
+ table_name="RayleighExtinction",
136
+ metadata=sql_metadata,
137
+ columns=[
138
+ SQLColumnInfo("wavelength", ArrayF1D, unit="nm"),
139
+ SQLColumnInfo("altitude", ArrayF2D, unit="km"),
140
+ SQLColumnInfo("AOD", ArrayF2D),
141
+ SQLColumnInfo("version", String, primary_key=True),
142
+ ],
143
+ constraints=[
144
+ ForeignKeyConstraint(
145
+ [
146
+ "version",
147
+ ],
148
+ [
149
+ "AtmosphericModel.version",
150
+ ],
151
+ )
152
+ ],
153
+ )
154
+
155
+ selected_model_sql_info = SQLTableInfo(
156
+ table_name="SelectedAtmosphericModel",
157
+ metadata=sql_metadata,
158
+ columns=[
159
+ SQLColumnInfo("date", Date),
160
+ SQLColumnInfo("provenance", String),
161
+ SQLColumnInfo("season", String),
162
+ SQLColumnInfo("site", String),
163
+ SQLColumnInfo("version", String),
164
+ ],
165
+ )
166
+
167
+ ContainerMap.register_container_pair(
168
+ cp_container=AtmosphericModelContainer,
169
+ db_container=atmospheric_model_sql_info,
170
+ )
171
+
172
+ ContainerMap.register_container_pair(
173
+ cp_container=MolecularAtmosphericProfileMetaContainer,
174
+ db_container=map_meta_sql_info,
175
+ )
176
+
177
+ ContainerMap.register_container_pair(
178
+ cp_container=MolecularAtmosphericProfileContainer,
179
+ db_container=map_sql_info,
180
+ )
181
+
182
+ ContainerMap.register_container_pair(
183
+ cp_container=MolecularDensityContainer,
184
+ db_container=mdp_sql_info,
185
+ )
186
+
187
+ ContainerMap.register_container_pair(
188
+ cp_container=MacobacContainer,
189
+ db_container=macobac_sql_info,
190
+ )
191
+
192
+ ContainerMap.register_container_pair(
193
+ cp_container=RayleighExtinctionContainer,
194
+ db_container=rayleigh_extinction_sql_info,
195
+ )
196
+ ContainerMap.register_container_pair(
197
+ cp_container=SelectedAtmosphericModelContainer,
198
+ db_container=selected_model_sql_info,
199
+ )
@@ -0,0 +1,150 @@
1
+ """Common Metadata SQL info."""
2
+
3
+ from sqlalchemy.schema import ForeignKeyConstraint, UniqueConstraint
4
+
5
+ from ....core.common_metadata_containers import (
6
+ ActivityReferenceMetadataContainer,
7
+ ContactReferenceMetadataContainer,
8
+ InstrumentReferenceMetadataContainer,
9
+ ProcessReferenceMetadataContainer,
10
+ ProductReferenceMetadataContainer,
11
+ ReferenceMetadataContainer,
12
+ )
13
+ from ...interfaces.sql_column_info import SQLColumnInfo
14
+ from ...interfaces.sql_metadata import sql_metadata
15
+ from ...interfaces.sql_table_info import SQLTableInfo
16
+ from ...interfaces.types import Integer, String
17
+ from .container_map import ContainerMap
18
+
19
+ reference_metadata_sql_info = SQLTableInfo(
20
+ table_name="reference_metadata",
21
+ metadata=sql_metadata,
22
+ columns=[
23
+ SQLColumnInfo("ID", Integer, unique=True, primary_key=True, autoincrement=True),
24
+ SQLColumnInfo("ID_optical_throughput", Integer),
25
+ SQLColumnInfo("version_atmospheric_model", String),
26
+ SQLColumnInfo("version", String),
27
+ ],
28
+ constraints=[
29
+ ForeignKeyConstraint(["ID_optical_throughput"], ["optical_throughput.ID"]),
30
+ ForeignKeyConstraint(
31
+ ["version_atmospheric_model"], ["AtmosphericModel.version"]
32
+ ),
33
+ UniqueConstraint("ID"),
34
+ ],
35
+ )
36
+
37
+ product_reference_metadata_sql_info = SQLTableInfo(
38
+ table_name="product_reference_metadata",
39
+ metadata=sql_metadata,
40
+ columns=[
41
+ SQLColumnInfo("ID", Integer, unique=True, primary_key=True),
42
+ SQLColumnInfo("description", String),
43
+ SQLColumnInfo("creation_time", String),
44
+ SQLColumnInfo("product_id", String),
45
+ SQLColumnInfo("data_category", String),
46
+ SQLColumnInfo("data_level", String),
47
+ SQLColumnInfo("data_association", String),
48
+ SQLColumnInfo("data_type", String),
49
+ SQLColumnInfo("data_model_name", String),
50
+ SQLColumnInfo("data_model_version", String),
51
+ SQLColumnInfo("data_model_url", String),
52
+ SQLColumnInfo("format", String),
53
+ ],
54
+ constraints=[
55
+ ForeignKeyConstraint(["ID"], ["reference_metadata.ID"]),
56
+ UniqueConstraint("ID"),
57
+ ],
58
+ )
59
+
60
+ contact_reference_metadata_sql_info = SQLTableInfo(
61
+ table_name="contact_reference_metadata",
62
+ metadata=sql_metadata,
63
+ columns=[
64
+ SQLColumnInfo("ID", Integer, unique=True, primary_key=True),
65
+ SQLColumnInfo("organization", String),
66
+ SQLColumnInfo("name", String),
67
+ SQLColumnInfo("email", String),
68
+ ],
69
+ constraints=[
70
+ ForeignKeyConstraint(["ID"], ["reference_metadata.ID"]),
71
+ UniqueConstraint("ID"),
72
+ ],
73
+ )
74
+
75
+ activity_reference_metadata_sql_info = SQLTableInfo(
76
+ table_name="activity_reference_metadata",
77
+ metadata=sql_metadata,
78
+ columns=[
79
+ SQLColumnInfo("ID", Integer, unique=True, primary_key=True),
80
+ SQLColumnInfo("activity_id", String),
81
+ SQLColumnInfo("name", String),
82
+ SQLColumnInfo("type", String),
83
+ SQLColumnInfo("start", String),
84
+ SQLColumnInfo("end", String),
85
+ SQLColumnInfo("software_name", String),
86
+ SQLColumnInfo("software_version", String),
87
+ ],
88
+ constraints=[
89
+ ForeignKeyConstraint(["ID"], ["reference_metadata.ID"]),
90
+ UniqueConstraint("ID"),
91
+ ],
92
+ )
93
+
94
+ process_reference_metadata_sql_info = SQLTableInfo(
95
+ table_name="process_reference_metadata",
96
+ metadata=sql_metadata,
97
+ columns=[
98
+ SQLColumnInfo("ID", Integer, unique=True, primary_key=True),
99
+ SQLColumnInfo("type", String),
100
+ SQLColumnInfo("subtype", String),
101
+ SQLColumnInfo("subtype_id", String),
102
+ ],
103
+ constraints=[
104
+ ForeignKeyConstraint(["ID"], ["activity_reference_metadata.ID"]),
105
+ UniqueConstraint("ID"),
106
+ ],
107
+ )
108
+
109
+ instrument_reference_metadata_sql_info = SQLTableInfo(
110
+ table_name="instrument_reference_metadata",
111
+ metadata=sql_metadata,
112
+ columns=[
113
+ SQLColumnInfo("ID", Integer, unique=True, primary_key=True),
114
+ SQLColumnInfo("site", String),
115
+ SQLColumnInfo("type", String),
116
+ SQLColumnInfo("subtype", String),
117
+ SQLColumnInfo("instrument_id", String),
118
+ ],
119
+ constraints=[ForeignKeyConstraint(["ID"], ["process_reference_metadata.ID"])],
120
+ )
121
+
122
+ ContainerMap.register_container_pair(
123
+ cp_container=ReferenceMetadataContainer,
124
+ db_container=reference_metadata_sql_info,
125
+ )
126
+
127
+ ContainerMap.register_container_pair(
128
+ cp_container=ProductReferenceMetadataContainer,
129
+ db_container=product_reference_metadata_sql_info,
130
+ )
131
+
132
+ ContainerMap.register_container_pair(
133
+ cp_container=ContactReferenceMetadataContainer,
134
+ db_container=contact_reference_metadata_sql_info,
135
+ )
136
+
137
+ ContainerMap.register_container_pair(
138
+ cp_container=ActivityReferenceMetadataContainer,
139
+ db_container=activity_reference_metadata_sql_info,
140
+ )
141
+
142
+ ContainerMap.register_container_pair(
143
+ cp_container=ProcessReferenceMetadataContainer,
144
+ db_container=process_reference_metadata_sql_info,
145
+ )
146
+
147
+ ContainerMap.register_container_pair(
148
+ cp_container=InstrumentReferenceMetadataContainer,
149
+ db_container=instrument_reference_metadata_sql_info,
150
+ )
@@ -0,0 +1,59 @@
1
+ """ContainerMap class."""
2
+
3
+ from ctapipe.core import Container
4
+
5
+ from ...interfaces.sql_table_info import SQLTableInfo
6
+
7
+
8
+ class ContainerMap:
9
+ """
10
+ Map CalibPipe and database containers.
11
+
12
+ The correspondence must be set using the `register_container_pair()`
13
+ method, called automatically for the built-in CalibPipe containers. Once
14
+ set, this map allows us to quickly get the DB container associated
15
+ to a CalilbPipe container (or contrary) to switch between the two worlds.
16
+ """
17
+
18
+ cp_container = Container
19
+
20
+ db_container_info = SQLTableInfo
21
+ cp_container_type = type[cp_container]
22
+
23
+ _cp_containers: dict[db_container_info, cp_container_type] = {}
24
+ _db_containers: dict[cp_container_type, db_container_info] = {}
25
+
26
+ @staticmethod
27
+ def map_to_cp_container(
28
+ db_container: db_container_info,
29
+ ) -> cp_container_type:
30
+ """Return the CalibPipe container corresponding to a DB container."""
31
+ return ContainerMap._cp_containers[db_container]
32
+
33
+ @staticmethod
34
+ def map_to_db_container(
35
+ cp_container: cp_container_type,
36
+ ) -> db_container_info:
37
+ """Return the DB container corresponding to a CalibPipe container."""
38
+ return ContainerMap._db_containers[cp_container]
39
+
40
+ @staticmethod
41
+ def get_cp_containers() -> list:
42
+ """Return the list of registered CalibPipe containers."""
43
+ return [*ContainerMap._db_containers]
44
+
45
+ @staticmethod
46
+ def register_container_pair(
47
+ cp_container: cp_container_type, db_container: db_container_info
48
+ ) -> None:
49
+ """Associate a CalibPipe container and a DB container."""
50
+ ContainerMap._cp_containers[db_container] = cp_container
51
+ ContainerMap._db_containers[cp_container] = db_container
52
+
53
+ @staticmethod
54
+ def unregister_container_pair(
55
+ cp_container: cp_container_type, db_container: db_container_info
56
+ ) -> None:
57
+ """Deassociate a CalibPipe container and a DB container."""
58
+ ContainerMap._db_containers[cp_container].pop(db_container, None)
59
+ ContainerMap._cp_containers[db_container].pop(cp_container, None)
@@ -0,0 +1,61 @@
1
+ """Observatory SQL table info."""
2
+
3
+ from sqlalchemy.schema import ForeignKeyConstraint, UniqueConstraint
4
+
5
+ from ....utils.observatory_containers import ObservatoryContainer, SeasonContainer
6
+ from ...interfaces.sql_column_info import SQLColumnInfo
7
+ from ...interfaces.sql_metadata import sql_metadata
8
+ from ...interfaces.sql_table_info import SQLTableInfo
9
+ from ...interfaces.types import Date, Float, Integer, String
10
+ from .container_map import ContainerMap
11
+
12
+ observatory_sql_info = SQLTableInfo(
13
+ table_name="Observatory",
14
+ metadata=sql_metadata,
15
+ columns=[
16
+ SQLColumnInfo("name", String, primary_key=True),
17
+ SQLColumnInfo("latitude", Float, unit="deg"),
18
+ SQLColumnInfo("longitude", Float, unit="deg"),
19
+ SQLColumnInfo("elevation", Integer, unit="m"),
20
+ SQLColumnInfo("version", Integer, primary_key=True),
21
+ ],
22
+ constraints=[
23
+ UniqueConstraint("name", "version", name="observatory_name_version_unique"),
24
+ ],
25
+ )
26
+
27
+ season_sql_info = SQLTableInfo(
28
+ table_name="Season",
29
+ metadata=sql_metadata,
30
+ columns=[
31
+ SQLColumnInfo("start", Date),
32
+ SQLColumnInfo("stop", Date),
33
+ SQLColumnInfo("name", String),
34
+ SQLColumnInfo("alias", String),
35
+ SQLColumnInfo("name_Observatory", String, nullable=False),
36
+ SQLColumnInfo("version_Observatory", Integer, nullable=False),
37
+ ],
38
+ constraints=[
39
+ ForeignKeyConstraint(
40
+ ["name_Observatory", "version_Observatory"],
41
+ ["Observatory.name", "Observatory.version"],
42
+ ),
43
+ UniqueConstraint(
44
+ "start",
45
+ "stop",
46
+ "name_Observatory",
47
+ "version_Observatory",
48
+ name="season_unique",
49
+ ),
50
+ ],
51
+ )
52
+
53
+ ContainerMap.register_container_pair(
54
+ cp_container=ObservatoryContainer,
55
+ db_container=observatory_sql_info,
56
+ )
57
+
58
+ ContainerMap.register_container_pair(
59
+ cp_container=SeasonContainer,
60
+ db_container=season_sql_info,
61
+ )
@@ -0,0 +1,39 @@
1
+ """TableVersionManager class."""
2
+
3
+ from sqlalchemy import Table
4
+
5
+ from ...interfaces.sql_table_info import SQLTableInfo
6
+
7
+
8
+ class TableVersionManager:
9
+ """
10
+ Create versioned tables for CalibPipe.
11
+
12
+ The main method is `apply_version()` that returns a table given
13
+ a table information and a version. The returned table will
14
+ contain the same data as the table information and have
15
+ a unique name containing the common table name and the
16
+ software version.
17
+ """
18
+
19
+ @staticmethod
20
+ def get_safe_version_string(version: str) -> str:
21
+ """Create a string from a version that is safe for table names."""
22
+ return version.replace("-", "_").replace(".", "_")
23
+
24
+ @staticmethod
25
+ def update_version(old_name: str, version: str) -> str:
26
+ """Update the DB object name with a new version number."""
27
+ safe_version = TableVersionManager.get_safe_version_string(version)
28
+ root_name = old_name.rsplit("_v")[0]
29
+ new_name = "".join([root_name, "_v", safe_version])
30
+ return new_name
31
+
32
+ @staticmethod
33
+ def apply_version(table_info: SQLTableInfo, version: str | None = None) -> Table:
34
+ """Create a DB object class with a particular version number."""
35
+ if not version:
36
+ return table_info.get_table()
37
+ safe_version = TableVersionManager.get_safe_version_string(version)
38
+ table_name = "".join([table_info.table_name, "_v", safe_version])
39
+ return table_info.get_table(table_name=table_name)
@@ -0,0 +1,30 @@
1
+ """OpticalThroughput SQL info."""
2
+
3
+ from calibpipe.telescope.throughput.containers import OpticalThoughtputContainer
4
+
5
+ from ...interfaces.sql_column_info import SQLColumnInfo
6
+ from ...interfaces.sql_metadata import sql_metadata
7
+ from ...interfaces.sql_table_info import SQLTableInfo
8
+ from ...interfaces.types import DateTime, Float, Integer, String
9
+ from .container_map import ContainerMap
10
+
11
+ optical_throughput_sql_info = SQLTableInfo(
12
+ table_name="optical_throughput",
13
+ metadata=sql_metadata,
14
+ columns=[
15
+ SQLColumnInfo("ID", Integer, primary_key=True, autoincrement=True),
16
+ SQLColumnInfo("tel_id", Integer),
17
+ SQLColumnInfo("obs_id", Integer),
18
+ SQLColumnInfo("validity_start", DateTime(timezone=True)),
19
+ SQLColumnInfo("validity_end", DateTime(timezone=True)),
20
+ SQLColumnInfo("optical_throughput_coefficient", Float),
21
+ SQLColumnInfo("optical_throughput_coefficient_std", Float),
22
+ SQLColumnInfo("method", String),
23
+ SQLColumnInfo("n_events", Integer),
24
+ ],
25
+ )
26
+
27
+ ContainerMap.register_container_pair(
28
+ cp_container=OpticalThoughtputContainer,
29
+ db_container=optical_throughput_sql_info,
30
+ )
@@ -0,0 +1,17 @@
1
+ """SQL info for run metadata."""
2
+
3
+ from ...interfaces.sql_column_info import SQLColumnInfo
4
+ from ...interfaces.sql_metadata import sql_metadata
5
+ from ...interfaces.sql_table_info import SQLTableInfo
6
+ from ...interfaces.types import DateTime, String
7
+
8
+ version_control_sql_info = SQLTableInfo(
9
+ table_name="version_control_table",
10
+ metadata=sql_metadata,
11
+ columns=[
12
+ SQLColumnInfo("name", String),
13
+ SQLColumnInfo("version", String),
14
+ SQLColumnInfo("validity_start", DateTime(timezone=True)),
15
+ SQLColumnInfo("validity_end", DateTime(timezone=True)),
16
+ ],
17
+ )
@@ -0,0 +1,28 @@
1
+ """
2
+ Connection utilities for the database.
3
+
4
+ The framework used here is `sqlachemy` that can be used with
5
+ different engines and dialects. For now the calibration data
6
+ is stored in a `PostgreSQL` database and accessed using the
7
+ `psycopg` dialect.
8
+
9
+ The main connection object is the :class:`SQLConnection` that provides the
10
+ interface to a SQL database, not knowing which engine it is
11
+ (can be `Postgres`, `MySQL`, `Oracle` etc.).
12
+
13
+ To use the :class:`SQLConnection` with a different DB system or dialect,
14
+ it is enough to change the uri and generate the relevant one
15
+ following the example of the postgres uri.
16
+ """
17
+
18
+ from .calibpipe_database import CalibPipeDatabase
19
+ from .postgres_utils import get_postgres_uri
20
+ from .sql_connection import SQLConnection
21
+ from .user_confirmation import get_user_confirmation
22
+
23
+ __all__ = [
24
+ "SQLConnection",
25
+ "get_user_confirmation",
26
+ "get_postgres_uri",
27
+ "CalibPipeDatabase",
28
+ ]
@@ -0,0 +1,60 @@
1
+ """CalibPipeDatabase class."""
2
+
3
+ from .postgres_utils import (
4
+ get_postgres_uri,
5
+ )
6
+ from .sql_connection import SQLConnection
7
+
8
+
9
+ class CalibPipeDatabase(SQLConnection):
10
+ """
11
+ CalibPipeDatabase connection. For now `SQLConnection` (`PostgreSQL+psycopg`).
12
+
13
+ This class simply creates a valid URI from named parameters to create the
14
+ particular instance of DB used for CalibPipe data and provides no additional
15
+ interface.
16
+
17
+ A few built-in queries can be found in the module
18
+ :mod:`queries<calibpipe.database.interfaces.queries>`.
19
+
20
+ Attributes
21
+ ----------
22
+ user: str
23
+ Username used to connect to the database.
24
+
25
+ database: str
26
+ Name of the database with which the connection must be established.
27
+
28
+ password: str
29
+ Password for the given user.
30
+
31
+ host: str, default=`localhost`
32
+ Database host.
33
+
34
+ port: Optional[int], default=None
35
+ Database port.
36
+
37
+ autocommit: bool, default=False
38
+ Tell if the modifications to the DB must be committed automatically when the
39
+ connection closes. Default is `False`, in this case the `commit()` method
40
+ has to be called explicitly.
41
+
42
+ """
43
+
44
+ def __init__(
45
+ self,
46
+ user: str,
47
+ database: str,
48
+ password: str,
49
+ host: str = "localhost",
50
+ port: int | None = None,
51
+ autocommit: bool = False,
52
+ ) -> None:
53
+ """Initialize the database connection."""
54
+ uri = get_postgres_uri(
55
+ user=user, database=database, passwd=password, host=host, port=port
56
+ )
57
+ super().__init__(
58
+ uri=uri,
59
+ autocommit=autocommit,
60
+ )