ctao-calibpipe 0.1.0rc8__py3-none-any.whl → 0.2.0rc1__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.
Potentially problematic release.
This version of ctao-calibpipe might be problematic. Click here for more details.
- calibpipe/_version.py +2 -2
- calibpipe/core/common_metadata_containers.py +3 -0
- calibpipe/database/adapter/adapter.py +1 -1
- calibpipe/database/adapter/database_containers/__init__.py +2 -0
- calibpipe/database/adapter/database_containers/common_metadata.py +2 -0
- calibpipe/database/adapter/database_containers/throughput.py +30 -0
- calibpipe/database/interfaces/table_handler.py +79 -97
- calibpipe/telescope/throughput/containers.py +59 -0
- calibpipe/tests/unittests/array/test_cross_calibration.py +417 -0
- calibpipe/tests/unittests/database/test_table_handler.py +95 -0
- calibpipe/tests/unittests/telescope/camera/test_calculate_camcalib_coefficients.py +347 -0
- calibpipe/tests/unittests/telescope/camera/test_produce_camcalib_test_data.py +42 -0
- calibpipe/tests/unittests/telescope/throughput/test_muon_throughput_calibrator.py +189 -0
- calibpipe/tools/camcalib_test_data.py +361 -0
- calibpipe/tools/camera_calibrator.py +558 -0
- calibpipe/tools/muon_throughput_calculator.py +239 -0
- calibpipe/tools/telescope_cross_calibration_calculator.py +721 -0
- {ctao_calibpipe-0.1.0rc8.dist-info → ctao_calibpipe-0.2.0rc1.dist-info}/METADATA +3 -2
- {ctao_calibpipe-0.1.0rc8.dist-info → ctao_calibpipe-0.2.0rc1.dist-info}/RECORD +24 -14
- {ctao_calibpipe-0.1.0rc8.dist-info → ctao_calibpipe-0.2.0rc1.dist-info}/WHEEL +1 -1
- {ctao_calibpipe-0.1.0rc8.dist-info → ctao_calibpipe-0.2.0rc1.dist-info}/entry_points.txt +4 -0
- {ctao_calibpipe-0.1.0rc8.dist-info → ctao_calibpipe-0.2.0rc1.dist-info}/licenses/AUTHORS.md +0 -0
- {ctao_calibpipe-0.1.0rc8.dist-info → ctao_calibpipe-0.2.0rc1.dist-info}/licenses/LICENSE +0 -0
- {ctao_calibpipe-0.1.0rc8.dist-info → ctao_calibpipe-0.2.0rc1.dist-info}/top_level.txt +0 -0
calibpipe/_version.py
CHANGED
|
@@ -17,5 +17,5 @@ __version__: str
|
|
|
17
17
|
__version_tuple__: VERSION_TUPLE
|
|
18
18
|
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
__version__ = version = '0.
|
|
21
|
-
__version_tuple__ = version_tuple = (0,
|
|
20
|
+
__version__ = version = '0.2.0rc1'
|
|
21
|
+
__version_tuple__ = version_tuple = (0, 2, 0, 'rc1')
|
|
@@ -22,6 +22,9 @@ class ReferenceMetadataContainer(Container):
|
|
|
22
22
|
description="Version of the reference metadata schema used in the data product",
|
|
23
23
|
type=int,
|
|
24
24
|
)
|
|
25
|
+
ID_optical_throughput = Field(
|
|
26
|
+
None, description="Optical throughput ID to serve as a foreign key", type=int
|
|
27
|
+
)
|
|
25
28
|
|
|
26
29
|
|
|
27
30
|
class ProductReferenceMetadataContainer(Container):
|
|
@@ -36,7 +36,7 @@ class Adapter:
|
|
|
36
36
|
Returns
|
|
37
37
|
-------
|
|
38
38
|
Optional[tuple[sa.Table, dict[str, Any]]]
|
|
39
|
-
None if
|
|
39
|
+
None if no DB table information is associated to the container.
|
|
40
40
|
A tuple containing the SQL table corresponding to the container,
|
|
41
41
|
and a dictionary with the valued attributes contained in the
|
|
42
42
|
CalibPipe container.
|
|
@@ -37,6 +37,7 @@ from .common_metadata import (
|
|
|
37
37
|
from .container_map import ContainerMap
|
|
38
38
|
from .observatory import observatory_sql_info, season_sql_info
|
|
39
39
|
from .table_version_manager import TableVersionManager
|
|
40
|
+
from .throughput import optical_throughput_sql_info
|
|
40
41
|
from .version_control import version_control_sql_info
|
|
41
42
|
|
|
42
43
|
__all__ = [
|
|
@@ -58,4 +59,5 @@ __all__ = [
|
|
|
58
59
|
"activity_reference_metadata_sql_info",
|
|
59
60
|
"process_reference_metadata_sql_info",
|
|
60
61
|
"instrument_reference_metadata_sql_info",
|
|
62
|
+
"optical_throughput_sql_info",
|
|
61
63
|
]
|
|
@@ -21,10 +21,12 @@ reference_metadata_sql_info = SQLTableInfo(
|
|
|
21
21
|
metadata=sql_metadata,
|
|
22
22
|
columns=[
|
|
23
23
|
SQLColumnInfo("ID", Integer, unique=True, primary_key=True, autoincrement=True),
|
|
24
|
+
SQLColumnInfo("ID_optical_throughput", Integer),
|
|
24
25
|
SQLColumnInfo("version_atmospheric_model", String),
|
|
25
26
|
SQLColumnInfo("version", String),
|
|
26
27
|
],
|
|
27
28
|
constraints=[
|
|
29
|
+
ForeignKeyConstraint(["ID_optical_throughput"], ["optical_throughput.ID"]),
|
|
28
30
|
ForeignKeyConstraint(
|
|
29
31
|
["version_atmospheric_model"], ["AtmosphericModel.version"]
|
|
30
32
|
),
|
|
@@ -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
|
+
)
|
|
@@ -9,8 +9,6 @@ import sqlalchemy as sa
|
|
|
9
9
|
from astropy.table import QTable
|
|
10
10
|
from ctapipe.core import Container
|
|
11
11
|
|
|
12
|
-
import calibpipe.core.common_metadata_containers as common_metadata_module
|
|
13
|
-
|
|
14
12
|
from ...core.exceptions import DBStorageError
|
|
15
13
|
from ..adapter.adapter import Adapter
|
|
16
14
|
from ..adapter.database_containers.container_map import ContainerMap
|
|
@@ -235,36 +233,38 @@ class TableHandler:
|
|
|
235
233
|
raise DBStorageError("Issues with connection to the CalibPipe DB")
|
|
236
234
|
|
|
237
235
|
@staticmethod
|
|
238
|
-
def upload_data(
|
|
236
|
+
def upload_data(
|
|
237
|
+
calibpipe_data_container: Container,
|
|
238
|
+
metadata: list[Container] | None,
|
|
239
|
+
connection: CalibPipeDatabase,
|
|
240
|
+
) -> None:
|
|
239
241
|
"""
|
|
240
|
-
|
|
242
|
+
Upload data and optional metadata to the database.
|
|
241
243
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
and transfer the final metadata collection to this function.
|
|
244
|
+
This method uploads the provided data to the main database table and,
|
|
245
|
+
if provided, associates the metadata with the inserted data row.
|
|
245
246
|
|
|
246
247
|
Parameters
|
|
247
248
|
----------
|
|
248
|
-
calibpipe_data_container : ctapipe.
|
|
249
|
-
|
|
249
|
+
calibpipe_data_container : ctapipe.core.Container
|
|
250
|
+
The data container with the data to be uploaded to the main table of the database.
|
|
250
251
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
-------
|
|
258
|
-
insertion_list : list
|
|
259
|
-
list of metadata dictionaries that were uploaded to DB
|
|
260
|
-
"""
|
|
261
|
-
insertion_list = []
|
|
262
|
-
metadata_dict = {
|
|
263
|
-
container: values
|
|
264
|
-
for container, values in config_data.items()
|
|
265
|
-
if "Reference" in container
|
|
266
|
-
}
|
|
252
|
+
metadata : list[Container] or None
|
|
253
|
+
Optional list of metadata containers to be uploaded. Should include
|
|
254
|
+
a "ReferenceMetadataContainer" if metadata is provided.
|
|
255
|
+
|
|
256
|
+
connection : CalibPipeDatabase
|
|
257
|
+
An active database connection to the CalibPipe database.
|
|
267
258
|
|
|
259
|
+
Raises
|
|
260
|
+
------
|
|
261
|
+
DBStorageError
|
|
262
|
+
If there are issues with the database connection.
|
|
263
|
+
|
|
264
|
+
ValueError
|
|
265
|
+
If the main table does not contain a single autoincremented primary key
|
|
266
|
+
or if ReferenceMetadataContainer is missing when metadata is provided.
|
|
267
|
+
"""
|
|
268
268
|
data_db_container = ContainerMap.map_to_db_container(
|
|
269
269
|
type(calibpipe_data_container)
|
|
270
270
|
)
|
|
@@ -272,80 +272,62 @@ class TableHandler:
|
|
|
272
272
|
col.autoincrement for col in data_db_container.get_table().c
|
|
273
273
|
)
|
|
274
274
|
is_single_pk = len(data_db_container.get_primary_keys()) == 1
|
|
275
|
-
# Check if there are only one autoincremented pk in the table
|
|
276
|
-
if has_autoincrement_pk and is_single_pk:
|
|
277
|
-
pk_name = data_db_container.get_primary_keys()[0].name
|
|
278
|
-
try:
|
|
279
|
-
with CalibPipeDatabase(
|
|
280
|
-
**config_data["database_configuration"]
|
|
281
|
-
) as connection:
|
|
282
|
-
TableHandler.insert_row_in_database(
|
|
283
|
-
data_db_container.get_table(),
|
|
284
|
-
calibpipe_data_container,
|
|
285
|
-
connection,
|
|
286
|
-
)
|
|
287
|
-
# Get the last uploaded DB record,
|
|
288
|
-
# to which all metadata will be attached
|
|
289
|
-
stmt = (
|
|
290
|
-
sa.select(data_db_container.get_table())
|
|
291
|
-
.order_by(sa.desc(data_db_container.get_table().c[pk_name]))
|
|
292
|
-
.limit(1)
|
|
293
|
-
)
|
|
294
|
-
last_db_record = connection.execute(stmt).fetchone()
|
|
295
|
-
data_pk_value = last_db_record._asdict()[pk_name]
|
|
296
|
-
|
|
297
|
-
# We should process Reference metadata separately,
|
|
298
|
-
# because it contains autoincremented PK
|
|
299
|
-
# to which all other metadata are connected
|
|
300
|
-
cp_container = getattr(
|
|
301
|
-
common_metadata_module, "ReferenceMetadataContainer"
|
|
302
|
-
)
|
|
303
|
-
db_container = ContainerMap.map_to_db_container(cp_container)
|
|
304
|
-
reference_meta_insertion = cp_container(
|
|
305
|
-
ID_optical_throughput=data_pk_value,
|
|
306
|
-
**config_data["ReferenceMetadataContainer"],
|
|
307
|
-
)
|
|
308
|
-
TableHandler.insert_row_in_database(
|
|
309
|
-
db_container.get_table(), reference_meta_insertion, connection
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
# Extract value of the Reference metadata PK,
|
|
313
|
-
# and connect to it all other metadata tables
|
|
314
|
-
stmt = (
|
|
315
|
-
sa.select(db_container.get_table())
|
|
316
|
-
.order_by(sa.desc(db_container.get_table().c.ID))
|
|
317
|
-
.limit(1)
|
|
318
|
-
)
|
|
319
|
-
metadata_id = connection.execute(stmt).fetchone()
|
|
320
|
-
|
|
321
|
-
# Remove Reference metadata from the dict to not process it second time
|
|
322
|
-
metadata_dict.pop("ReferenceMetadataContainer", None)
|
|
323
|
-
|
|
324
|
-
# Create list with values that should be inserted
|
|
325
|
-
# to the metadata tables in the DB
|
|
326
|
-
for container in metadata_dict.keys():
|
|
327
|
-
cp_container = getattr(common_metadata_module, container)
|
|
328
|
-
insertion_list.append(
|
|
329
|
-
cp_container(ID=metadata_id.ID, **config_data[container])
|
|
330
|
-
)
|
|
331
275
|
|
|
332
|
-
|
|
333
|
-
for insertion, container in zip(
|
|
334
|
-
insertion_list, metadata_dict.keys()
|
|
335
|
-
):
|
|
336
|
-
cp_container = getattr(common_metadata_module, container)
|
|
337
|
-
db_container = ContainerMap.map_to_db_container(cp_container)
|
|
338
|
-
TableHandler.insert_row_in_database(
|
|
339
|
-
db_container.get_table(), insertion, connection
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
insertion_list = [reference_meta_insertion] + insertion_list
|
|
343
|
-
except sa.exc.DatabaseError:
|
|
344
|
-
raise DBStorageError("Issues with connection to the CalibPipe DB")
|
|
345
|
-
else:
|
|
276
|
+
if not (has_autoincrement_pk and is_single_pk):
|
|
346
277
|
raise ValueError(
|
|
347
278
|
f"Table '{data_db_container.table_name}' "
|
|
348
|
-
"doesn't contain single autoincremented primary key."
|
|
279
|
+
"doesn't contain a single autoincremented primary key."
|
|
349
280
|
)
|
|
350
281
|
|
|
351
|
-
|
|
282
|
+
pk_name = data_db_container.get_primary_keys()[0].name
|
|
283
|
+
|
|
284
|
+
try:
|
|
285
|
+
# Insert main data
|
|
286
|
+
table, values = TableHandler.get_database_table_insertion(
|
|
287
|
+
calibpipe_data_container
|
|
288
|
+
)
|
|
289
|
+
TableHandler.insert_row_in_database(table, values, connection)
|
|
290
|
+
|
|
291
|
+
# No metadata to upload
|
|
292
|
+
if not metadata:
|
|
293
|
+
return
|
|
294
|
+
|
|
295
|
+
# Get the last inserted primary key
|
|
296
|
+
stmt = sa.select(table).order_by(sa.desc(table.c[pk_name])).limit(1)
|
|
297
|
+
last_db_record = connection.execute(stmt).fetchone()
|
|
298
|
+
data_pk_value = last_db_record._asdict()[pk_name]
|
|
299
|
+
|
|
300
|
+
# Handle ReferenceMetadataContainer
|
|
301
|
+
reference_meta_container = next(
|
|
302
|
+
(
|
|
303
|
+
c
|
|
304
|
+
for c in metadata
|
|
305
|
+
if c.__class__.__name__ == "ReferenceMetadataContainer"
|
|
306
|
+
),
|
|
307
|
+
None,
|
|
308
|
+
)
|
|
309
|
+
if reference_meta_container is None:
|
|
310
|
+
raise ValueError("ReferenceMetadataContainer is required in metadata.")
|
|
311
|
+
|
|
312
|
+
reference_meta_container.ID_optical_throughput = data_pk_value
|
|
313
|
+
ref_table, ref_values = TableHandler.get_database_table_insertion(
|
|
314
|
+
reference_meta_container
|
|
315
|
+
)
|
|
316
|
+
TableHandler.insert_row_in_database(ref_table, ref_values, connection)
|
|
317
|
+
|
|
318
|
+
# Get ReferenceMetadata ID to link to other metadata
|
|
319
|
+
stmt = sa.select(ref_table).order_by(sa.desc(ref_table.c.ID)).limit(1)
|
|
320
|
+
metadata_id = connection.execute(stmt).fetchone().ID
|
|
321
|
+
|
|
322
|
+
# Upload other metadata
|
|
323
|
+
for container in metadata:
|
|
324
|
+
if container.__class__.__name__ == "ReferenceMetadataContainer":
|
|
325
|
+
continue
|
|
326
|
+
container.ID = metadata_id
|
|
327
|
+
meta_table, meta_values = TableHandler.get_database_table_insertion(
|
|
328
|
+
container
|
|
329
|
+
)
|
|
330
|
+
TableHandler.insert_row_in_database(meta_table, meta_values, connection)
|
|
331
|
+
|
|
332
|
+
except sa.exc.DatabaseError:
|
|
333
|
+
raise DBStorageError("Issues with connection to the CalibPipe DB")
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"""Containers to keep optical throughput data and metadata."""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
from ctapipe.core import Container, Field
|
|
7
|
+
|
|
8
|
+
# UNIX_TIME_ZERO value corresponds to "epoch" special time from PostgreSQL documentation:
|
|
9
|
+
# https://www.postgresql.org/docs/current/datatype-datetime.html#DATATYPE-DATETIME-SPECIAL-TABLE
|
|
10
|
+
|
|
11
|
+
UNIX_TIME_ZERO = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class OpticalThoughtputContainer(Container):
|
|
15
|
+
"""Optical throughput calibration coefficient and analysis results for a single telescope."""
|
|
16
|
+
|
|
17
|
+
optical_throughput_coefficient = Field(
|
|
18
|
+
np.nan,
|
|
19
|
+
"Optical throughput from the selected calibration method",
|
|
20
|
+
type=np.float64,
|
|
21
|
+
allow_none=False,
|
|
22
|
+
)
|
|
23
|
+
optical_throughput_coefficient_std = Field(
|
|
24
|
+
np.nan,
|
|
25
|
+
"Optical throughput from the selected calibration method",
|
|
26
|
+
type=np.float64,
|
|
27
|
+
allow_none=False,
|
|
28
|
+
)
|
|
29
|
+
method = Field(
|
|
30
|
+
"None",
|
|
31
|
+
"Calibration method used to fill optical_throughput_coefficient",
|
|
32
|
+
type=str,
|
|
33
|
+
allow_none=False,
|
|
34
|
+
)
|
|
35
|
+
validity_start = Field(
|
|
36
|
+
UNIX_TIME_ZERO,
|
|
37
|
+
description="Starting timestamp of validity for the selected throughput.",
|
|
38
|
+
type=datetime.datetime,
|
|
39
|
+
allow_none=False,
|
|
40
|
+
)
|
|
41
|
+
validity_end = Field(
|
|
42
|
+
UNIX_TIME_ZERO,
|
|
43
|
+
description="Ending timestamp of validity for the selected throughput.",
|
|
44
|
+
type=datetime.datetime,
|
|
45
|
+
allow_none=False,
|
|
46
|
+
)
|
|
47
|
+
obs_id = Field(
|
|
48
|
+
-1,
|
|
49
|
+
description="ID of the observation block for validity",
|
|
50
|
+
type=np.int32,
|
|
51
|
+
allow_none=False,
|
|
52
|
+
)
|
|
53
|
+
tel_id = Field(-1, description="Telescope ID", type=np.int32, allow_none=False)
|
|
54
|
+
n_events = Field(
|
|
55
|
+
0,
|
|
56
|
+
description="Number of muon rings used to calculate the throughput",
|
|
57
|
+
type=np.int32,
|
|
58
|
+
allow_none=False,
|
|
59
|
+
)
|