Skip to content

Commit

Permalink
Merge branch 'i18_pymalcolm' into 'master'
Browse files Browse the repository at this point in the history
Add Xspress ODIN support

See merge request controls/python3/pymalcolm!1
  • Loading branch information
tomtrafford committed Feb 26, 2024
2 parents 7f50f03 + 883569c commit 30b2536
Show file tree
Hide file tree
Showing 10 changed files with 748 additions and 8 deletions.
2 changes: 1 addition & 1 deletion malcolm/modules/ADCore/parts/hdfwriterpart.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import os
import time
import h5py
from typing import Dict, Iterator, List, Optional
from xml.etree import cElementTree as ET

import h5py
from annotypes import Anno, add_call_types
from scanpointgenerator import CompoundGenerator, Dimension

Expand Down
6 changes: 0 additions & 6 deletions malcolm/modules/ADOdin/blocks/odin_writer_block.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,6 @@
description: type of the pixel data
rbv: $(prefix):DataType

#- ca.parts.CALongPa#-rt:
# name: flushData# PerNFrames
# description: Nu# mber of frames to capture between HDF dataset flushes
# pv: $(prefix):N# umFramesFlush
# rbv_suffix: _RB# V

# Filename
- ca.parts.CACharArrayPart:
name: filePath
Expand Down
39 changes: 39 additions & 0 deletions malcolm/modules/ADOdin/parts/odinwriterpart.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,29 @@ def create_dataset_infos(
)


def create_raw_dataset_infos(
name: str, rank: int, filename: str, n_raw: int
) -> Iterator[Info]:
for i in range(n_raw + 1):
yield scanning.infos.DatasetProducedInfo(
name=f"{name}.raw{i+1}",
filename=filename,
type=scanning.infos.DatasetType.RAW,
rank=rank,
path="/raw" + str(i + 1),
uniqueid="",
)
for i in range(n_raw + 1):
yield scanning.infos.DatasetProducedInfo(
name=f"{name}.uid{i+1}",
filename=filename,
type=scanning.infos.DatasetType.RAW,
rank=rank,
path="/uid" + str(i + 1),
uniqueid="",
)


def files_shape(frames, block_size, file_count):
# all files get at least per_file blocks
per_file = int(frames) / int(file_count * block_size)
Expand Down Expand Up @@ -173,6 +196,12 @@ def create_vds(generator, raw_name, vds_path, child, uid_name, sum_name):
"data",
data_type.lower(),
)
with h5py.File(vds_path, "r+", libver="latest") as vds:
count = 1
for f in files:
vds["raw" + str(count)] = h5py.ExternalLink(f, "/data")
vds["uid" + str(count)] = h5py.ExternalLink(f, "/uid")
count += 1

shape = (hdf_shape, 1, 1)

