Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
calng
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
calibration
calng
Commits
4dfa248d
Commit
4dfa248d
authored
3 years ago
by
David Hammer
Browse files
Options
Downloads
Patches
Plain Diff
Geometry device: overhaul + allow loading CrystFEL
parent
2a21de06
No related branches found
No related tags found
1 merge request
!12
Snapshot: field test deployed version as of end of run 202201
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
src/calng/DetectorAssembler.py
+1
-1
1 addition, 1 deletion
src/calng/DetectorAssembler.py
src/calng/base_geometry.py
+210
-36
210 additions, 36 deletions
src/calng/base_geometry.py
src/calng/scenes.py
+1
-1
1 addition, 1 deletion
src/calng/scenes.py
with
212 additions
and
38 deletions
src/calng/DetectorAssembler.py
+
1
−
1
View file @
4dfa248d
...
@@ -243,7 +243,7 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
...
@@ -243,7 +243,7 @@ class DetectorAssembler(TrainMatcher.TrainMatcher):
continue
continue
geometry_device
=
geometry_device_list
[
0
].
split
(
"
:
"
)[
0
]
geometry_device
=
geometry_device_list
[
0
].
split
(
"
:
"
)[
0
]
self
.
log
.
INFO
(
f
"
Asking
{
geometry_device
}
for a geometry
"
)
self
.
log
.
INFO
(
f
"
Asking
{
geometry_device
}
for a geometry
"
)
self
.
signalSlotable
.
call
(
geometry_device
,
"
pleaseSendYour
Geometry
"
)
self
.
signalSlotable
.
call
(
geometry_device
,
"
send
Geometry
"
)
time
.
sleep
(
1
)
time
.
sleep
(
1
)
if
self
.
_geometry
is
not
None
:
if
self
.
_geometry
is
not
None
:
...
...
This diff is collapsed.
Click to expand it.
src/calng/base_geometry.py
+
210
−
36
View file @
4dfa248d
import
contextlib
import
pickle
import
pickle
import
matplotlib.pyplot
as
plt
import
matplotlib.pyplot
as
plt
import
numpy
as
np
import
numpy
as
np
from
karabo.bound
import
(
from
karabo.bound
import
(
BOOL_ELEMENT
,
DOUBLE_ELEMENT
,
DOUBLE_ELEMENT
,
IMAGEDATA_ELEMENT
,
IMAGEDATA_ELEMENT
,
INT32_ELEMENT
,
INT32_ELEMENT
,
KARABO_CLASSINFO
,
KARABO_CLASSINFO
,
NODE_ELEMENT
,
NODE_ELEMENT
,
OUTPUT_CHANNEL
,
OUTPUT_CHANNEL
,
OVERWRITE_ELEMENT
,
SLOT_ELEMENT
,
SLOT_ELEMENT
,
STRING_ELEMENT
,
TABLE_ELEMENT
,
TABLE_ELEMENT
,
VECTOR_CHAR_ELEMENT
,
VECTOR_CHAR_ELEMENT
,
VECTOR_STRING_ELEMENT
,
VECTOR_STRING_ELEMENT
,
...
@@ -73,8 +77,23 @@ ModuleColumn = Schema()
...
@@ -73,8 +77,23 @@ ModuleColumn = Schema()
@KARABO_CLASSINFO
(
"
ManualGeometryBase
"
,
deviceVersion
)
@KARABO_CLASSINFO
(
"
ManualGeometryBase
"
,
deviceVersion
)
class
ManualGeometryBase
(
PythonDevice
):
class
ManualGeometryBase
(
PythonDevice
):
geometry_class
=
None
# concrete device subclass must set this
@staticmethod
@staticmethod
def
expectedParameters
(
expected
):
def
expectedParameters
(
expected
):
# Karabo things
(
OVERWRITE_ELEMENT
(
expected
)
.
key
(
"
state
"
)
.
setNewDefaultValue
(
State
.
INIT
)
.
commit
(),
OVERWRITE_ELEMENT
(
expected
)
.
key
(
"
doNotCompressEvents
"
)
.
setNewDefaultValue
(
True
)
.
commit
(),
)
# "mandatory" for geometry serving device
# "mandatory" for geometry serving device
(
(
OUTPUT_CHANNEL
(
expected
)
OUTPUT_CHANNEL
(
expected
)
...
@@ -82,7 +101,23 @@ class ManualGeometryBase(PythonDevice):
...
@@ -82,7 +101,23 @@ class ManualGeometryBase(PythonDevice):
.
dataSchema
(
geometry_schema
)
.
dataSchema
(
geometry_schema
)
.
commit
(),
.
commit
(),
SLOT_ELEMENT
(
expected
).
key
(
"
pleaseSendYourGeometry
"
).
commit
(),
SLOT_ELEMENT
(
expected
)
.
key
(
"
sendGeometry
"
)
.
displayedName
(
"
Send geometry
"
)
.
description
(
"
Send current geometry on output channel. This output channel is
"
"
typically used by assembler devices waiting for new geometries.
"
"
Updating the geometry will usually automatically cause update, but
"
"
hit this slot in case geometry is missing somewhere.
"
)
.
allowedStates
(
State
.
ON
)
.
commit
(),
SLOT_ELEMENT
(
expected
)
.
key
(
"
updatePreview
"
)
.
displayedName
(
"
Update preview
"
)
.
allowedStates
(
State
.
ON
)
.
commit
(),
OUTPUT_CHANNEL
(
expected
)
OUTPUT_CHANNEL
(
expected
)
.
key
(
"
previewOutput
"
)
.
key
(
"
previewOutput
"
)
...
@@ -92,6 +127,53 @@ class ManualGeometryBase(PythonDevice):
...
@@ -92,6 +127,53 @@ class ManualGeometryBase(PythonDevice):
IMAGEDATA_ELEMENT
(
expected
).
key
(
"
layoutPreview
"
).
commit
(),
IMAGEDATA_ELEMENT
(
expected
).
key
(
"
layoutPreview
"
).
commit
(),
)
)
# options to load from file
# future plan: pick option from manual / file / encoder or other devices
(
NODE_ELEMENT
(
expected
)
.
key
(
"
geometryFile
"
)
.
displayedName
(
"
Geometry file
"
)
.
description
(
"
Allows loading geometry from CrystFEL geometry file
"
)
.
commit
(),
STRING_ELEMENT
(
expected
)
.
key
(
"
geometryFile.filePath
"
)
.
displayedName
(
"
File path
"
)
.
description
(
"
Full path (including filename and suffix) to the desired geometry
"
"
file. Keep in mind that the default directory is $KARABO/var/data on
"
"
device server node, so it
'
s probably wise to give absolute path.
"
)
.
assignmentOptional
()
.
defaultValue
(
""
)
.
reconfigurable
()
.
commit
(),
SLOT_ELEMENT
(
expected
)
.
key
(
"
geometryFile.load
"
)
.
displayedName
(
"
Load file
"
)
.
description
(
"
Trigger loading from file. Automatically called after starting device
"
"
if geometryFile.filePath is set. Should be manually called after
"
"
changing file path. In case loading the file fails, manual settings
"
"
will be used.
"
)
.
allowedStates
(
State
.
ON
)
.
commit
(),
BOOL_ELEMENT
(
expected
)
.
key
(
"
geometryFile.updateManualOnLoad
"
)
.
displayedName
(
"
Update manual settings
"
)
.
description
(
"
If this flag is on, the manual settings on this device will be
"
"
updated according to the loaded geometry file. This is useful when
"
"
you want to load a file and then tweak the geometry a bit.
"
)
.
assignmentOptional
()
.
defaultValue
(
True
)
.
commit
(),
)
# scenes are fun
# scenes are fun
(
(
VECTOR_STRING_ELEMENT
(
expected
)
VECTOR_STRING_ELEMENT
(
expected
)
...
@@ -102,21 +184,75 @@ class ManualGeometryBase(PythonDevice):
...
@@ -102,21 +184,75 @@ 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
)
self
.
KARABO_SLOT
(
self
.
pleaseSendYourGeometry
)
# slots go in __init__
self
.
KARABO_SLOT
(
self
.
sendGeometry
)
self
.
KARABO_SLOT
(
self
.
updatePreview
)
self
.
KARABO_SLOT
(
self
.
requestScene
)
self
.
KARABO_SLOT
(
self
.
requestScene
)
self
.
update_geom
()
self
.
KARABO_SLOT
(
self
.
load_geometry_from_file
,
slotName
=
"
geometryFile_load
"
)
plt
.
switch_backend
(
"
agg
"
)
plt
.
switch_backend
(
"
agg
"
)
# plotting backend which works for preview hack
# these will be set by load_geometry_from_file or get_manual_geometry
self
.
geometry
=
None
self
.
pickled_geometry
=
None
self
.
registerInitialFunction
(
self
.
_initialization
)
self
.
registerInitialFunction
(
self
.
_initialization
)
def
_initialization
(
self
):
def
_initialization
(
self
):
if
self
.
get
(
"
geometryFile.filePath
"
):
self
.
log_status_info
(
"
geometryFile.filePath set, will try to load geometry
"
)
self
.
load_geometry_from_file
()
if
self
.
geometry
is
None
:
# no file path or loading failed
self
.
get_manual_geometry
()
self
.
updateState
(
State
.
ON
)
self
.
updateState
(
State
.
ON
)
self
.
pleaseSendYourGeometry
()
def
_set_geometry
(
self
,
geometry
,
update_preview
=
True
,
send
=
True
):
self
.
geometry
=
geometry
self
.
pickled_geometry
=
pickle
.
dumps
(
self
.
geometry
)
if
update_preview
:
self
.
updatePreview
()
if
send
:
self
.
sendGeometry
()
def
get_manual_geometry
(
self
):
# subclass must implement this
raise
NotImplementedError
()
def
_update_manual_from_current
(
self
):
# subclass should implement this
# TODO: figure out for JUNGFRAUGeometry
raise
NotImplementedError
()
def
load_geometry_from_file
(
self
):
with
self
.
push_state
(
State
.
CHANGING
):
geometry
=
None
file_path
=
self
.
get
(
"
geometryFile.filePath
"
)
self
.
log_status_info
(
f
"
Loading geometry from
{
file_path
}
...
"
)
try
:
geometry
=
self
.
geometry_class
.
from_crystfel_geom
(
file_path
)
except
FileNotFoundError
:
self
.
log_status_warn
(
"
Geometry file not found
"
)
except
RuntimeError
as
e
:
self
.
log_status_warn
(
f
"
Failed to load geometry file:
{
e
}
"
)
except
Exception
as
e
:
self
.
log_status_warn
(
f
"
Misc. exception when loading geometry file:
{
e
}
"
)
else
:
self
.
_set_geometry
(
geometry
)
self
.
log_status_info
(
"
Successfully loaded geometry from file
"
)
if
self
.
get
(
"
geometryFile.updateManualOnLoad
"
):
self
.
log_status_info
(
"
Updating manual settings on device to reflect loaded geometry
"
)
self
.
_update_manual_from_current
()
return
True
return
False
def
requestScene
(
self
,
params
):
def
requestScene
(
self
,
params
):
payload
=
Hash
()
payload
=
Hash
()
...
@@ -135,10 +271,13 @@ class ManualGeometryBase(PythonDevice):
...
@@ -135,10 +271,13 @@ class ManualGeometryBase(PythonDevice):
response
[
"
payload
"
]
=
payload
response
[
"
payload
"
]
=
payload
self
.
reply
(
response
)
self
.
reply
(
response
)
def
pleaseSendYourGeometry
(
self
):
def
sendGeometry
(
self
):
self
.
update_geom
()
self
.
writeChannel
(
self
.
writeChannel
(
"
geometryOutput
"
,
Hash
(
"
pickledGeometry
"
,
self
.
pickled
))
"
geometryOutput
"
,
Hash
(
"
pickledGeometry
"
,
self
.
pickled_geometry
)
axis
=
self
.
geom
.
inspect
()
)
def
updatePreview
(
self
):
axis
=
self
.
geometry
.
inspect
()
axis
.
figure
.
tight_layout
(
pad
=
0
)
axis
.
figure
.
tight_layout
(
pad
=
0
)
axis
.
figure
.
set_facecolor
(
"
none
"
)
axis
.
figure
.
set_facecolor
(
"
none
"
)
# axis.figure.set_size_inches(6, 6)
# axis.figure.set_size_inches(6, 6)
...
@@ -152,6 +291,7 @@ class ManualGeometryBase(PythonDevice):
...
@@ -152,6 +291,7 @@ class ManualGeometryBase(PythonDevice):
"
layoutPreview
"
,
"
layoutPreview
"
,
ImageData
(
image_buffer
,
encoding
=
Encoding
.
RGBA
,
bitsPerPixel
=
3
*
8
),
ImageData
(
image_buffer
,
encoding
=
Encoding
.
RGBA
,
bitsPerPixel
=
3
*
8
),
)
)
self
.
log_status_info
(
"
Preview updated
"
)
def
preReconfigure
(
self
,
config
):
def
preReconfigure
(
self
,
config
):
self
.
_prereconfigure_update_hash
=
config
self
.
_prereconfigure_update_hash
=
config
...
@@ -159,6 +299,23 @@ class ManualGeometryBase(PythonDevice):
...
@@ -159,6 +299,23 @@ class ManualGeometryBase(PythonDevice):
def
postReconfigure
(
self
):
def
postReconfigure
(
self
):
del
self
.
_prereconfigure_update_hash
del
self
.
_prereconfigure_update_hash
def
log_status_info
(
self
,
msg
):
self
.
log
.
INFO
(
msg
)
self
.
set
(
"
status
"
,
msg
)
def
log_status_warn
(
self
,
msg
):
self
.
log
.
WARN
(
msg
)
self
.
set
(
"
status
"
,
msg
)
@contextlib.contextmanager
def
push_state
(
self
,
state
):
previous_state
=
self
.
get
(
"
state
"
)
self
.
updateState
(
state
)
try
:
yield
finally
:
self
.
updateState
(
previous_state
)
@KARABO_CLASSINFO
(
"
ManualQuadrantsGeometryBase
"
,
deviceVersion
)
@KARABO_CLASSINFO
(
"
ManualQuadrantsGeometryBase
"
,
deviceVersion
)
class
ManualQuadrantsGeometryBase
(
ManualGeometryBase
):
class
ManualQuadrantsGeometryBase
(
ManualGeometryBase
):
...
@@ -189,19 +346,29 @@ class ManualQuadrantsGeometryBase(ManualGeometryBase):
...
@@ -189,19 +346,29 @@ class ManualQuadrantsGeometryBase(ManualGeometryBase):
path
.
startswith
(
"
quadrantCorners
"
)
path
.
startswith
(
"
quadrantCorners
"
)
for
path
in
self
.
_prereconfigure_update_hash
.
getPaths
()
for
path
in
self
.
_prereconfigure_update_hash
.
getPaths
()
):
):
self
.
update
_geom
()
self
.
get_manual
_geom
etry
()
super
().
postReconfigure
()
super
().
postReconfigure
()
def
update_geom
(
self
):
def
get_manual_geometry
(
self
):
self
.
quadrant_corners
=
tuple
(
self
.
log_status_info
(
"
Updating geometry from manual configuration
"
)
(
self
.
get
(
f
"
quadrantCorners.Q
{
q
}
.x
"
),
self
.
get
(
f
"
quadrantCorners.Q
{
q
}
.y
"
))
with
self
.
push_state
(
State
.
CHANGING
):
for
q
in
range
(
1
,
5
)
self
.
quadrant_corners
=
tuple
(
)
(
self
.
geom
=
self
.
geometry_class
.
from_quad_positions
(
self
.
quadrant_corners
)
self
.
get
(
f
"
quadrantCorners.Q
{
q
}
.x
"
),
self
.
pickled
=
pickle
.
dumps
(
self
.
geom
)
self
.
get
(
f
"
quadrantCorners.Q
{
q
}
.y
"
),
# TODO: send to anyone who asks? make slot for that? send on connect?
)
self
.
writeChannel
(
"
geometryOutput
"
,
Hash
(
"
pickledGeometry
"
,
self
.
pickled
))
for
q
in
range
(
1
,
5
)
)
geometry
=
self
.
geometry_class
.
from_quad_positions
(
self
.
quadrant_corners
)
self
.
_set_geometry
(
geometry
)
def
_update_manual_from_current
(
self
):
update
=
Hash
()
for
(
x
,
y
),
quadrant
in
zip
(
self
.
geometry
.
quad_positions
(),
range
(
1
,
5
)):
update
.
set
(
f
"
quadrantCorners.Q
{
quadrant
}
.x
"
,
x
)
update
.
set
(
f
"
quadrantCorners.Q
{
quadrant
}
.y
"
,
y
)
self
.
set
(
update
)
@KARABO_CLASSINFO
(
"
ManualModulesGeometryBase
"
,
deviceVersion
)
@KARABO_CLASSINFO
(
"
ManualModulesGeometryBase
"
,
deviceVersion
)
...
@@ -216,24 +383,31 @@ class ManualModulesGeometryBase(ManualGeometryBase):
...
@@ -216,24 +383,31 @@ class ManualModulesGeometryBase(ManualGeometryBase):
.
defaultValue
([])
.
defaultValue
([])
.
reconfigurable
()
.
reconfigurable
()
.
commit
(),
.
commit
(),
OVERWRITE_ELEMENT
(
expected
)
.
key
(
"
geometryFile.updateManualOnLoad
"
)
.
setNewDefaultValue
(
False
)
.
commit
(),
)
)
def
postReconfigure
(
self
):
def
postReconfigure
(
self
):
if
self
.
_prereconfigure_update_hash
.
has
(
"
modules
"
):
if
self
.
_prereconfigure_update_hash
.
has
(
"
modules
"
):
self
.
update
_geom
()
self
.
get_manual
_geom
etry
()
super
().
postReconfigure
()
super
().
postReconfigure
()
def
update_geom
(
self
):
def
get_manual_geometry
(
self
):
modules
=
self
.
get
(
"
modules
"
)
self
.
log_status_info
(
"
Updating geometry from manual configuration
"
)
module_pos
=
[(
module
.
get
(
"
posX
"
),
module
.
get
(
"
posY
"
))
for
module
in
modules
]
with
self
.
push_state
(
State
.
CHANGING
):
orientations
=
[
modules
=
self
.
get
(
"
modules
"
)
(
module
.
get
(
"
orientationX
"
),
module
.
get
(
"
orientationY
"
))
module_pos
=
[
for
module
in
modules
(
module
.
get
(
"
posX
"
),
module
.
get
(
"
posY
"
))
for
module
in
modules
]
]
self
.
geom
=
self
.
geometry_class
.
from_module_positions
(
orientations
=
[
module_pos
,
orientations
=
orientations
(
module
.
get
(
"
orientationX
"
),
module
.
get
(
"
orientationY
"
))
)
for
module
in
modules
self
.
pickled
=
pickle
.
dumps
(
self
.
geom
)
]
# TODO: send to anyone who asks? make slot for that?
geometry
=
self
.
geometry_class
.
from_module_positions
(
self
.
writeChannel
(
"
geometryOutput
"
,
Hash
(
"
pickledGeometry
"
,
self
.
pickled
))
module_pos
,
orientations
=
orientations
)
self
.
_set_geometry
(
geometry
)
This diff is collapsed.
Click to expand it.
src/calng/scenes.py
+
1
−
1
View file @
4dfa248d
...
@@ -810,7 +810,7 @@ def detector_assembler_overview(device_id, geometry_device_id):
...
@@ -810,7 +810,7 @@ def detector_assembler_overview(device_id, geometry_device_id):
height
=
BASE_INC
,
height
=
BASE_INC
,
),
),
DisplayCommandModel
(
DisplayCommandModel
(
keys
=
[
f
"
{
geometry_device_id
}
.
pleaseSendYour
Geometry
"
],
keys
=
[
f
"
{
geometry_device_id
}
.
send
Geometry
"
],
width
=
14
*
BASE_INC
,
width
=
14
*
BASE_INC
,
height
=
BASE_INC
,
height
=
BASE_INC
,
),
),
...
...
This diff is collapsed.
Click to expand it.
David Hammer
@hammerd
mentioned in commit
3566342d
·
2 years ago
mentioned in commit
3566342d
mentioned in commit 3566342d031db1bb435b6430f100afdbaaa6c4bf
Toggle commit list
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment