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

Overhaul geometry device classes, initial Jungfrau support

parent ace4eb6e
No related branches found
No related tags found
2 merge requests!12Snapshot: field test deployed version as of end of run 202201,!7Draft: Add simple assembler and manual geometry devices using extra_geom
......@@ -27,7 +27,11 @@ setup(name='calng',
'AgipdCorrection = calng.AgipdCorrection:AgipdCorrection',
'DsscCorrection = calng.DsscCorrection:DsscCorrection',
'ModuleStacker = calng.ModuleStacker:ModuleStacker',
'ManualAgipdGeometry = calng.ManualAgipdGeometry:ManualAgipdGeometry',
'ManualDsscGeometry = calng.ManualDsscGeometry:ManualDsscGeometry',
'ManualJungfrauGeometry = calng.ManualJungfrauGeometry:ManualJungfrauGeometry',
'ShmemToZMQ = calng.ShmemToZMQ:ShmemToZMQ',
'SimpleAssembler = calng.SimpleAssembler:SimpleAssembler',
],
'karabo.middlelayer_device': [
......
......@@ -2,11 +2,11 @@ import extra_geom
from karabo.bound import KARABO_CLASSINFO
from ._version import version as deviceVersion
from .manual_geometry_base import ManualGeometryBase
from .manual_geometry_base import ManualQuadrantsGeometryBase
@KARABO_CLASSINFO("ManualAgipdGeometry", deviceVersion)
class ManualAgipdGeometry(ManualGeometryBase):
class ManualAgipdGeometry(ManualQuadrantsGeometryBase):
geometry_class = extra_geom.AGIPD_1MGeometry
@staticmethod
......
......@@ -2,11 +2,11 @@ import extra_geom
from karabo.bound import KARABO_CLASSINFO
from ._version import version as deviceVersion
from .manual_geometry_base import ManualGeometryBase
from .manual_geometry_base import ManualQuadrantsGeometryBase
@KARABO_CLASSINFO("ManualDsscGeometry", deviceVersion)
class ManualDsscGeometry(ManualGeometryBase):
class ManualDsscGeometry(ManualQuadrantsGeometryBase):
geometry_class = extra_geom.DSSC_1MGeometry
@staticmethod
......
import extra_geom
from karabo.bound import KARABO_CLASSINFO, OVERWRITE_ELEMENT, Hash
from ._version import version as deviceVersion
from .manual_geometry_base import ManualModulesGeometryBase
@KARABO_CLASSINFO("ManualJungfrauGeometry", deviceVersion)
class ManualJungfrauGeometry(ManualModulesGeometryBase):
geometry_class = extra_geom.JUNGFRAUGeometry
@staticmethod
def expectedParameters(expected):
# TODO: come up with some sweet defaults (this is two modules from docs 4M)
(
OVERWRITE_ELEMENT(expected)
.key("modules")
.setNewDefaultValue(
[
Hash(
"posX", 95, "posY", 564, "orientationX", -1, "orientationY", -1
),
Hash(
"posX", 95, "posY", 17, "orientationX", -1, "orientationY", -1
),
]
)
)
......@@ -3,6 +3,7 @@ import pickle
import re
import numpy as np
from calng import utils
from karabo.bound import (
FLOAT_ELEMENT,
IMAGEDATA_ELEMENT,
......@@ -25,20 +26,21 @@ from karabo.bound import (
Unit,
)
from karabo.common.api import KARABO_SCHEMA_DISPLAY_TYPE_SCENES as DT_SCENES
from TrainMatcher import TrainMatcher, scenes as trainmatcher_scenes
from TrainMatcher import TrainMatcher
from TrainMatcher import scenes as trainmatcher_scenes
from . import scenes
from ._version import version as deviceVersion
from calng import utils
preview_schema = Schema()
(
IMAGEDATA_ELEMENT(preview_schema).key("image").commit(),
UINT64_ELEMENT(preview_schema).key("trainId").readOnly().commit(),
)
xtdf_source_re = re.compile(r".*\/DET\/(\d+)CH0:xtdf")
daq_source_re = re.compile(r".*\/DET\/.*?(\d+):daqOutput")
# TODO: merge scene with TrainMatcher's nice overview
@KARABO_CLASSINFO("SimpleAssembler", deviceVersion)
......@@ -48,9 +50,9 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
(
OVERWRITE_ELEMENT(expected)
.key("availableScenes")
# TODO: add assemblerOverview scene
.setNewDefaultValue(["scene", "assemblerOverview"])
.commit(),
FLOAT_ELEMENT(expected)
.key("processingTime")
.unit(Unit.SECOND)
......@@ -61,6 +63,7 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
.info("Cannot keep up with GUI limit")
.needsAcknowledging(False)
.commit(),
FLOAT_ELEMENT(expected)
.key("timeOfFlight")
.unit(Unit.SECOND)
......@@ -71,15 +74,18 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
.info("Time of flight exceeding 1 s")
.needsAcknowledging(False)
.commit(),
STRING_ELEMENT(expected)
.key("pathToStack")
.assignmentOptional()
.defaultValue("image.data")
.commit(),
INPUT_CHANNEL(expected)
.key("geometryInput")
.displayedName("Geometry input")
.commit(),
OUTPUT_CHANNEL(expected) # can OVERWRITE_ELEMENT even do this?
.key("output")
.dataSchema(preview_schema)
......@@ -145,7 +151,7 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
module_indices_unfilled.discard(module_index)
for unfilled_module in module_indices_unfilled:
self.input_buffer[module_index].fill(0)
self.input_buffer[unfilled_module].fill(0)
# TODO: configurable treatment of missing modules
# TODO: reusable output buffer to save on allocation
......@@ -179,8 +185,15 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
@functools.lru_cache
def _source_to_index(self, source):
# note: cache means warning only shows up once (also not performance-critical)
# TODO: allow user to inspect, modify the mapping
match = xtdf_source_re.match(source)
if match is None:
self.log.WARN(f"Couldn't figure out index for source {source}")
return 0
return int(match.group(1))
if match is not None:
return int(match.group(1))
match = daq_source_re.match(source)
if match is not None:
return int(match.group(1)) - 1
self.log.WARN(f"Couldn't figure out index for source {source}")
return 0
import pickle
import matplotlib.pyplot as plt
import numpy as np
from karabo.bound import (
DOUBLE_ELEMENT,
KARABO_CLASSINFO,
IMAGEDATA_ELEMENT,
INT32_ELEMENT,
KARABO_CLASSINFO,
NODE_ELEMENT,
OUTPUT_CHANNEL,
SLOT_ELEMENT,
TABLE_ELEMENT,
VECTOR_CHAR_ELEMENT,
VECTOR_STRING_ELEMENT,
Encoding,
......@@ -17,14 +21,11 @@ from karabo.bound import (
State,
)
from karabo.common.api import KARABO_SCHEMA_DISPLAY_TYPE_SCENES as DT_SCENES
import numpy as np
from matplotlib.backends.backend_agg import FigureCanvasAgg
import matplotlib.pyplot as plt
from . import scenes
from ._version import version as deviceVersion
geometry_schema = Schema()
(
VECTOR_CHAR_ELEMENT(geometry_schema)
......@@ -38,6 +39,37 @@ geometry_schema = Schema()
preview_schema = Schema()
(IMAGEDATA_ELEMENT(preview_schema).key("overview").commit())
ModuleColumn = Schema()
(
DOUBLE_ELEMENT(ModuleColumn)
.key("posX")
.assignmentOptional()
.defaultValue(95)
.reconfigurable()
.commit(),
DOUBLE_ELEMENT(ModuleColumn)
.key("posY")
.assignmentOptional()
.defaultValue(564)
.reconfigurable()
.commit(),
INT32_ELEMENT(ModuleColumn)
.key("orientationX")
.assignmentOptional()
.defaultValue(-1)
.reconfigurable()
.commit(),
INT32_ELEMENT(ModuleColumn)
.key("orientationY")
.assignmentOptional()
.defaultValue(-1)
.reconfigurable()
.commit(),
)
@KARABO_CLASSINFO("ManualGeometryBase", deviceVersion)
class ManualGeometryBase(PythonDevice):
......@@ -49,37 +81,20 @@ class ManualGeometryBase(PythonDevice):
.key("geometryOutput")
.dataSchema(geometry_schema)
.commit(),
SLOT_ELEMENT(expected).key("pleaseSendYourGeometry").commit(),
SLOT_ELEMENT(expected).key("reloadScenes").commit(),
OUTPUT_CHANNEL(expected)
.key("previewOutput")
.dataSchema(preview_schema)
.commit(),
IMAGEDATA_ELEMENT(expected).key("layoutPreview").commit(),
)
# configuring this one manually
# subclasses should set better defaults
(NODE_ELEMENT(expected).key("quadrantCorners").commit(),)
for q in range(1, 5):
(
NODE_ELEMENT(expected).key(f"quadrantCorners.Q{q}").commit(),
DOUBLE_ELEMENT(expected)
.key(f"quadrantCorners.Q{q}.x")
.assignmentOptional()
.defaultValue(0)
.reconfigurable()
.commit(),
DOUBLE_ELEMENT(expected)
.key(f"quadrantCorners.Q{q}.y")
.assignmentOptional()
.defaultValue(0)
.reconfigurable()
.commit(),
)
# scenes are fun
# TODO: add the scene
(
VECTOR_STRING_ELEMENT(expected)
.key("availableScenes")
......@@ -89,6 +104,9 @@ class ManualGeometryBase(PythonDevice):
.commit(),
)
def update_geom(self):
raise NotImplementedError()
def __init__(self, config):
super().__init__(config)
......@@ -116,22 +134,6 @@ class ManualGeometryBase(PythonDevice):
response["payload"] = payload
self.reply(response)
def update_geom(self):
self.quadrant_corners = tuple(
(self.get(f"quadrantCorners.Q{q}.x"), self.get(f"quadrantCorners.Q{q}.y"))
for q in range(1, 5)
)
self.geom = self.geometry_class.from_quad_positions(self.quadrant_corners)
self.pickled = pickle.dumps(self.geom)
# TODO: send to anyone who asks? make slot for that?
self.writeChannel("geometryOutput", Hash("pickledGeometry", self.pickled))
def reloadScenes(self):
global scenes
import importlib
scenes = importlib.reload(scenes)
def pleaseSendYourGeometry(self):
self.writeChannel("geometryOutput", Hash("pickledGeometry", self.pickled))
axis = self.geom.inspect()
......@@ -148,7 +150,6 @@ class ManualGeometryBase(PythonDevice):
"layoutPreview",
ImageData(image_buffer, encoding=Encoding.RGBA, bitsPerPixel=3 * 8),
)
# self.writeChannel("previewOutput", Hash("overview", ImageData()))
def preReconfigure(self, config):
self._prereconfigure_update_hash = config
......@@ -159,3 +160,68 @@ class ManualGeometryBase(PythonDevice):
for path in self._prereconfigure_update_hash.getPaths()
):
self.update_geom()
del self._prereconfigure_update_hash
@KARABO_CLASSINFO("ManualQuadrantsGeometryBase", deviceVersion)
class ManualQuadrantsGeometryBase(ManualGeometryBase):
@staticmethod
def expectedParameters(expected):
# note: subclasses should set better defaults
(NODE_ELEMENT(expected).key("quadrantCorners").commit(),)
for q in range(1, 5):
(
NODE_ELEMENT(expected).key(f"quadrantCorners.Q{q}").commit(),
DOUBLE_ELEMENT(expected)
.key(f"quadrantCorners.Q{q}.x")
.assignmentOptional()
.defaultValue(0)
.reconfigurable()
.commit(),
DOUBLE_ELEMENT(expected)
.key(f"quadrantCorners.Q{q}.y")
.assignmentOptional()
.defaultValue(0)
.reconfigurable()
.commit(),
)
def update_geom(self):
self.quadrant_corners = tuple(
(self.get(f"quadrantCorners.Q{q}.x"), self.get(f"quadrantCorners.Q{q}.y"))
for q in range(1, 5)
)
self.geom = self.geometry_class.from_quad_positions(self.quadrant_corners)
self.pickled = pickle.dumps(self.geom)
# TODO: send to anyone who asks? make slot for that? send on connect?
self.writeChannel("geometryOutput", Hash("pickledGeometry", self.pickled))
@KARABO_CLASSINFO("ManualModulesGeometryBase", deviceVersion)
class ManualModulesGeometryBase(ManualGeometryBase):
@staticmethod
def expectedParameters(expected):
(
TABLE_ELEMENT(expected)
.key("modules")
.setColumns(ModuleColumn)
.assignmentOptional()
.defaultValue([])
.reconfigurable()
.commit(),
)
def update_geom(self):
modules = self.get("modules")
module_pos = [(module.get("posX"), module.get("posY")) for module in modules]
orientations = [
(module.get("orientationX"), module.get("orientationY"))
for module in modules
]
self.geom = self.geometry_class.from_module_positions(
module_pos, orientations=orientations
)
self.pickled = pickle.dumps(self.geom)
# TODO: send to anyone who asks? make slot for that?
self.writeChannel("geometryOutput", Hash("pickledGeometry", self.pickled))
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