Skip to content

Commit c8ecfb2

Browse files
committed
Implement CalibrationData on top of DetectorData
1 parent 58d299f commit c8ecfb2

18 files changed

Lines changed: 1241 additions & 1474 deletions

src/extra/calibration.py

Lines changed: 73 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -607,11 +607,10 @@ class CalibrationData(Mapping):
607607
(e.g. `cd["Offset"]`), giving you `MultiModuleConstant` objects.
608608
"""
609609

610-
def __init__(self, constant_groups, module_details, detector_name):
610+
def __init__(self, constant_groups, detector):
611611
# {calibration: {karabo_da: SingleConstant}}
612612
self.constant_groups = constant_groups
613-
self.module_details = module_details
614-
self.detector_name = detector_name
613+
self.detector = detector
615614

616615
@staticmethod
617616
def _format_cond(condition):
@@ -675,18 +674,7 @@ def from_condition(
675674

676675
client = client or get_client()
677676

678-
detector_id = client.detector_by_identifier(detector_name)["id"]
679-
pdus = client.get(
680-
"physical_detector_units/get_all_by_detector",
681-
{
682-
"detector_id": detector_id,
683-
"pdu_snapshot_at": client.format_time(pdu_snapshot_at),
684-
},
685-
)
686-
module_details = sorted(pdus, key=lambda d: d["karabo_da"])
687-
for mod in module_details:
688-
if mod.get("module_number") is None:
689-
mod["module_number"] = int(re.findall(r"\d+", mod["karabo_da"])[-1])
677+
detector = DetectorData.from_identifier(detector_name, pdu_snapshot_at=pdu_snapshot_at)
690678

691679
constant_groups = {}
692680

@@ -718,7 +706,7 @@ def from_condition(
718706
const_group = constant_groups.setdefault(cal_type, {})
719707
const_group[aggr] = SingleConstant.from_response(ccv)
720708

721-
return cls(constant_groups, module_details, detector_name)
709+
return cls(constant_groups, detector)
722710

723711
@classmethod
724712
def from_report(
@@ -777,10 +765,18 @@ def from_report(
777765
if len(det_ids) > 1:
778766
raise Exception(f"Found multiple detector IDs in report: {det_ids}")
779767
# The "identifier", "name" & "karabo_name" fields seem to have the same names
780-
det_name = client.detector_by_id(det_ids.pop())["identifier"]
781768

782-
module_details = sorted(pdus.values(), key=lambda d: d["karabo_da"])
783-
return cls(constant_groups, module_details, det_name)
769+
detector_row = client.detector_by_id(det_ids.pop())
770+
detector_types = {det_type["id"]: det_type for det_type
771+
in client.get("detector_types")}
772+
773+
# Extend PDUs by data missing in the report result set.
774+
for pdu in pdus.values():
775+
pdu["detector"] = detector_row
776+
pdu["detector_type"] = detector_types[pdu["detector_type_id"]]
777+
778+
return cls(constant_groups, DetectorData(
779+
detector_row, sorted(pdus.values(), key=lambda x: x["karabo_da"])))
784780

785781
@staticmethod
786782
def _read_correction_file(metadata_path: Path):
@@ -848,11 +844,24 @@ def from_correction(
848844
else:
849845
yaml_path = Path(metadata_file_or_proposal)
850846

851-
852847
constant_groups, pdus, det_name = cls._read_correction_file(yaml_path)
853848
module_details = sorted(pdus.values(), key=lambda d: d["karabo_da"])
849+
854850
if not use_calcat:
855-
return cls(constant_groups, module_details, det_name)
851+
detector_row = {
852+
'id': None, 'identifier': det_name,
853+
'source_name_pattern': None, 'number_of_modules': None,
854+
'first_module_index': None
855+
}
856+
857+
for pdu in pdus.values():
858+
pdu.update(
859+
id=None, uuid=None, detector={'identifier': det_name},
860+
virtual_device_name=None, module_number=None,
861+
detector_type={'name': None})
862+
863+
return cls(
864+
constant_groups, DetectorData(detector_row, pdus.values()))
856865

857866
# Get module_number, virtual_device_name from CCV info if possible
858867
need_metadata = {
@@ -861,6 +870,10 @@ def from_correction(
861870

862871
def extend_module_info(pdu_dict):
863872
kda = pdu_dict['karabo_da_at_ccv_begin_at']
873+
874+
pdus[kda].update(pdu_dict)
875+
pdus[kda]['karabo_da'] = pdu_dict['karabo_da_at_ccv_begin_at']
876+
864877
if vdn := pdu_dict['virtual_device_name_at_ccv_begin_at']:
865878
pdus[kda]['virtual_device_name'] = vdn
866879
if modnum := pdu_dict['module_number_at_ccv_begin_at']:
@@ -890,16 +903,16 @@ def extend_module_info(pdu_dict):
890903
const_obj._have_calcat_metadata = True
891904
extend_module_info(ccv_dict['physical_detector_unit'])
892905

893-
# If we didn't get module numbers from the PDU mapping, and we have
894-
# the expected number of modules, fill the numbers in sequentially.
895-
if any('module_number' not in d for d in module_details):
896-
det_info = client.detector_by_identifier(det_name)
897-
if len(module_details) == det_info['number_of_modules']:
898-
if (first := det_info['first_module_index']) is not None:
899-
for i, d in enumerate(module_details, start=first):
900-
d['module_number'] = i
906+
detector_row = client.detector_by_identifier(det_name)
907+
detector_types = {det_type["id"]: det_type for det_type
908+
in client.get("detector_types")}
909+
910+
# Extend PDUs by data missing in the report result set.
911+
for da, pdu in pdus.items():
912+
pdu["detector"] = detector_row
913+
pdu["detector_type"] = detector_types[pdu["detector_type_id"]]
901914

902-
return cls(constant_groups, module_details, det_name)
915+
return cls(constant_groups, DetectorData(detector_row, pdus.values()))
903916

904917
def __getitem__(self, key):
905918
if isinstance(key, str):
@@ -956,8 +969,20 @@ def pdu_names(self):
956969
May include missing modules."""
957970
return [m["physical_name"] for m in self.module_details]
958971

959-
def detector(self):
960-
return DetectorData.from_identifier(self.detector_name)
972+
@property
973+
def module_details(self):
974+
return [dict(
975+
id=pdu.pdu_id, physical_name=pdu.physical_name,
976+
karabo_da=pdu.aggregator,
977+
virtual_device_name=pdu.virtual_device_name, uuid=pdu.legacy_uuid,
978+
module_number=pdu.module_number,
979+
module_number_at_ccv_begin_at=pdu.module_number,
980+
detector_type=dict(name=pdu.detector_type)
981+
) for pdu in self.detector.values()]
982+
983+
@property
984+
def detector_name(self):
985+
return self.detector.identifier
961986

962987
def require_calibrations(self, calibrations) -> "CalibrationData":
963988
"""Drop any modules missing the specified constant types"""
@@ -988,15 +1013,18 @@ def select_modules(
9881013
aggr: const for (aggr, const) in const_group.items() if aggr in aggs
9891014
}
9901015
matched_aggregators.update(d.keys())
1016+
9911017
module_details = [
9921018
m for m in self.module_details if m["karabo_da"] in matched_aggregators
9931019
]
994-
return type(self)(constant_groups, module_details, self.detector_name)
1020+
1021+
return type(self)(
1022+
constant_groups, self.detector._replace_modules(module_details))
9951023

9961024
def select_calibrations(self, calibrations) -> "CalibrationData":
9971025
"""Return a new `CalibrationData` object with only the selected constant types"""
9981026
const_groups = {c: self.constant_groups[c] for c in calibrations}
999-
return type(self)(const_groups, self.module_details, self.detector_name)
1027+
return type(self)(const_groups, self.detector)
10001028

10011029
def merge(self, *others: "CalibrationData") -> "CalibrationData":
10021030
"""Combine two or more `CalibrationData` objects for the same detector.
@@ -1043,7 +1071,8 @@ def merge(self, *others: "CalibrationData") -> "CalibrationData":
10431071
if cal_type in caldata:
10441072
d.update(caldata.constant_groups[cal_type])
10451073

1046-
return type(self)(constant_groups, module_details, det_name)
1074+
return type(self)(
1075+
constant_groups, self.detector._replace_modules(module_details))
10471076

10481077
def summary_table(self, module_naming="modnum"):
10491078
"""Make a table overview of the constants found.
@@ -1545,6 +1574,15 @@ def __repr__(self):
15451574
return f'<DetectorData: {len(self.pdus)}/{self.number_of_modules} ' \
15461575
f'modules of {self.identifier} on {self.pdu_snapshot_at}>'
15471576

1577+
def _replace_modules(self, module_rows_or_pdus):
1578+
detector_row = {'id': self.id, 'identifier': self.identifier,
1579+
'number_of_modules': self.number_of_modules,
1580+
'source_name_pattern': self._source_name_pattern,
1581+
'first_module_index': self._first_module_index}
1582+
1583+
return type(self)(detector_row, module_rows_or_pdus,
1584+
self.pdu_snapshot_at)
1585+
15481586
@property
15491587
def source_name_pattern(self) -> str:
15501588
"""Source name pattern."""

0 commit comments

Comments
 (0)