Skip to content
Snippets Groups Projects
Commit b2bcfb9f authored by David Hammer's avatar David Hammer
Browse files

DetectorAssembler: handle quirk of JF module indices, add test

parent 142c805c
No related branches found
No related tags found
No related merge requests found
......@@ -51,6 +51,13 @@ def module_index_schema():
.reconfigurable()
.commit(),
STRING_ELEMENT(schema)
.key("regexUsed")
.assignmentOptional()
.defaultValue("")
.reconfigurable()
.commit(),
INT32_ELEMENT(schema)
.key("index")
.assignmentOptional()
......@@ -213,16 +220,20 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
self.start()
def _source_to_index_from_regex(self):
"""Helper function to run through either user supplied or built-in regex and
extract mapping of source -> (matching regex, module index) from current table
of sources. If relying on built-in regexes, will use the first one to match
anything on all sources."""
res = {}
sources = [
row["source"].partition("@")[0]
for row in self.get("sources")
if row["select"]
]
if self.get("sourceIndexPattern"):
source_re = re.compile(self.get("sourceIndexPattern"))
if (source_pattern := self.get("sourceIndexPattern")):
source_re = re.compile(source_pattern)
res = {
source: int(match.group("index"))
source: (source_pattern, int(match.group("index")))
for source in sources
if (match := source_re.match(source)) is not None
}
......@@ -239,7 +250,13 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
),
(
r".*\/DET\/.*?(\d+):daqOutput", # typical JF receiver source
lambda match: int(match.group(1)) - 1,
lambda match: int(match.group(1)),
# don't subtract 1; JUNGFRAUGeometry does this for us
),
(
r".*\/CORRECT(\d+)_M(\d+)", # typical JF correction device
lambda match: int(match.group(2)),
# don't subtract 1; JUNGFRAUGeometry does this for us
),
(
r".*\/CORRECT(\d+)", # generic correction device enumeration
......@@ -251,29 +268,62 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
matches = [source_re.match(source) for source in sources]
if any(match is not None for match in matches):
res = {
source: extractor(match)
source: (source_pattern, extractor(match))
for (source, match) in zip(sources, matches)
if match is not None
}
break
for source in sources:
if source not in res:
res[source] = None
res[source] = (None, None)
return res
def _merge_source_to_index_from_regex(self):
"""Helper function to fill out the source module index table. It will use
_source_to_index_from_regex and add to the sourceToModuleIndex table any sources
not yet set (ex. new source added to sources / device just initialized / some
sources manually set)."""
table = self.get("sourceToModuleIndex")
known_sources = {row["source"] for row in table if row["select"]}
used_indices = {row["index"] for row in table if row["select"]}
for (source, index) in self._source_to_index_from_regex().items():
for source, (
source_pattern,
index,
) in self._source_to_index_from_regex().items():
if source in known_sources:
# already in table - maybe manually set
continue
elif index is None:
# was not matched by chosen regex (if any)
table.append(Hash("select", False, "source", source, "index", -1))
elif index in used_indices:
table.append(Hash("select", False, "source", source, "index", index))
# was matched, but module index used by other source
self.log.WARN(f"Index {index} already used, deselecting {source}")
table.append(
Hash(
"select",
False,
"source",
source,
"regexUsed",
source_pattern,
"index",
index,
)
)
else:
table.append(Hash("select", True, "source", source, "index", index))
table.append(
Hash(
"select",
True,
"source",
source,
"regexUsed",
source_pattern,
"index",
index,
)
)
used_indices.add(index)
self.set(
"sourceToModuleIndex",
......@@ -281,6 +331,9 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
)
def _set_source_to_index_from_table(self):
"""Sets internal source to module index mapping based on the values currently in
the sourceToModuleIndex table. Should be called whenever the table is updated.
"""
mapping = {
row["source"]: row["index"]
for row in self.get("sourceToModuleIndex")
......@@ -323,7 +376,9 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
self._geometry = geom_utils.deserialize_geometry(serialized_geometry)
except Exception as e:
self.log.WARN(f"Failed to deserialize geometry; {e}")
return
# TODO: test with multiple memory cells (extra geom notion of extra dimensions)
# NOTE: could almost test n_modules against _source_to_index JF inconsistent
def on_matched_data(self, train_id, sources):
ts_start = default_timer()
......
from karabo.bound import Hash
from calng.DetectorAssembler import DetectorAssembler
class NotADetectorAssembler(DetectorAssembler):
def __init__(self):
self._parameters = Hash()
def get(self, key):
return self._parameters.get(key)
def set(self, key, value):
return self._parameters.set(key, value)
def test_agipd_mapping():
d = NotADetectorAssembler()
spb_agipd_mapping = {
s: i
for i, s in enumerate(
[
"SPB_DET_AGIPD1M-1/CAL/CORRECT00_Q1M1:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT01_Q1M2:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT02_Q1M3:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT03_Q1M4:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT04_Q2M1:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT05_Q2M2:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT06_Q2M3:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT07_Q2M4:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT08_Q3M1:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT09_Q3M2:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT10_Q3M3:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT11_Q3M4:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT12_Q4M1:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT13_Q4M2:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT14_Q4M3:preview.outputRaw",
"SPB_DET_AGIPD1M-1/CAL/CORRECT15_Q4M4:preview.outputRaw",
]
)
}
subset = list(spb_agipd_mapping.keys())
del subset[4:7]
d.set("sources", [Hash("select", True, "source", s) for s in subset])
d.set("sourceToModuleIndex", [])
d._merge_source_to_index_from_regex()
d._set_source_to_index_from_table()
for source in subset:
assert spb_agipd_mapping[source] == d._source_to_index[source]
assert len(subset) == len(d._source_to_index)
def test_jf_mapping():
spb_jf_mapping = {
s: i # special: JF geometry itself subtracts one
for i, s in enumerate(
[
"SPB_IRDA_JF4M/CAL/CORRECT00_M1:preview.outputCorrected",
"SPB_IRDA_JF4M/CAL/CORRECT01_M2:preview.outputCorrected",
"SPB_IRDA_JF4M/CAL/CORRECT02_M3:preview.outputCorrected",
"SPB_IRDA_JF4M/CAL/CORRECT03_M4:preview.outputCorrected",
"SPB_IRDA_JF4M/CAL/CORRECT04_M5:preview.outputCorrected",
"SPB_IRDA_JF4M/CAL/CORRECT05_M6:preview.outputCorrected",
"SPB_IRDA_JF4M/CAL/CORRECT06_M7:preview.outputCorrected",
"SPB_IRDA_JF4M/CAL/CORRECT07_M8:preview.outputCorrected",
],
start=1,
)
}
d = NotADetectorAssembler()
subset = list(spb_jf_mapping.keys())
del subset[2:4]
d.set("sources", [Hash("select", True, "source", s) for s in subset])
d.set("sourceToModuleIndex", [])
d._merge_source_to_index_from_regex()
d._set_source_to_index_from_table()
for source in subset:
assert spb_jf_mapping[source] == d._source_to_index[source]
assert len(subset) == len(d._source_to_index)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment