DanMAX TomoScan — APS collaboration
Background
Max IV (DanMAX beamline) is designing a new tomography scan macro (tomoscan)
for their Sardana/Tango control system. They circulated a requirements document
describing the intended workflow and parameters, below is a detailed description
of how it maps onto the existing APS 2-BM tomoscan implementation
(tomoscan-decarlof).
This page documents the comparison: first the architectural difference in how scan-related variables are stored and propagated into the HDF5 file, then a step-by-step and parameter-by-parameter match-up between the two implementations.
Where scan parameters live (and how they reach the HDF5 file)
The single most important architectural difference between the two
implementations is where each scan parameter lives at runtime and how it ends
up in the output HDF5 file (the /process group at 2-BM, the dxchange
section at Max IV).
2-BM model: parameters as EPICS PVs → NDAttributes → HDF5 layout
At 2-BM there are four cooperating pieces, none of which is Python writing HDF5:
PVs are defined in EPICS database templates (
.template) and instantiated by the IOC at boot from a.substitutionsfile:tomoScanApp/Db/tomoScan.template, tomoScan_2BM.template, tomoScan_PSO.template, tomoScan_Helical.template, …
Loaded by iocBoot/iocTomoScan_2BMB/tomoScan.substitutions + st.cmd.
Persistent across reboots via autosave (auto_settings.req, save_restore.cmd). User-edited scan parameters survive IOC restarts.
Every parameter is therefore a named, network-addressable record that any EPICS client (MEDM, pyepics,
caputfrom a shell) can read or write at any time — not justtomoscan.
TomoScanDetectorAttributes.xml tells the areaDetector camera plugin to attach a list of EPICS PV values as NDAttributes to every image array. Excerpt:
<Attribute name="SampleX" type="EPICS_PV" source="2bmb:m63.RBV" ... /> <Attribute name="RingCurrent" type="EPICS_PV" source="S:SRcurrentAI" ... />
At runtime the camera IOC reads each
sourcePV and tags each NDArray withname=value. This file is selected at scan start via theCamNDAttributesFilePV (tomoscan_2bm.py:58).TomoScanLayout.xml tells the ADHdf5 file-writer plugin how to build the HDF5 tree and which NDAttribute populates each dataset. The
/processgroup seen in 2-BM output files is declared here:<group name="process"> <group name="acquisition"> <dataset name="scan_type" source="ndattribute" ndattribute="ScanType" when="OnFileOpen"/> <group name="sample"> <dataset name="in_x" source="ndattribute" ndattribute="SampleInX" when="OnFileClose"/> ...
Selected at scan start via the
FPXMLFileNamePV (tomoscan_2bm.py:59). The same layout file also places image data under/exchange/data,/exchange/data_white,/exchange/data_dark(the DXchange convention).Python TomoScan2BM does not write HDF5 itself (except the two add-ons
add_theta()andweb_camera_frame,tomoscan_2bm.py:531–588). It just sets PVs and starts the acquisition; the IOC’s C++ writer plugin assembles/process,/measurement,/exchange, etc. from the NDAttribute stream flowing through the plugin chain.
Consequences:
Parameters are persistent (autosave) and introspectable (any EPICS client).
A free MEDM GUI — every parameter is already a PV.
Adding a new field in the HDF5 = add an
<Attribute>to the attributes XML + a<dataset>to the layout XML. No Python change required.HDF5 writing happens in IOC C++ at line-rate; Python is out of the per-frame loop.
Schema is fragmented across two XML files that must stay in sync (each parameter must be declared as an NDAttribute AND have a layout entry).
Max IV model: macro args + Tango attributes → JSON-driven Python writer
From the Max IV requirements document, parameters live in three different places, none of them a persistent named record per parameter:
Most scan parameters are macro arguments to the
tomoscanSardana call:scan_type,rot_mot,scan_start,scan_end,nsteps,exp_time,latency,npt_fields,tomo_det,posflat,condition,tori_name,center, plus the binaryfields_flagstring. They exist only for the duration of the macro call — per-scan, no autosave, no IOC.Some parameters live as Tango device attributes on the
tomo/configuratordevice — the document explicitly mentionsDarkFileandWhiteFilebeing updated on it (steps 2.4, 3.8). The detector device carries atomo_det.labelTango attribute that the macro sets to"dark","flat","proj",""to label each phase (steps 2.2, 2.5, 3.5, 3.11, 4.1, …).Environment context comes from Sardana env vars — e.g.
self.getEnv('ScanDir')(used in step 3.1 to locate the visit folder and.positions/directory).
The HDF5 itself is built by Python code (the make_dxchange_file()
function in danmax_tomo.py) driven by a dxchange_configuration.json
mapping file. The JSON describes each output dataset as one of four kinds:
Entry type |
Source of value |
|---|---|
|
Symbolic link to a dataset (or slice) in another HDF5 file |
|
Copy of a dataset (or slice) in another HDF5 file |
|
Read from a Tango attribute at write-time |
|
Literal value provided in the JSON |
So the analog of 2-BM’s
<Attribute … type="EPICS_PV" source="…"> is the JSON tango entry; the
analog of layout’s
<dataset name="in_x" ndattribute="SampleInX"/> is a JSON entry mapping
process/acquisition/sample/in_x ← tango://…/SampleInX.
Side-by-side: where scan parameters live and how they reach HDF5
Concern |
2-BM (EPICS) |
Max IV (Sardana/Tango) |
|---|---|---|
Where a scan parameter “lives” |
Persistent EPICS PV in the tomoscan IOC |
Macro argument (per-call) + selected Tango device attributes |
Persistence across reboots |
Autosave restores all PVs |
None inherent — user re-types args (or wraps in a Sardana macro/script that hard-codes them) |
External readability |
Any EPICS client at any time |
Only callers that know the Tango device + attribute, or readers of
|
GUI |
Free MEDM screen, one widget per PV |
Sardana CLI/GUI per macro; |
HDF5 writer |
areaDetector ADHdf5 plugin (C++, in IOC) — Python is not in the per-frame path |
Pure Python ( |
Mapping PV/attribute → HDF5 path |
Two XML files ( |
One JSON file ( |
Entry types supported |
NDAttribute (EPICS_PV, EPICS_PV.timestamp, PARAM, …), constant value, dataset from frames |
|
When values are sampled |
Per |
At HDF5 write time (after scan) — |
Adding a new metadata field |
Add |
Add an entry to the JSON config; Python |
Where DXchange image data comes from |
Written by the file plugin in real time from the NDArray stream,
into |
Linked ( |
Number of HDF5 files per scan |
One (DXchange groups live inside the single ADHdf5 file) |
Open in the spec — either the Sardana master |
|
Built automatically by the layout XML group of the same name |
Built by JSON entries pulling from Tango attributes / values |
Architectural takeaway. At 2-BM, the IOC is the source of truth for scan parameters and the file plugin is the writer; Python is a thin orchestrator. At Max IV, the macro call is the source of truth for scan parameters and a Python function with a JSON spec is the writer; persistent state is limited to whatever the configurator Tango device chooses to expose.
The trade-off is:
2-BM gets persistence, free GUIs, external scriptability of every parameter, and Python out of the per-frame data path — at the cost of an EPICS IOC + autosave + two XML files to keep in sync.
Max IV gets simpler deployment (no IOC), config in one JSON, and the flexibility of
h5 link/copyto compose dxchange from arbitrary Sardana scan files — at the cost of no parameter persistence, no native GUI, and Python in the metadata-writing path.
If Max IV wants the 2-BM-style “every scan parameter is its own named,
persistent, externally-visible record,” the equivalent move in their stack
would be to promote each scan parameter to a memorized attribute on
tomo/configurator rather than leaving them as transient macro arguments.
Scan-sequence step-by-step comparison
The Max IV requirements document lists 11 ordered steps for the scan macro. The table below maps each step to the matching 2-BM behaviour and points to the relevant source location.
# |
Max IV requirement |
2-BM status |
Where in 2-BM code / notes |
|---|---|---|---|
1 |
Arm area + scalar detector ONCE for all frames (total = dark + flat + proj + ortho + flat_after) |
Partial mismatch. File plugin is armed once for the total frame count, but the area detector itself is re-armed per phase (Internal mode for dark/flat, PSOExternal for projections). |
|
2 |
Dark before (optional) |
Match. |
|
3 |
Flat before (optional) |
Match (but no |
|
4 |
Sample angular scan, branching on |
Partial. 2-BM supports Standard (fly), Helical, Step, FPGA, Stream
variants — but as separate Python classes, not a single |
|
5 |
Collect orthogonal angles on rotation back (every 90°) |
MISSING. |
No feature in any 2-BM variant. Return-to-start just rotates back. |
6 |
Flat after (optional) |
Match. |
|
7 |
Close fast shutter |
Match. |
|
8 |
Dark after (optional) |
Match. |
|
9 |
Create dxchange file |
Match (different mechanism). |
2-BM writes DXchange-compliant HDF5 directly via the AreaDetector
ADHdf5 plugin using |
10 |
Rotate back to start (optional) |
Match. |
|
11 |
Initiate reconstruction (tori file, auto COR, etc.) |
No built-in recon trigger. Closest analog: post-scan FDT/SCP data
transfer to analysis machine ( |
No |
Scan-parameter comparison
Max IV parameter |
2-BM equivalent |
Notes |
|---|---|---|
|
Not used. Individual EPICS PVs/enums ( |
Max IV’s “binary key” UX has no 2-BM analog. |
|
|
Combined into one enum. |
|
|
Combined into one enum. |
|
Missing. |
No orthogonal-back-projection feature. |
|
|
|
|
|
Separated. |
|
Partial — encoded as class choice, not parameter. |
|
|
|
Hard-coded per beamline, not a runtime arg. |
|
|
|
|
|
2-BM extra: separate flat exposure time. |
|
Implicit (camera/PSO timing in |
No user-facing latency parameter. |
|
Two mechanisms. (1) Runtime swap between two pre-wired cameras via
the |
Open question in the Max IV spec: auto-detect which detector(s) in the Sardana measurement group are 2D, and potentially write one dxchange file per active 2D detector (concurrent multi-detector). |
|
Partial match. 2-BM has a dedicated “move sample out for flats”
mechanism via |
Missing vs. Max IV: (a) only X, Y, and rotation are supported — no
way to script motion of arbitrary auxiliary motors (e.g. |
|
Hardcoded 2 s sleep after |
Not user-tunable. |
|
Missing. |
No reconstruction-config concept. |
Infrastructure / cross-cutting comparison
Topic |
2-BM |
Max IV requirement |
|---|---|---|
Trigger HW |
PSO (Aerotech) or FPGA (softGlueZynq) |
PandABox |
Shutter model |
Two shutters: front-end (slow) + fast |
One fast shutter |
Detector framework |
EPICS areaDetector + ADHdf5 file plugin |
Tango ( |
Frame labeling per phase |
Implicit via |
Explicit |
File format |
Single HDF5 (DXchange in |
Open question — extra |
DXchange entry generator |
XML layout drives the AreaDetector writer + |
JSON-driven ( |
Multi-detector support |
One acquiring at a time (Optique Peter dual-camera swap is runtime; a new camera model requires an IOC reboot) |
Open question (potentially one dxchange file per 2D det, concurrent) |
Web-camera snapshot into HDF5 |
Yes ( |
Not mentioned |
Post-scan data transfer |
FDT/SCP to analysis host |
Not mentioned (covered later by ReconBlazer) |
Streaming reconstruction hooks |
|
Not in initial scope |
Bottom line
Matched well: dark/flat before/after, return to start, single-HDF5 output with DXchange-style groups, optional features toggled per-scan, helical/step variants.
Missing in 2-BM (must build for Max IV):
Orthogonal projections on the way back to start.
Multi-motor / named-library flat-field positions. 2-BM already handles odd-shaped samples via
SampleOutAngleEnable+SampleOutAngle+SampleOutX/Y, but only with a fixed set of motors and a single preset. Max IV needs (a) arbitrary motor list per position, (b) a named library of positions stored as files under.positions/, and (c) validation that the named position exists before scan start.Reconstruction trigger with
tori/centerconfig.scan_typeas a runtime parameter unifying ascan / ascanct / dscan / dscanct / timescan.User-tunable scintillator
conditiondelay andlatencyparameter.fields_flagbinary-string UX.Concurrent multi-detector acquisition with per-detector dxchange routing.
2-BM features beyond the Max IV spec (worth porting):
Flat fields at a sample-specific angular position —
SampleOutAngleEnable+SampleOutAnglerotate the sample to a chosen angle before translating it out (SampleOutX,SampleOutY,FlatFieldAxis) and restore the pre-flat angle on return (tomoscan.py:443–450, 463–483). Critical for odd-shape samples where translating out at an arbitrary angle would otherwise clip the sample, the holder, or the field of view.Different exposure times for projections vs. flat fields —
DifferentFlatExposuretoggles a separateFlatExposureTimethat overridesExposureTimeduring flat-field collection. Critical for large / local tomography of very dense samples, where projections need a long exposure to penetrate the sample but flats (taken with no sample in the beam) would saturate the detector at the same exposure and must be shortened.
Architectural mismatches Max IV will have to decide:
Tango
tomo_det.labelvs. EPICSHDF5Locationfor frame labeling.Whether to arm the camera (not just the file writer) once for all frames — 2-BM only does this for the file plugin.