Expand Down Expand Up @@ -385,6 +414,16 @@ def on_configure(
dataset_infos = list(
create_dataset_infos(formatName, generator, fileName, self.secondary_set)
)

dataset_infos += list(
create_raw_dataset_infos(
formatName,
len(generator.dimensions) + 2,
fileName,
int(child.numProcesses.value),
)
)

return dataset_infos

@add_call_types
Expand Down
2 changes: 2 additions & 0 deletions malcolm/modules/scanning/infos.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ class DatasetType(Enum):
PRIMARY = "primary"
#: Calculated from detector data, like the sum of each frame
SECONDARY = "secondary"
#: Raw data sets (used when linking to raw odin datasets)
RAW = "raw"
#: Data that only makes sense when considered with detector data, like a
#: measure of beam current with an ion chamber
MONITOR = "monitor"
Expand Down
1 change: 1 addition & 0 deletions malcolm/modules/xspress3/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import parts
5 changes: 4 additions & 1 deletion malcolm/modules/xspress3/blocks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
xspress3_driver_block = make_block_creator(__file__, "xspress3_driver_block.yaml")
xspress3_dtc_block = make_block_creator(__file__, "xspress3_dtc_block.yaml")
xspress3_runnable_block = make_block_creator(__file__, "xspress3_runnable_block.yaml")

xspress3_writer_block = make_block_creator(__file__, "xspress3_writer_block.yaml")
xspress3_odin_runnable_block = make_block_creator(
__file__, "xspress3_odin_runnable_block.yaml"
)
__all__ = check_yaml_names(globals())
83 changes: 83 additions & 0 deletions malcolm/modules/xspress3/blocks/xspress3_odin_runnable_block.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
- builtin.parameters.string:
name: mri_prefix
description: Malcolm resource id of the Block and prefix for children

- builtin.parameters.string:
name: pv_prefix
description: PV prefix for driver and all plugins

- builtin.parameters.string:
name: config_dir
description: Where to store saved configs

- builtin.parameters.string:
name: label
description: Beamline specific label for the detector
default: Xspress 3

- builtin.parameters.string:
name: drv_suffix
description: PV suffix for detector driver

- builtin.parameters.int32:
name: processes
description: Number of FR/FP pairs

- builtin.parameters.int32:
name: num_datasets
description: Total number of datasets that will be writen

- builtin.parameters.string:
name: writer_suffix
description: PV suffix for Odin data writer
default: OD

- scanning.controllers.RunnableController:
mri: $(mri_prefix)
config_dir: $(config_dir)
description: |
Xspress3 is a solid state detector capable of acquiring at high count rates
- builtin.parameters.string:
name: sum_name
description: name of the sum dataset

- builtin.parts.LabelPart:
value: $(label)

- xspress3.blocks.xspress3_driver_block:
mri: $(mri_prefix):$(drv_suffix)
prefix: $(pv_prefix):$(drv_suffix)

- ADCore.parts.DetectorDriverPart:
name: Xspress3Odin
mri: $(mri_prefix):$(drv_suffix)

- scanning.parts.ExposureDeadtimePart:
name: DEADTIME
readout_time: 7e-5

- builtin.parts.IconPart:
svg: $(yamldir)/../icons/quantum_detectors.svg

# Adding what might be needed for the Xspress3 Odin writer

- builtin.parameters.string:
name: secondary_set
description: Name of secondary dataset to link in nxs file
default: sum

- xspress3.blocks.xspress3_writer_block:
mri: $(mri_prefix):$(writer_suffix)
prefix: $(pv_prefix):$(writer_suffix)

- xspress3.parts.XspressWriterPart:
name: XSPRESSWRITER
mri: $(mri_prefix):$(writer_suffix)
sum_name: $(sum_name)
secondary_set: $(secondary_set)
num_pairs: $(processes)
num_datasets: $(num_datasets)

- scanning.parts.DatasetTablePart:
name: DSET
119 changes: 119 additions & 0 deletions malcolm/modules/xspress3/blocks/xspress3_writer_block.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
- builtin.parameters.string:
name: mri
description: Malcolm resource id of the Block

- builtin.parameters.string:
name: prefix
description: The root PV for the all records

- builtin.defines.docstring:
value: |
Hardware block corresponding to PVs used for Odin File Writer
- OdinDataDriver.template should have pv prefix $(prefix)
- builtin.controllers.StatefulController:
mri: $(mri)
description: $(docstring)

- ca.parts.CALongPart:
name: numCapture
description: Number of frames to capture
pv: $(prefix):NumCapture
rbv_suffix: _RBV

- ca.parts.CALongPart:
name: numCaptured
description: Number of frames captured since last 'start'
rbv: $(prefix):NumCaptured_RBV

- ca.parts.CALongPart:
name: numProcesses
description: number of receiver/writer pairs and hence HDF files
rbv: $(prefix):NumProcesses_RBV

- ca.parts.CALongPart:
name: imageHeight
description: Height of the data frames
pv: $(prefix):ImageHeight
rbv_suffix: _RBV

- ca.parts.CALongPart:
name: imageWidth
description: Width of the data frames
pv: $(prefix):ImageWidth
rbv_suffix: _RBV

- ca.parts.CALongPart:
name: numFramesChunks
description: Size of chunks in frames
pv: $(prefix):NumFramesChunks
rbv_suffix: _RBV

- ca.parts.CALongPart:
name: numRowChunks
description: Number of Rows per Chunk
pv: $(prefix):NumRowChunks
rbv_suffix: _RBV

- ca.parts.CALongPart:
name: numColChunks
description: Number of Columns per Chunk
pv: $(prefix):NumColChunks
rbv_suffix: _RBV

- ca.parts.CALongPart:
name: blockSize
description: Number of contiguous frames written to each file
pv: $(prefix):BlockSize
rbv_suffix: _RBV

- ca.parts.CALongPart:
name: blocksPerFile
description: Number of blocks per file
pv: $(prefix):BlocksPerFile
rbv_suffix: _RBV

- ca.parts.CAStringPart:
name: dataType
description: type of the pixel data
rbv: $(prefix):DataType

# Filename
- ca.parts.CACharArrayPart:
name: filePath
description: Directory to write files into
pv: $(prefix):FilePath
rbv_suffix: _RBV

- ca.parts.CACharArrayPart:
name: fileName
description: Filename within directory
pv: $(prefix):FileName
rbv_suffix: _RBV

# commands
- ca.parts.CAActionPart:
name: start
description: Demand for starting acquisition
pv: $(prefix):Capture
status_pv: $(prefix):WriteStatus
good_status: Write OK

- ca.parts.CAActionPart:
name: stop
description: Demand for stopping acquisition
pv: $(prefix):Capture
value: 0
wait: False

# status
- ca.parts.CABooleanPart:
name: running
description: If detector is currently acquiring
rbv: $(prefix):Capture_RBV

- ca.parts.CACharArrayPart:
name: writeMessage
description: Error message if in error
rbv: $(prefix):WriteMessage
6 changes: 6 additions & 0 deletions malcolm/modules/xspress3/parts/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Expose a nice namespace
from malcolm.core import submodule_all

from .xspresswriterpart import AMri, APartName, XspressWriterPart

__all__ = submodule_all(globals())
Loading

0 comments on commit 30b2536

Please sign in to comment.