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', ...@@ -27,7 +27,11 @@ setup(name='calng',
'AgipdCorrection = calng.AgipdCorrection:AgipdCorrection', 'AgipdCorrection = calng.AgipdCorrection:AgipdCorrection',
'DsscCorrection = calng.DsscCorrection:DsscCorrection', 'DsscCorrection = calng.DsscCorrection:DsscCorrection',
'ModuleStacker = calng.ModuleStacker:ModuleStacker', 'ModuleStacker = calng.ModuleStacker:ModuleStacker',
'ManualAgipdGeometry = calng.ManualAgipdGeometry:ManualAgipdGeometry',
'ManualDsscGeometry = calng.ManualDsscGeometry:ManualDsscGeometry',
'ManualJungfrauGeometry = calng.ManualJungfrauGeometry:ManualJungfrauGeometry',
'ShmemToZMQ = calng.ShmemToZMQ:ShmemToZMQ', 'ShmemToZMQ = calng.ShmemToZMQ:ShmemToZMQ',
'SimpleAssembler = calng.SimpleAssembler:SimpleAssembler',
], ],
'karabo.middlelayer_device': [ 'karabo.middlelayer_device': [
......
...@@ -2,11 +2,11 @@ import extra_geom ...@@ -2,11 +2,11 @@ import extra_geom
from karabo.bound import KARABO_CLASSINFO from karabo.bound import KARABO_CLASSINFO
from ._version import version as deviceVersion from ._version import version as deviceVersion
from .manual_geometry_base import ManualGeometryBase from .manual_geometry_base import ManualQuadrantsGeometryBase
@KARABO_CLASSINFO("ManualAgipdGeometry", deviceVersion) @KARABO_CLASSINFO("ManualAgipdGeometry", deviceVersion)
class ManualAgipdGeometry(ManualGeometryBase): class ManualAgipdGeometry(ManualQuadrantsGeometryBase):
geometry_class = extra_geom.AGIPD_1MGeometry geometry_class = extra_geom.AGIPD_1MGeometry
@staticmethod @staticmethod
......
...@@ -2,11 +2,11 @@ import extra_geom ...@@ -2,11 +2,11 @@ import extra_geom
from karabo.bound import KARABO_CLASSINFO from karabo.bound import KARABO_CLASSINFO
from ._version import version as deviceVersion from ._version import version as deviceVersion
from .manual_geometry_base import ManualGeometryBase from .manual_geometry_base import ManualQuadrantsGeometryBase
@KARABO_CLASSINFO("ManualDsscGeometry", deviceVersion) @KARABO_CLASSINFO("ManualDsscGeometry", deviceVersion)
class ManualDsscGeometry(ManualGeometryBase): class ManualDsscGeometry(ManualQuadrantsGeometryBase):
geometry_class = extra_geom.DSSC_1MGeometry geometry_class = extra_geom.DSSC_1MGeometry
@staticmethod @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 ...@@ -3,6 +3,7 @@ import pickle
import re import re
import numpy as np import numpy as np
from calng import utils
from karabo.bound import ( from karabo.bound import (
FLOAT_ELEMENT, FLOAT_ELEMENT,
IMAGEDATA_ELEMENT, IMAGEDATA_ELEMENT,
...@@ -25,20 +26,21 @@ from karabo.bound import ( ...@@ -25,20 +26,21 @@ from karabo.bound import (
Unit, Unit,
) )
from karabo.common.api import KARABO_SCHEMA_DISPLAY_TYPE_SCENES as DT_SCENES 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 . import scenes
from ._version import version as deviceVersion from ._version import version as deviceVersion
from calng import utils
preview_schema = Schema() preview_schema = Schema()
( (
IMAGEDATA_ELEMENT(preview_schema).key("image").commit(), IMAGEDATA_ELEMENT(preview_schema).key("image").commit(),
UINT64_ELEMENT(preview_schema).key("trainId").readOnly().commit(), UINT64_ELEMENT(preview_schema).key("trainId").readOnly().commit(),
) )
xtdf_source_re = re.compile(r".*\/DET\/(\d+)CH0:xtdf") 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 # TODO: merge scene with TrainMatcher's nice overview
@KARABO_CLASSINFO("SimpleAssembler", deviceVersion) @KARABO_CLASSINFO("SimpleAssembler", deviceVersion)
...@@ -48,9 +50,9 @@ class SimpleAssembler(TrainMatcher.TrainMatcher): ...@@ -48,9 +50,9 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
( (
OVERWRITE_ELEMENT(expected) OVERWRITE_ELEMENT(expected)
.key("availableScenes") .key("availableScenes")
# TODO: add assemblerOverview scene
.setNewDefaultValue(["scene", "assemblerOverview"]) .setNewDefaultValue(["scene", "assemblerOverview"])
.commit(), .commit(),
FLOAT_ELEMENT(expected) FLOAT_ELEMENT(expected)
.key("processingTime") .key("processingTime")
.unit(Unit.SECOND) .unit(Unit.SECOND)
...@@ -61,6 +63,7 @@ class SimpleAssembler(TrainMatcher.TrainMatcher): ...@@ -61,6 +63,7 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
.info("Cannot keep up with GUI limit") .info("Cannot keep up with GUI limit")
.needsAcknowledging(False) .needsAcknowledging(False)
.commit(), .commit(),
FLOAT_ELEMENT(expected) FLOAT_ELEMENT(expected)
.key("timeOfFlight") .key("timeOfFlight")
.unit(Unit.SECOND) .unit(Unit.SECOND)
...@@ -71,15 +74,18 @@ class SimpleAssembler(TrainMatcher.TrainMatcher): ...@@ -71,15 +74,18 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
.info("Time of flight exceeding 1 s") .info("Time of flight exceeding 1 s")
.needsAcknowledging(False) .needsAcknowledging(False)
.commit(), .commit(),
STRING_ELEMENT(expected) STRING_ELEMENT(expected)
.key("pathToStack") .key("pathToStack")
.assignmentOptional() .assignmentOptional()
.defaultValue("image.data") .defaultValue("image.data")
.commit(), .commit(),
INPUT_CHANNEL(expected) INPUT_CHANNEL(expected)
.key("geometryInput") .key("geometryInput")
.displayedName("Geometry input") .displayedName("Geometry input")
.commit(), .commit(),
OUTPUT_CHANNEL(expected) # can OVERWRITE_ELEMENT even do this? OUTPUT_CHANNEL(expected) # can OVERWRITE_ELEMENT even do this?
.key("output") .key("output")
.dataSchema(preview_schema) .dataSchema(preview_schema)
...@@ -145,7 +151,7 @@ class SimpleAssembler(TrainMatcher.TrainMatcher): ...@@ -145,7 +151,7 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
module_indices_unfilled.discard(module_index) module_indices_unfilled.discard(module_index)
for unfilled_module in module_indices_unfilled: 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: configurable treatment of missing modules
# TODO: reusable output buffer to save on allocation # TODO: reusable output buffer to save on allocation
...@@ -179,8 +185,15 @@ class SimpleAssembler(TrainMatcher.TrainMatcher): ...@@ -179,8 +185,15 @@ class SimpleAssembler(TrainMatcher.TrainMatcher):
@functools.lru_cache @functools.lru_cache
def _source_to_index(self, source): def _source_to_index(self, source):
# note: cache means warning only shows up once (also not performance-critical) # 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) match = xtdf_source_re.match(source)
if match is None: if match is not None:
self.log.WARN(f"Couldn't figure out index for source {source}") return int(match.group(1))
return 0
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 pickle
import matplotlib.pyplot as plt
import numpy as np
from karabo.bound import ( from karabo.bound import (
DOUBLE_ELEMENT, DOUBLE_ELEMENT,
KARABO_CLASSINFO,
IMAGEDATA_ELEMENT, IMAGEDATA_ELEMENT,
INT32_ELEMENT,
KARABO_CLASSINFO,
NODE_ELEMENT, NODE_ELEMENT,
OUTPUT_CHANNEL, OUTPUT_CHANNEL,
SLOT_ELEMENT, SLOT_ELEMENT,
TABLE_ELEMENT,
VECTOR_CHAR_ELEMENT, VECTOR_CHAR_ELEMENT,
VECTOR_STRING_ELEMENT, VECTOR_STRING_ELEMENT,
Encoding, Encoding,
...@@ -17,14 +21,11 @@ from karabo.bound import ( ...@@ -17,14 +21,11 @@ from karabo.bound import (
State, State,
) )
from karabo.common.api import KARABO_SCHEMA_DISPLAY_TYPE_SCENES as DT_SCENES from karabo.common.api import KARABO_SCHEMA_DISPLAY_TYPE_SCENES as DT_SCENES
import numpy as np
from matplotlib.backends.backend_agg import FigureCanvasAgg from matplotlib.backends.backend_agg import FigureCanvasAgg
import matplotlib.pyplot as plt
from . import scenes from . import scenes
from ._version import version as deviceVersion from ._version import version as deviceVersion
geometry_schema = Schema() geometry_schema = Schema()
( (
VECTOR_CHAR_ELEMENT(geometry_schema) VECTOR_CHAR_ELEMENT(geometry_schema)
...@@ -38,6 +39,37 @@ geometry_schema = Schema() ...@@ -38,6 +39,37 @@ geometry_schema = Schema()
preview_schema = Schema() preview_schema = Schema()
(IMAGEDATA_ELEMENT(preview_schema).key("overview").commit()) (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) @KARABO_CLASSINFO("ManualGeometryBase", deviceVersion)
class ManualGeometryBase(PythonDevice): class ManualGeometryBase(PythonDevice):
...@@ -49,37 +81,20 @@ class ManualGeometryBase(PythonDevice): ...@@ -49,37 +81,20 @@ class ManualGeometryBase(PythonDevice):
.key("geometryOutput") .key("geometryOutput")
.dataSchema(geometry_schema) .dataSchema(geometry_schema)
.commit(), .commit(),
SLOT_ELEMENT(expected).key("pleaseSendYourGeometry").commit(), SLOT_ELEMENT(expected).key("pleaseSendYourGeometry").commit(),
SLOT_ELEMENT(expected).key("reloadScenes").commit(), SLOT_ELEMENT(expected).key("reloadScenes").commit(),
OUTPUT_CHANNEL(expected) OUTPUT_CHANNEL(expected)
.key("previewOutput") .key("previewOutput")
.dataSchema(preview_schema) .dataSchema(preview_schema)
.commit(), .commit(),
IMAGEDATA_ELEMENT(expected).key("layoutPreview").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 # scenes are fun
# TODO: add the scene
( (
VECTOR_STRING_ELEMENT(expected) VECTOR_STRING_ELEMENT(expected)
.key("availableScenes") .key("availableScenes")
...@@ -89,6 +104,9 @@ class ManualGeometryBase(PythonDevice): ...@@ -89,6 +104,9 @@ class ManualGeometryBase(PythonDevice):
.commit(), .commit(),
) )
def update_geom(self):
raise NotImplementedError()
def __init__(self, config): def __init__(self, config):
super().__init__(config) super().__init__(config)
...@@ -116,22 +134,6 @@ class ManualGeometryBase(PythonDevice): ...@@ -116,22 +134,6 @@ class ManualGeometryBase(PythonDevice):
response["payload"] = payload response["payload"] = payload
self.reply(response) 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): def pleaseSendYourGeometry(self):
self.writeChannel("geometryOutput", Hash("pickledGeometry", self.pickled)) self.writeChannel("geometryOutput", Hash("pickledGeometry", self.pickled))
axis = self.geom.inspect() axis = self.geom.inspect()
...@@ -148,7 +150,6 @@ class ManualGeometryBase(PythonDevice): ...@@ -148,7 +150,6 @@ class ManualGeometryBase(PythonDevice):
"layoutPreview", "layoutPreview",
ImageData(image_buffer, encoding=Encoding.RGBA, bitsPerPixel=3 * 8), ImageData(image_buffer, encoding=Encoding.RGBA, bitsPerPixel=3 * 8),
) )
# self.writeChannel("previewOutput", Hash("overview", ImageData()))
def preReconfigure(self, config): def preReconfigure(self, config):
self._prereconfigure_update_hash = config self._prereconfigure_update_hash = config
...@@ -159,3 +160,68 @@ class ManualGeometryBase(PythonDevice): ...@@ -159,3 +160,68 @@ class ManualGeometryBase(PythonDevice):
for path in self._prereconfigure_update_hash.getPaths() for path in self._prereconfigure_update_hash.getPaths()
): ):
self.update_geom() 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