Skip to content

Commit

Permalink
XDIWriter now includes the mono d-spacing as metadata.
Browse files Browse the repository at this point in the history
Note: it uses the energy_positioner's ``d_spacing`` component. This
doesn't necessariy save the real mono; future work will need to be
done to make sure the energy device's ``d_spacing`` component is
actually the d-spacing of the mono.
  • Loading branch information
canismarko committed Apr 14, 2024
1 parent 6d945c5 commit f3faa52
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 3 deletions.
8 changes: 8 additions & 0 deletions src/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
from haven.instrument.dxp import DxpDetector
from haven.instrument.dxp import add_mcas as add_dxp_mcas
from haven.instrument.ion_chamber import IonChamber
from haven.instrument.monochromator import Monochromator
from haven.instrument.robot import Robot
from haven.instrument.shutter import Shutter
from haven.instrument.slits import ApertureSlits, BladeSlits
Expand Down Expand Up @@ -274,6 +275,13 @@ def aerotech_flyer(aerotech):
yield flyer


@pytest.fixture()
def mono(sim_registry):
mono = instantiate_fake_device(Monochromator, name="monochromator")
sim_registry.register(mono)
yield mono


@pytest.fixture()
def aps(sim_registry):
aps = instantiate_fake_device(ApsMachine, name="APS")
Expand Down
13 changes: 11 additions & 2 deletions src/haven/plans/energy_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,21 @@ def energy_scan(
scan_args = [(motor, energies) for motor in energy_positioners]
scan_args += [(motor, exposure) for motor in time_positioners]
scan_args = [item for items in scan_args for item in items]
# Do the actual scan
# Add some extra metadata
config = load_config()
md_ = {"edge": E0_str, "E0": E0}
for positioner in energy_positioners:
try:
md_["d_spacing"] = positioner.d_spacing.get()
except AttributeError:
continue
else:
break
# Do the actual scan
yield from bp.list_scan(
real_detectors,
*scan_args,
md=ChainMap(md, {"edge": E0_str, "E0": E0}, config),
md=ChainMap(md, md_, config),
)


Expand Down
16 changes: 16 additions & 0 deletions src/haven/tests/test_energy_xafs_scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,22 @@ def test_raises_on_empty_positioners(RE, energies):
RE(energy_scan(energies, energy_positioners=[]))


def test_saves_dspacing(mono, energies, I0, It):
"""Does the mono's d-spacing get added to metadata."""
# Prepare the messages from the plan
mono.d_spacing._readback = 1.5418
msgs = list(energy_scan(energies, detectors=[It], energy_positioners = [mono], time_positioners=[It.exposure_time]))
# Find the metadata written by the plan
for msg in msgs:
if msg.command == "open_run":
md = msg.kwargs
break
else:
raise RuntimeError("No open run message found")
# Check for the dspacing of the mono in the metadata
assert md['d_spacing'] == 1.5418


def test_single_range(mono_motor, exposure_motor, I0):
E0 = 10000
expected_energies = np.arange(9990, 10001, step=1)
Expand Down
3 changes: 2 additions & 1 deletion src/haven/tests/test_xdi_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
start_doc = {
"versions": {"bluesky": "1.8.3", "ophyd": "1.6.4"},
"detectors": ["I0", "It"],
"d_spacing": 3.,
"motors": ["energy", "exposure"],
"edge": "Ni_K",
"facility": {
Expand Down Expand Up @@ -202,7 +203,7 @@ def test_required_headers(writer):
assert "# Column.1: energy" in xdi_output
assert "# Element.symbol: Ni" in xdi_output
assert "# Element.edge: K" in xdi_output
# assert "# Mono.d_spacing: 3" in xdi_output # Not implemented yet
assert "# Mono.d_spacing: 3" in xdi_output # Not implemented yet
assert "# -------------" in xdi_output


Expand Down
8 changes: 8 additions & 0 deletions src/haven/xdi_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,14 @@ def write_header(self, doc):
else:
fd.write(f"# Element.symbol: {elem}\n")
fd.write(f"# Element.edge: {edge}\n")
# Monochromator information
try:
d_spacing = doc['d_spacing']
except KeyError:
pass
else:
fd.write(f"# Mono.d_spacing: {d_spacing}\n")
# Facility information
now = self.start_time
fd.write(f"# Scan.start_time: {now.strftime('%Y-%m-%d %H:%M:%S%z')}\n")
md_paths = [
Expand Down

0 comments on commit f3faa52

Please sign in to comment.