File Writers#
Write data files during data acquisition. The file writer callbacks are:
|
Base class for filewriter callbacks. |
|
Customize |
|
General class for writing HDF5/NeXus file (using only NeXus base classes). |
|
Deprecated: Use |
|
Write SPEC data file as data is collected, line-by-line. |
Overview#
Each filewriter can be used as a callback to the Bluesky RunEngine
for live data acquisition or later as a handler for a document set
from the databroker. Methods are provided to handle each document
type. The callback method, receiver(document_type, document)
, receives
the set of documents, one-by-one, and sends them to the appropriate
handler. Once the stop
document is received, the writer()
method
is called to write the output file.
Examples#
Write SPEC file automatically from data acquisition:
specwriter = apstools.callbacks.SpecWriterCallback()
RE.subscribe(specwriter.receiver)
Write NeXus file automatically from data acquisition:
nxwriter = apstools.callbacks.NXWriter()
RE.subscribe(nxwriter.receiver)
Write APS-specific NeXus file automatically from data acquisition:
nxwriteraps = apstools.callbacks.NXWriterAPS()
RE.subscribe(nxwriteraps.receiver)
Programmer’s Note#
Subclassing from object
(or no superclass)
avoids the need to import bluesky.callbacks.core.CallbackBase
.
One less import when only accessing the Databroker.
The only advantage to subclassing from CallbackBase
seems to be a simpler setup call to RE.subscribe()
.
superclass |
subscription code |
---|---|
object |
|
CallbackBase |
|
HDF5/NeXus File Writers#
FileWriterCallbackBase#
Base class for filewriter callbacks.
Applications should subclass and rewrite the writer()
method.
The local buffers are cleared when a start document is received. Content is collected here from each document until the stop document. The content is written once the stop document is received.
Output File Name and Path#
The output file will be written to the file named in
self.file_name
. (Include the output directory if
different from the current working directory.)
When self.file_name
is None
(the default), the
make_file_name()
method will construct
the file name using a combination of the date and time
(from the start
document), the start
document
uid
, and the scan_id
.
The default file extension (given in NEXUS_FILE_EXTENSION
)
is used in
make_file_name()
.
The directory will be
self.file_path
(or the current working directory
if self.file_path
is None
which is the default).
Either specify self.file_name
or override
make_file_name()
in a subclass to change the procedure for default output file names.
Metadata#
Almost all metadata keys (additional attributes added to the run’s
start
document) are completely optional. Certain keys are
specified by the RunEngine, some keys are specified by the plan
(or plan support methods), and other keys are supplied by the
user or the instrument team.
These are the keys used by this callback to help guide how information is stored in a NeXus HDF5 file structure.
key |
creator |
how is it used |
---|---|---|
detectors |
inconsistent |
name(s) of the signals used as detectors |
motors |
inconsistent |
synonym for |
plan_args |
inconsistent |
parameters (arguments) given |
plan_name |
inconsistent |
name of the plan used to collect data |
positioners |
inconsistent |
name(s) of the signals used as positioners |
scan_id |
RunEngine |
incrementing number of the run, user can reset |
uid |
RunEngine |
unique identifier of the run |
versions |
instrument |
documents the software versions used to collect data |
For more information about Bluesky events and document types, see https://blueskyproject.io/event-model/data-model.html.
NXWriter#
General class for writing HDF5/NeXus file (using only NeXus base classes).
One scan is written to one HDF5/NeXus file.
Output File Name and Path#
The output file will be written to the file named in
self.file_name
. (Include the output directory if
different from the current working directory.)
When self.file_name
is None
(the default), the
make_file_name()
method will construct
the file name using a combination of the date and time
(from the start document), the start
document
uid
, and the scan_id
.
The default file extension (given in NEXUS_FILE_EXTENSION
) is
used in
make_file_name()
.
The directory will be
self.file_path
(or the current working directory
if self.file_path
is None
which is the default).
Either specify self.file_name
of override
make_file_name()
in a subclass
to change the procedure for default output file names.
Metadata#
Almost all metadata keys (additional attributes added to the run’s
start
document) are completely optional. Certain keys are
specified by the RunEngine, some keys are specified by the plan
(or plan support methods), and other keys are supplied by the
user or the instrument team.
These are the keys used by this callback to help guide how information is stored in a NeXus HDF5 file structure.
key |
creator |
how is it used |
---|---|---|
detectors |
inconsistent |
name(s) of the signals used as plottable values |
motors |
inconsistent |
synonym for |
plan_args |
inconsistent |
parameters (arguments) given |
plan_name |
inconsistent |
name of the plan used to collect data |
positioners |
inconsistent |
name(s) of the positioners used for plotting |
scan_id |
RunEngine |
incrementing number of the run, user can reset |
subtitle |
user |
-tba- |
title |
user |
/entry/title |
uid |
RunEngine |
unique identifier of the run |
versions |
instrument |
documents the software versions used to collect data |
Notes:
detectors[0]
will be used as the/entry/data@signal
attributethe complete list in
positioners
will be used as the/entry/data@axes
attribute
Templates#
Use templates to build NeXus base classes or application definitions with data already collected by the nxwriter and saved in other places in the NeXus/HDF5 file (such as /entry/instrument/bluesky). Templates are used to:
make links from existing fields or groups to new locations
create new groups as directed
create constants for attributes or fields
A template is a [source, target]
list, where source is a string and target
varies depending on the type of template. A list of templates is stored as a
JSON string in the run’s metadata under a pre-arranged key.
For reasons of expediency, always use absolute HDF5 addresses. Relative addresses are not supported now.
A link template makes a pointer from an existing field or group to another location. In a link template, the source is an existing HDF5 address. The target is a NeXus class path. If the path contains a group which is not yet defined, the addtional component names the NeXus class to be used. See the examples below.
A constant template defines a new NeXus field. The source string, which can be
a class path (see above), ends with an =
. The target can be a text, a
number, or an array. Anything that can be converted into a JSON document and
then written to an HDF5 dataset.
An attribute template adds a new attribute to a field or group. Use the @ symbol in the source string as shown in the examples below. The target is the value of the attribute.
EXAMPLE:
1template_examples = [
2 # *constant* template
3 # define a constant array in a new NXdata group
4 ["/entry/example:NXdata/array=", [1, 2, 3]],
5
6 # *attribute* template
7 # set the example group "signal" attribute
8 # (new array is the default plottable data)
9 ["/entry/example/@signal", "array"],
10
11 # *link* template
12 # link the new array into a new NXnote group as field "x"
13 ["/entry/example/array", "/entry/example/note:NXnote/x"],
14]
15
16md = {
17 "title": "NeXus/HDF5 template support example",
18
19 # encode the Python dictionary as a JSON string
20 nxwriter.template_key: json.dumps(template_examples),
21}
The templates in this example add this structure to the /entry
group in the
HDF5 file:
1/entry:NXentry
2 @NX_class = "NXentry"
3 ...
4 example:NXdata
5 @NX_class = "NXdata"
6 @signal = "array"
7 @target = "/entry/example"
8 array:NX_INT64[3] = [1, 2, 3]
9 @target = "/entry/example/array"
10 note:NXnote
11 @NX_class = "NXnote"
12 @target = "/entry/example/note"
13 x --> /entry/example/array
NXWriterAPS#
Customize NXWriter
with APS-specific content.
Adds
/entry/instrument/undulator
group if metadata exists.Adds APS information to
/entry/instrument/source
group.
APS instruments should subclass NXWriterAPS
to make customizations for specific plans or other considerations.
HDF5/NeXus File Structures#
Bluesky stores a wealth of information about a measurement in a run.
Raw data from the Bluesky run is stored in the HDF5/NeXus structure
under the /entry/instrument/bluesky
group as shown in this example:
1 bluesky:NXnote
2 @NX_class = NXnote
3 @target = /entry/instrument/bluesky
4 plan_name --> /entry/instrument/bluesky/metadata/plan_name
5 uid --> /entry/instrument/bluesky/metadata/run_start_uid
The NeXus structure is built using links to the raw data in
/entry/instrument/bluesky
.
Metadata#
Metadata from the start
document is stored in the metadata
subgroup
as shown in this example:
1 metadata:NXnote
2 @NX_class = NXnote
3 @target = /entry/instrument/bluesky/metadata
4 beamline_id:NX_CHAR = b'APS USAXS 9-ID-C'
5 @target = /entry/instrument/bluesky/metadata/beamline_id
6 datetime:NX_CHAR = b'2019-05-02 17:45:33.904824'
7 @target = /entry/instrument/bluesky/metadata/datetime
8 detectors:NX_CHAR = b'- I0_USAXS\n'
9 @target = /entry/instrument/bluesky/metadata/detectors
10 @text_format = yaml
11 hints:NX_CHAR = b'dimensions:\n- - - m_stage_r\n - primary\n'
12 @target = /entry/instrument/bluesky/metadata/hints
13 @text_format = yaml
14 login_id:NX_CHAR = b'usaxs@usaxscontrol.xray.aps.anl.gov'
15 @target = /entry/instrument/bluesky/metadata/login_id
16 motors:NX_CHAR = b'- m_stage_r\n'
17 @target = /entry/instrument/bluesky/metadata/motors
18 @text_format = yaml
19 pid:NX_INT64[] =
20 @target = /entry/instrument/bluesky/metadata/pid
21 plan_name:NX_CHAR = b'tune_mr'
22 @target = /entry/instrument/bluesky/metadata/plan_name
23 plan_type:NX_CHAR = b'generator'
24 @target = /entry/instrument/bluesky/metadata/plan_type
25 proposal_id:NX_CHAR = b'testing Bluesky installation'
26 @target = /entry/instrument/bluesky/metadata/proposal_id
27 purpose:NX_CHAR = b'tuner'
28 @target = /entry/instrument/bluesky/metadata/purpose
29 run_start_uid:NX_CHAR = 2ffe4d87-9f0c-464a-9d14-213ec71afaf7
30 @long_name = bluesky run uid
31 @target = /entry/instrument/bluesky/metadata/run_start_uid
32 tune_md:NX_CHAR = b"initial_position: 8.824977\ntime_iso8601: '2019-05-02 17:45:33.923544'\nwidth: -0.004\n"
33 @target = /entry/instrument/bluesky/metadata/tune_md
34 @text_format = yaml
35 tune_parameters:NX_CHAR = b'initial_position: 8.824977\nnum: 31\npeak_choice: com\nwidth: -0.004\nx_axis: m_stage_r\ny_axis: I0_USAXS\n'
36 @target = /entry/instrument/bluesky/metadata/tune_parameters
37 @text_format = yaml
38 uid --> /entry/instrument/bluesky/run_start_uid
Note that complex structures (lists and dictionaries)
are written as YAML. YAML is easily converted back into the
python structure using yaml.load(yaml_text)
where yaml_text
is the YAML text from the HDF5 file.
Streams#
Data from each ophyd signal in a document stream is stored as datasets
within a NXdata
[1] subgroup of that stream. Bluesky collects value(s) and timestamp(s)
which are stored in the datasets value
and EPOCH
, respectively.
Since EPOCH
is the absolute number of seconds from some time in the deep past,
an additional time
dataset repeats this data as time relative to the first time.
(This makes it much easier for some visualization programs to display
value v. time plots.) Additional information, as available (such as units),
is added as NeXus attributes. The @target
attribute is automatically added
to simplify linking any item into the NeXus tree structure.
For example, the main data in a run is usually stored in the primary
stream.
Here, we show the tree structure for one signal (I0_USAXS
) from the primary stream:
1 primary:NXnote
2 @NX_class = NXnote
3 @target = /entry/instrument/bluesky/streams/primary
4 @uid = 90489e9b-d66e-4753-8c4f-849e7a809aeb
5 I0_USAXS:NXdata
6 @NX_class = NXdata
7 @axes = time
8 @signal = value
9 @signal_type = detector
10 @target = /entry/instrument/bluesky/streams/primary/I0_USAXS
11 EPOCH:NX_FLOAT64[31] = [1556837134.972796, 1556837135.589462, 1556837135.989462, '...', 1556837147.656129]
12 @long_name = epoch time (s)
13 @target = /entry/instrument/bluesky/streams/primary/I0_USAXS/EPOCH
14 @units = s
15 time:NX_FLOAT64[31] = [0.0, 0.6166660785675049, 1.0166659355163574, '...', 12.683332920074463]
16 @long_name = time since first data (s)
17 @start_time = 1556837134.972796
18 @start_time_iso = 2019-05-02T17:45:34.972796
19 @target = /entry/instrument/bluesky/streams/primary/I0_USAXS/time
20 @units = s
21 value:NX_FLOAT64[31] = [127.0, 126.0, 127.0, '...', 127.0]
22 @long_name = I0_USAXS
23 @lower_ctrl_limit = 0.0
24 @precision = 0
25 @signal_type = detector
26 @source = PV:9idcLAX:vsc:c0.S2
27 @target = /entry/instrument/bluesky/streams/primary/I0_USAXS/value
28 @units =
29 @upper_ctrl_limit = 0.0
Baseline#
In Bluesky, baseline streams record the value (and timestamp) of a
signal at the start and end of the run. Similar to the handling for
streams (above), a subgroup is created for each baseline stream.
The datasets include value
, EPOCH
, time
(as above) and
value_start
and value_end
. Here’s an example:
1 baseline:NXnote
2 @NX_class = NXnote
3 @target = /entry/instrument/bluesky/streams/baseline
4 @uid = f5fce6ac-f3fa-4c34-b11d-9e33c263cd20
5 aps_current:NXdata
6 @NX_class = NXdata
7 @axes = time
8 @signal = value
9 @target = /entry/instrument/bluesky/streams/baseline/aps_current
10 EPOCH:NX_FLOAT64[2] = [1556837133.753769, 1556837147.753723]
11 @long_name = epoch time (s)
12 @target = /entry/instrument/bluesky/streams/baseline/aps_current/EPOCH
13 @units = s
14 time:NX_FLOAT64[2] = [0.0, 13.999953985214233]
15 @long_name = time since first data (s)
16 @start_time = 1556837133.753769
17 @start_time_iso = 2019-05-02T17:45:33.753769
18 @target = /entry/instrument/bluesky/streams/baseline/aps_current/time
19 @units = s
20 value:NX_FLOAT64[2] = [0.004512578244000032, 0.003944485484000011]
21 @long_name = aps_current
22 @lower_ctrl_limit = 0.0
23 @precision = 1
24 @source = PV:S:SRcurrentAI
25 @target = /entry/instrument/bluesky/streams/baseline/aps_current/value
26 @units = mA
27 @upper_ctrl_limit = 310.0
28 value_end:NX_FLOAT64[] =
29 @long_name = aps_current
30 @lower_ctrl_limit = 0.0
31 @precision = 1
32 @source = PV:S:SRcurrentAI
33 @target = /entry/instrument/bluesky/streams/baseline/aps_current/value_end
34 @units = mA
35 @upper_ctrl_limit = 310.0
36 value_start:NX_FLOAT64[] =
37 @long_name = aps_current
38 @lower_ctrl_limit = 0.0
39 @precision = 1
40 @source = PV:S:SRcurrentAI
41 @target = /entry/instrument/bluesky/streams/baseline/aps_current/value_start
42 @units = mA
43 @upper_ctrl_limit = 310.0
Full Structure#
The full structure of the example HDF5/NeXus file (omitting the attributes
and array data for brevity) is shown next. You can see that most of the
NeXus structure is completed by making links to data from either
/entry/instrument/bluesky/metadata
or /entry/instrument/bluesky/streams
:
120190502-174533-S00108-2ffe4d8.hdf : NeXus data file
2 entry:NXentry
3 duration:NX_FLOAT64[] = [ ... ]
4 end_time:NX_CHAR = 2019-05-02T17:45:48.078618
5 entry_identifier --> /entry/instrument/bluesky/uid
6 plan_name --> /entry/instrument/bluesky/metadata/plan_name
7 program_name:NX_CHAR = bluesky
8 start_time:NX_CHAR = 2019-05-02T17:45:33.937294
9 title:NX_CHAR = tune_mr-S0108-2ffe4d8
10 contact:NXuser
11 affiliation --> /entry/instrument/bluesky/streams/baseline/bss_user_info_institution/value_start
12 email --> /entry/instrument/bluesky/streams/baseline/bss_user_info_email/value_start
13 facility_user_id --> /entry/instrument/bluesky/streams/baseline/bss_user_info_badge/value_start
14 name --> /entry/instrument/bluesky/streams/baseline/bss_user_info_contact/value_start
15 role:NX_CHAR = contact
16 data:NXdata
17 EPOCH --> /entry/instrument/bluesky/streams/primary/scaler0_time/time
18 I0_USAXS --> /entry/instrument/bluesky/streams/primary/I0_USAXS/value
19 m_stage_r --> /entry/instrument/bluesky/streams/primary/m_stage_r/value
20 m_stage_r_soft_limit_hi --> /entry/instrument/bluesky/streams/primary/m_stage_r_soft_limit_hi/value
21 m_stage_r_soft_limit_lo --> /entry/instrument/bluesky/streams/primary/m_stage_r_soft_limit_lo/value
22 m_stage_r_user_setpoint --> /entry/instrument/bluesky/streams/primary/m_stage_r_user_setpoint/value
23 scaler0_display_rate --> /entry/instrument/bluesky/streams/primary/scaler0_display_rate/value
24 scaler0_time --> /entry/instrument/bluesky/streams/primary/scaler0_time/value
25 instrument:NXinstrument
26 bluesky:NXnote
27 plan_name --> /entry/instrument/bluesky/metadata/plan_name
28 uid --> /entry/instrument/bluesky/metadata/run_start_uid
29 metadata:NXnote
30 APSTOOLS_VERSION:NX_CHAR = b'1.1.0'
31 BLUESKY_VERSION:NX_CHAR = b'1.5.2'
32 EPICS_CA_MAX_ARRAY_BYTES:NX_CHAR = b'1280000'
33 EPICS_HOST_ARCH:NX_CHAR = b'linux-x86_64'
34 OPHYD_VERSION:NX_CHAR = b'1.3.3'
35 beamline_id:NX_CHAR = b'APS USAXS 9-ID-C'
36 datetime:NX_CHAR = b'2019-05-02 17:45:33.904824'
37 detectors:NX_CHAR = b'- I0_USAXS\n'
38 hints:NX_CHAR = b'dimensions:\n- - - m_stage_r\n - primary\n'
39 login_id:NX_CHAR = b'usaxs@usaxscontrol.xray.aps.anl.gov'
40 motors:NX_CHAR = b'- m_stage_r\n'
41 pid:NX_INT64[] = [ ... ]
42 plan_name:NX_CHAR = b'tune_mr'
43 plan_type:NX_CHAR = b'generator'
44 proposal_id:NX_CHAR = b'testing Bluesky installation'
45 purpose:NX_CHAR = b'tuner'
46 run_start_uid:NX_CHAR = 2ffe4d87-9f0c-464a-9d14-213ec71afaf7
47 tune_md:NX_CHAR = b"initial_position: 8.824977\ntime_iso8601: '2019-05-02 17:45:33.923544'\nwidth: -0.004\n"
48 tune_parameters:NX_CHAR = b'initial_position: 8.824977\nnum: 31\npeak_choice: com\nwidth: -0.004\nx_axis: m_stage_r\ny_axis: I0_USAXS\n'
49 uid --> /entry/instrument/bluesky/run_start_uid
50 streams:NXnote
51 baseline:NXnote
52 aps_current:NXdata
53 EPOCH:NX_FLOAT64[2] = [ ... ]
54 time:NX_FLOAT64[2] = [ ... ]
55 value:NX_FLOAT64[2] = [ ... ]
56 value_end:NX_FLOAT64[] = [ ... ]
57 value_start:NX_FLOAT64[] = [ ... ]
58 aps_fill_number:NXdata
59 EPOCH:NX_FLOAT64[2] = [ ... ]
60 time:NX_FLOAT64[2] = [ ... ]
61 value:NX_FLOAT64[2] = [ ... ]
62 value_end:NX_FLOAT64[] = [ ... ]
63 value_start:NX_FLOAT64[] = [ ... ]
64 aps_global_feedback:NXdata
65 EPOCH:NX_FLOAT64[2] = [ ... ]
66 time:NX_FLOAT64[2] = [ ... ]
67 value:NX_CHAR[3,3] = ["Off", "Off"]
68 value_end:NX_CHAR = b'Off'
69 value_start:NX_CHAR = b'Off'
70 # many baseline groups omitted for brevity
71 primary:NXnote
72 I0_USAXS:NXdata
73 EPOCH:NX_FLOAT64[31] = [ ... ]
74 time:NX_FLOAT64[31] = [ ... ]
75 value:NX_FLOAT64[31] = [ ... ]
76 m_stage_r:NXdata
77 EPOCH:NX_FLOAT64[31] = [ ... ]
78 time:NX_FLOAT64[31] = [ ... ]
79 value:NX_FLOAT64[31] = [ ... ]
80 m_stage_r_soft_limit_hi:NXdata
81 EPOCH:NX_FLOAT64[31] = [ ... ]
82 time:NX_FLOAT64[31] = [ ... ]
83 value:NX_FLOAT64[31] = [ ... ]
84 m_stage_r_soft_limit_lo:NXdata
85 EPOCH:NX_FLOAT64[31] = [ ... ]
86 time:NX_FLOAT64[31] = [ ... ]
87 value:NX_FLOAT64[31] = [ ... ]
88 m_stage_r_user_setpoint:NXdata
89 EPOCH:NX_FLOAT64[31] = [ ... ]
90 time:NX_FLOAT64[31] = [ ... ]
91 value:NX_FLOAT64[31] = [ ... ]
92 scaler0_display_rate:NXdata
93 EPOCH:NX_FLOAT64[31] = [ ... ]
94 time:NX_FLOAT64[31] = [ ... ]
95 value:NX_FLOAT64[31] = [ ... ]
96 scaler0_time:NXdata
97 EPOCH:NX_FLOAT64[31] = [ ... ]
98 time:NX_FLOAT64[31] = [ ... ]
99 value:NX_FLOAT64[31] = [ ... ]
100 detectors:NXnote
101 I0_USAXS:NXdetector
102 data --> /entry/instrument/bluesky/streams/primary/I0_USAXS
103 monochromator:NXmonochromator
104 energy --> /entry/instrument/bluesky/streams/baseline/monochromator_dcm_energy/value_start
105 feedback_on --> /entry/instrument/bluesky/streams/baseline/monochromator_feedback_on/value_start
106 mode --> /entry/instrument/bluesky/streams/baseline/monochromator_dcm_mode/value_start
107 theta --> /entry/instrument/bluesky/streams/baseline/monochromator_dcm_theta/value_start
108 wavelength --> /entry/instrument/bluesky/streams/baseline/monochromator_dcm_wavelength/value_start
109 y_offset --> /entry/instrument/bluesky/streams/baseline/monochromator_dcm_y_offset/value_start
110 positioners:NXnote
111 m_stage_r:NXpositioner
112 value --> /entry/instrument/bluesky/streams/primary/m_stage_r
113 source:NXsource
114 name:NX_CHAR = Bluesky framework
115 probe:NX_CHAR = x-ray
116 type:NX_CHAR = Synchrotron X-ray Source
APS-specific HDF5/NeXus File Structures#
Examples of additional structure in NeXus file added by
NXWriterAPS()
:
1 source:NXsource
2 @NX_class = NXsource
3 @target = /entry/instrument/source
4 current --> /entry/instrument/bluesky/streams/baseline/aps_current/value_start
5 energy:NX_INT64[] =
6 @units = GeV
7 fill_number --> /entry/instrument/bluesky/streams/baseline/aps_fill_number/value_start
8 name:NX_CHAR = Advanced Photon Source
9 @short_name = APS
10 probe:NX_CHAR = x-ray
11 type:NX_CHAR = Synchrotron X-ray Source
12 undulator:NXinsertion_device
13 @NX_class = NXinsertion_device
14 @target = /entry/instrument/undulator
15 device --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_device/value_start
16 energy --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_energy/value_start
17 energy_taper --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_energy_taper/value_start
18 gap --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_gap/value_start
19 gap_taper --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_gap_taper/value_start
20 harmonic_value --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_harmonic_value/value_start
21 location --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_location/value_start
22 total_power --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_total_power/value_start
23 type:NX_CHAR = undulator
24 version --> /entry/instrument/bluesky/streams/baseline/undulator_downstream_version/value_start
SPEC File Structure#
EXAMPLE : use as Bluesky callback:
from apstools import SpecWriterCallback
specwriter = SpecWriterCallback()
RE.subscribe(specwriter.receiver)
EXAMPLE : use as writer from Databroker:
from apstools import SpecWriterCallback
specwriter = SpecWriterCallback()
for key, doc in db.get_documents(db["a123456"]):
specwriter.receiver(key, doc)
print("Look at SPEC data file: "+specwriter.spec_filename)
EXAMPLE : use as writer from Databroker with customizations:
from apstools import SpecWriterCallback
# write into file: /tmp/cerium.spec
specwriter = SpecWriterCallback(filename="/tmp/cerium.spec")
for key, doc in db.get_documents(db["abcd123"]):
specwriter.receiver(key, doc)
# write into file: /tmp/barium.dat
specwriter.newfile("/tmp/barium.dat")
for key, doc in db.get_documents(db["b46b63d4"]):
specwriter.receiver(key, doc)
Example output from SpecWriterCallback()
:
1#F test_specdata.txt
2#E 1510948301
3#D Fri Nov 17 13:51:41 2017
4#C BlueSky user = mintadmin host = mint-vm
5
6#S 233 scan(detectors=['synthetic_pseudovoigt'], num=20, motor=['m1'], start=-1.65, stop=-1.25, per_step=None)
7#D Fri Nov 17 11:58:56 2017
8#C Fri Nov 17 11:58:56 2017. plan_type = generator
9#C Fri Nov 17 11:58:56 2017. uid = ddb81ac5-f3ee-4219-b047-c1196d08a5c1
10#MD beamline_id = developer__YOUR_BEAMLINE_HERE
11#MD login_id = mintadmin@mint-vm
12#MD motors = ['m1']
13#MD num_intervals = 19
14#MD num_points = 20
15#MD pid = 7133
16#MD plan_pattern = linspace
17#MD plan_pattern_args = {'start': -1.65, 'stop': -1.25, 'num': 20}
18#MD plan_pattern_module = numpy
19#MD proposal_id = None
20#N 20
21#L m1 m1_user_setpoint Epoch_float Epoch synthetic_pseudovoigt
22-1.6500000000000001 -1.65 8.27465009689331 8 2155.6249784809206
23-1.6288 -1.6289473684210525 8.46523666381836 8 2629.5229081466964
24-1.608 -1.6078947368421053 8.665581226348877 9 3277.4074328018964
25-1.5868 -1.5868421052631578 8.865738153457642 9 4246.145049452576
26-1.5656 -1.5657894736842104 9.066259145736694 9 5825.186516381953
27-1.5448000000000002 -1.5447368421052632 9.266754627227783 9 8803.414029867528
28-1.5236 -1.5236842105263158 9.467074871063232 9 15501.419687691103
29-1.5028000000000001 -1.5026315789473683 9.667330741882324 10 29570.38936784884
30-1.4816 -1.4815789473684209 9.867793798446655 10 55562.3437459487
31-1.4604000000000001 -1.4605263157894737 10.067811012268066 10 89519.64275090238
32-1.4396 -1.4394736842105262 10.268356084823608 10 97008.97190269837
33-1.4184 -1.418421052631579 10.470621824264526 10 65917.29757650592
34-1.3972 -1.3973684210526316 10.669955730438232 11 36203.46726798266
35-1.3764 -1.3763157894736842 10.870310306549072 11 18897.64061096024
36-1.3552 -1.3552631578947367 11.070487976074219 11 10316.223844200193
37-1.3344 -1.3342105263157895 11.271018743515015 11 6540.179615556269
38-1.3132000000000001 -1.313157894736842 11.4724280834198 11 4643.555421314616
39-1.292 -1.2921052631578946 11.673305034637451 12 3533.8582404216445
40-1.2712 -1.2710526315789474 11.874176025390625 12 2809.1872596809008
41-1.25 -1.25 12.074703216552734 12 2285.9226305883626
42#C Fri Nov 17 11:59:08 2017. num_events_primary = 20
43#C Fri Nov 17 11:59:08 2017. time = 2017-11-17 11:59:08.324011
44#C Fri Nov 17 11:59:08 2017. exit_status = success
Source Code#
Base Class for File Writer Callbacks#
|
Base class for filewriter callbacks. |
- class apstools.callbacks.callback_base.FileWriterCallbackBase(*args, **kwargs)[source]#
Base class for filewriter callbacks.
New with apstools release 1.3.0.
Applications should subclass and rewrite the
writer()
method.The local buffers are cleared when a start document is received. Content is collected here from each document until the stop document. The content is written once the stop document is received.
User Interface methods
receiver
(key, doc)bluesky callback (handles a stream of documents)
Internal methods
clear
()delete any saved data from the cache and reinitialize
generate a file name to be used as default
writer
()print summary of run as diagnostic
Document Handler methods
bulk_events
(doc)Deprecated.
datum
(doc)Like an event, but for data recorded outside of bluesky.
descriptor
(doc)description of the data stream to be acquired
event
(doc)a single "row" of data
resource
(doc)like a descriptor, but for data recorded outside of bluesky
start
(doc)beginning of a run, clear cache and collect metadata
stop
(doc)end of the run, end collection and initiate the
writer()
method- datum(doc)[source]#
Like an event, but for data recorded outside of bluesky.
Example:
Datum ===== datum_id : 621caa0f-70f1-4e3d-8718-b5123d434502/0 datum_kwargs : HDF5_file_name : /mnt/usaxscontrol/USAXS_data/2020-06/06_10_Minjee_waxs/AGIX3N1_0699.hdf point_number : 0 resource : 621caa0f-70f1-4e3d-8718-b5123d434502
NeXus File Writer Callbacks#
|
General class for writing HDF5/NeXus file (using only NeXus base classes). |
|
Customize |
- class apstools.callbacks.nexus_writer.NXWriter(*args, **kwargs)[source]#
General class for writing HDF5/NeXus file (using only NeXus base classes).
One scan is written to one HDF5/NeXus file.
Note
If you use
NXWriter
, you must wait for the writer() method to finish before proceeding with the next acquisition or processing. (The writer() method is launched in a background thread to complete once all readable assets are available, potentially even after the run ends.)See the table below for which wait method to call.
EXAMPLES:
Interactive use (outside of a plan):
# ... nxwriter = NXWriter() # create the callback instance RE.subscribe(nxwriter.receiver) # subscribe to the RunEngine # ... RE(bp.count([camera])) nxwriter.wait_writer() # ... run = cat.v2[-1] # for additional processing
Note
There are two methods to wait for the callback. One is for interactive use when not using the RunEngine. The other is for use in a plan that is executed by the bluesky RunEngine.
When
Method
Which uses
interactive
wait_writer()
time.sleep()
in a plan
wait_writer_plan_stub()
yield from bps.sleep()
The
wait_writer()
method callstime.sleep()
and this would block the RunEngine from its routine processing of other background tasks. Thewait_writer_plan_stub()
method replaces that call withyield from bps.sleep()
which does not block the RunEngine from processing other background tasks.In a custom plan, use the
wait_writer_plan_stub()
method instead:# ... nxwriter = NXWriter() # create the callback instance RE.subscribe(nxwriter.receiver) # subscribe to the RunEngine # ... def my_plan(dets, n=5): for i in range(n): yield from bp.count(dets) yield from nxwriter.wait_writer_plan_stub()
METHODS
writer
()Write collected data to HDF5/NeXus data file.
h5string
(text)Format string for h5py interface.
add_dataset_attributes
(ds, v[, long_name])add attributes from v dictionary to dataset ds
decide if a signal in the primary stream is a detector or a positioner
create_NX_group
(parent, specification)create an h5 group with named NeXus class (specification)
return the title for this sample
get_stream_link
(signal[, stream, ref])return the h5 object for
signal
resolve_class_path
(class_path)Parse the class path, make any groups, return the HDF5 address.
Wait for the writer to finish.
Wait for the writer to finish.
write_data
(parent)group: /entry/data:NXdata
write_detector
(parent)group: /entry/instrument/detectors:NXnote/DETECTOR:NXdetector
group: /entry/data:NXentry
write_instrument
(parent)group: /entry/instrument:NXinstrument
write_metadata
(parent)group: /entry/instrument/bluesky/metadata:NXnote
write_monochromator
(parent)group: /entry/instrument/monochromator:NXmonochromator
write_positioner
(parent)group: /entry/instrument/positioners:NXnote/POSITIONER:NXpositioner
write_root
(filename)root of the HDF5 file
write_sample
(parent)group: /entry/sample:NXsample
write_slits
(parent)group: /entry/instrument/slits:NXnote/SLIT:NXslit
write_source
(parent)group: /entry/instrument/source:NXsource
write_streams
(parent)group: /entry/instrument/bluesky/streams:NXnote
Process any link templates provided as run metadata.
write_user
(parent)group: /entry/contact:NXuser
New with apstools release 1.3.0. Update in release 1.6.11 to wait for area detector HDF5 files.
- add_dataset_attributes(ds, v, long_name=None)[source]#
add attributes from v dictionary to dataset ds
- assign_signal_type()[source]#
decide if a signal in the primary stream is a detector or a positioner
- create_NX_group(parent, specification)[source]#
create an h5 group with named NeXus class (specification)
- getResourceFile(resource_id)[source]#
full path to the resource file specified by uid
resource_id
override in subclass as needed
- get_sample_title()[source]#
return the title for this sample
default title: S{scan_id}-{plan_name}-{short_uid}
- get_stream_link(signal, stream=None, ref=None)[source]#
return the h5 object for
signal
DEFAULTS
stream
:baseline
key
:value_start
- resolve_class_path(class_path)[source]#
Parse the class path, make any groups, return the HDF5 address.
New with apstools release 1.6.18.
- template_key = 'nxwriter_template'#
The template (dict) is written as a JSON string to this metadata key.
- wait_writer()[source]#
Wait for the writer to finish. For interactive use (Not in a plan).
If you use
NXWriter
interactively, you must callNXWriter.wait_writer()
which waits for all data processing to finish before proceeding with the next acquisition or processing.
- wait_writer_plan_stub()[source]#
Wait for the writer to finish. Use in a plan (with RunEngine).
If you use
NXWriter
in a plan, you must callNXWriter.wait_writer()
which waits for all data processing to finish before proceeding with the next acquisition or processing.
- write_data(parent)[source]#
group: /entry/data:NXdata
- write_entry()[source]#
group: /entry/data:NXentry
- write_metadata(parent)[source]#
group: /entry/instrument/bluesky/metadata:NXnote
metadata from the bluesky start document
- write_positioner(parent)[source]#
group: /entry/instrument/positioners:NXnote/POSITIONER:NXpositioner
- write_slits(parent)[source]#
group: /entry/instrument/slits:NXnote/SLIT:NXslit
override in subclass to store content, name patterns vary with each instrument
- write_source(parent)[source]#
group: /entry/instrument/source:NXsource
Note: this is (somewhat) generic, override for a different source
- write_streams(parent)[source]#
group: /entry/instrument/bluesky/streams:NXnote
data from all the bluesky streams
- writer()[source]#
Write collected data to HDF5/NeXus data file.
The callback launches
_threaded_writer()
and returns. In the thread,write_root()
(or methods within) can wait on certain items (such as an external HDF5 file written by an area detector IOC) to become readable or a timeout period has expired.
- class apstools.callbacks.nexus_writer.NXWriterAPS(*args, **kwargs)[source]#
Customize
NXWriter
with APS-specific content.New with apstools release 1.3.0.
Adds /entry/instrument/undulator group if metadata exists.
Adds APS information to /entry/instrument/source group.
write_instrument
(parent)group: /entry/instrument:NXinstrument
write_source
(parent)group: /entry/instrument/source:NXsource
write_undulator
(parent)group: /entry/instrument/undulator:NXinsertion_device
SPEC Data File Writer Callback#
EXAMPLE:
Execution of this plan (with RE(myPlan())
):
def myPlan():
yield from bps.open_run()
spec_comment("this is a start document comment", "start")
spec_comment("this is a descriptor document comment", "descriptor")
yield bps.Msg('checkpoint')
yield from bps.trigger_and_read([scaler])
spec_comment("this is an event document comment after the first read")
yield from bps.sleep(2)
yield bps.Msg('checkpoint')
yield from bps.trigger_and_read([scaler])
spec_comment("this is an event document comment after the second read")
spec_comment("this is a stop document comment", "stop")
yield from bps.close_run()
results in this SPEC file output:
#S 1145 myPlan()
#D Mon Jan 28 12:48:09 2019
#C Mon Jan 28 12:48:09 2019. plan_type = generator
#C Mon Jan 28 12:48:09 2019. uid = ef98648a-8e3a-4e7e-ac99-3290c9b5fca7
#C Mon Jan 28 12:48:09 2019. this is a start document comment
#C Mon Jan 28 12:48:09 2019. this is a descriptor document comment
#MD APSTOOLS_VERSION = 2019.0103.0+5.g0f4e8b2
#MD BLUESKY_VERSION = 1.4.1
#MD OPHYD_VERSION = 1.3.0
#MD SESSION_START = 2019-01-28 12:19:25.446836
#MD beamline_id = developer
#MD ipython_session_start = 2018-02-14 12:54:06.447450
#MD login_id = mintadmin@mint-vm
#MD pid = 21784
#MD proposal_id = None
#N 2
#L Epoch_float scaler_time Epoch
1.4297869205474854 1.1 1
4.596935987472534 1.1 5
#C Mon Jan 28 12:48:11 2019. this is an event document comment after the first read
#C Mon Jan 28 12:48:14 2019. this is an event document comment after the second read
#C Mon Jan 28 12:48:14 2019. this is a stop document comment
#C Mon Jan 28 12:48:14 2019. num_events_primary = 2
#C Mon Jan 28 12:48:14 2019. exit_status = success
|
Deprecated: Use |
|
Write SPEC data file as data is collected, line-by-line. |
|
make it easy to add spec-style comments in a custom plan |
- class apstools.callbacks.spec_file_writer.SpecWriterCallback(filename=None, auto_write=True, RE=None, reset_scan_id=False)[source]#
Deprecated: Use
SpecWriterCallback2
.Collect data from Bluesky RunEngine documents to write as SPEC data.
This gathers data from all documents in a scan and appends scan to the file when the
stop
document is received. One or more scans can be written to the same file. The file format is text.Note
SpecWriterCallback()
does not inherit fromFileWriterCallbackBase()
.PARAMETERS
- filename
string : (optional) Local, relative or absolute name of SPEC data file to be used. If
filename=None
, defaults to format ofYYYmmdd-HHMMSS.dat
derived from the current system time.- auto_write
boolean : (optional) If
True
(default),write_scan()
is called when stop document is received. IfFalse
, the caller is responsible for callingwrite_scan()
before the nextstart
document is received.- RE
object : Instance of
bluesky.RunEngine
orNone
.- reset_scan_id
boolean : (optional) If True, and filename exists, then sets
RE.md.scan_id
to highest scan number in existing SPEC data file. default: False
User Interface methods
receiver
(key, document)Bluesky callback: receive all documents for handling
newfile
([filename, scan_id, RE])prepare to use a new SPEC data file
usefile
(filename)read from existing SPEC data file
generate a file name to be used as default
clear
()reset all scan data defaults
format the scan for a SPEC data file
write the most recent (completed) scan to the file
Internal methods
Write the (initial) header section of a SPEC data file.
start
(doc)handle start documents
descriptor
(doc)handle descriptor documents
event
(doc)handle event documents
bulk_events
(doc)handle bulk_events documents
datum
(doc)handle datum documents
resource
(doc)handle resource documents
stop
(doc)handle stop documents
- descriptor(doc)[source]#
handle descriptor documents
prepare for primary scan data, ignore any other data stream
- newfile(filename=None, scan_id=None, RE=None)[source]#
prepare to use a new SPEC data file
but don’t create it until we have data
- class apstools.callbacks.spec_file_writer.SpecWriterCallback2(*args, **kwargs)[source]#
Write SPEC data file as data is collected, line-by-line.
This writes data from a scan as each event document is received. One or more scans can be written to the same file. The file format is text.
descriptor
(doc)Handle descriptor documents of certain streams.
event
(doc)a single "row" of data
start
(doc)First document of the run.
stop
(doc)Last document of the run.
writer
()Output to a file completed by other methods.
_cmt
(text)Return a SPEC-style comment.
_write_lines_
(lines[, mode])write (more) lines to the file
generate a file name to be used as default
newfile
([filename, scan_id, RE])prepare to use a new SPEC data file
usefile
(filename)read from existing SPEC data file
Write file header to file, if needed.
write_scan_data_row
(doc)Write row of scan data to file.
write_scan_end
(doc)Write scan ending to file.
Write scan header to file.
Synonym for 'file_name' property.
New in apstools 1.7.0.
- newfile(filename=None, scan_id=None, RE=None)[source]#
prepare to use a new SPEC data file
but don’t create it until we have data
- property spec_filename#
Synonym for ‘file_name’ property.
API compatibility with SpecWriterCallback.
- apstools.callbacks.spec_file_writer.spec_comment(comment, doc=None, writer=None)[source]#
make it easy to add spec-style comments in a custom plan
These comments only go into the SPEC data file.
PARAMETERS
- comment string :
(optional) Comment text to be written. SPEC expects it to be only one line!
- doc string :
(optional) Bluesky RunEngine document type. One of:
start descriptor event resource datum stop
(default:event
)- writer obj :
(optional) Instance of
SpecWriterCallback()
, typically:specwriter = SpecWriterCallback()