Skip to content

Commit

Permalink
Merge pull request #292 from bluesky/289-restore-reflections
Browse files Browse the repository at this point in the history
restore reflections to the proper sample

Thanks, all, for the reviews!
  • Loading branch information
prjemian authored Nov 16, 2023
2 parents fcd0f76 + 3ed3ddd commit 565d983
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 51 deletions.
25 changes: 16 additions & 9 deletions hkl/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
DEFAULT_WAVELENGTH = 1.54 # angstrom
EXPORT_FORMATS = "dict json yaml".split()

EQUAL_TOLERANCE = 1.0e-7


# standard value checks, raise exception(s) when appropriate
def _check_key(key, biblio, intro):
Expand Down Expand Up @@ -254,12 +256,12 @@ def validate(self, dc_obj):

def write(self, diffractometer):
"""Write sample details to diffractometer."""
s = diffractometer.calc._samples.get(self.name)
sample = diffractometer.calc._samples.get(self.name)
lattice_parameters = list(self.lattice.values)
if s is None:
s = diffractometer.calc.new_sample(self.name, lattice=lattice_parameters)
if sample is None:
sample = diffractometer.calc.new_sample(self.name, lattice=lattice_parameters)
else:
s.lattice = lattice_parameters
sample.lattice = lattice_parameters

reflection_list = []
for reflection in self.reflections:
Expand All @@ -275,18 +277,18 @@ def write(self, diffractometer):
w1 = rdict["wavelength"]
try:
diffractometer.calc.wavelength = w1
r = diffractometer.calc.sample.add_reflection(*args)
r = sample.add_reflection(*args)
if rdict["orientation_reflection"]:
reflection_list.append(r)
except RuntimeError as exc:
raise RuntimeError(f"could not add reflection({args}, wavelength={w1})") from exc
finally:
diffractometer.calc.wavelength = w0

if rdict["orientation_reflection"]:
reflection_list.append(r)
# Remaining code will not be executed if exception was raised.

if len(reflection_list) > 1:
r1, r2 = reflection_list[0], reflection_list[1]
diffractometer.calc.sample.compute_UB(r1, r2)
sample.compute_UB(r1, r2)


@dataclass
Expand Down Expand Up @@ -543,6 +545,11 @@ def restore(self, data, clear=True, restore_constraints=True):
If ``True`` (default), remove any previous configuration of the
diffractometer and reset it to default values before restoring the
configuration.
If ``False``, sample reflections will be append with all reflections
included in the configuration data for that sample. Existing
reflections will not be changed. The user may need to edit the
list of reflections after ``restore(clear=False)``.
restore_constraints *bool*:
If ``True`` (default), restore any constraints provided.
Expand Down
14 changes: 8 additions & 6 deletions hkl/sample.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"""Sample on the diffractometer."""

import logging

import numpy as np
Expand Down Expand Up @@ -88,21 +90,19 @@ class HklSample(object):
.. autosummary::
~name
~add_reflection
~affine
~remove_reflection
~swap_orientation_reflections
~clear_reflections
~affine
~compute_UB
~hkl_calc
~hkl_sample
~lattice
~name
~reciprocal
~reflection_measured_angles
~reflection_theoretical_angles
~reflections
~reflections_details
~remove_reflection
~swap_orientation_reflections
~U
~UB
~ux
Expand All @@ -113,6 +113,8 @@ class HklSample(object):
.. autosummary::
~hkl_calc
~hkl_sample
~__repr__
~__str__
~_create_reflection
Expand Down
32 changes: 0 additions & 32 deletions hkl/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,32 +0,0 @@
import logging

import numpy

from ..util import new_lattice

logger = logging.getLogger("ophyd_session_test")

TARDIS_TEST_MODE = "lifting_detector_mu"
TWO_PI = 2 * numpy.pi


def new_sample(diffractometer, name, lattice):
diffractometer.calc.new_sample(name, lattice=lattice)


def sample_kryptonite(diffractometer):
triclinic = new_lattice(4, 5, 6, 75, 85, 95)
new_sample(diffractometer, "kryptonite", lattice=triclinic)


def sample_silicon(diffractometer):
from .. import SI_LATTICE_PARAMETER

cubic = new_lattice(SI_LATTICE_PARAMETER)
new_sample(diffractometer, "silicon", lattice=cubic)


def sample_vibranium(diffractometer):
a0 = TWO_PI
cubic = new_lattice(a0)
new_sample(diffractometer, "vibranium", lattice=cubic)
2 changes: 1 addition & 1 deletion hkl/tests/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from ..configuration import DCSample
from ..util import Constraint
from ..util import new_lattice
from . import TWO_PI
from .tools import TWO_PI

TEST_CONFIG_FILE = "data/e4c-config.json"

Expand Down
61 changes: 61 additions & 0 deletions hkl/tests/test_restore_reflections.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""
Test that reflections from one sample are not restored to other samples.
"""

from .. import DiffractometerConfiguration
from .tools import sample_kryptonite
from .tools import sample_silicon
from .tools import sample_vibranium


def test_issue289(e4cv):
assert e4cv is not None

# setup four samples with reflections, all of them different
main = e4cv.calc.sample # the default sample
assert len(main.reflections) == 0
m_100 = main.add_reflection(1, 0, 0, (-45, 0, 0, 0))
m_010 = main.add_reflection(0, 1, 0, (45, 0, 0, 0))
main.compute_UB(m_100, m_010)

kryptonite = sample_kryptonite(e4cv)
assert len(kryptonite.reflections) == 0
k_200 = kryptonite.add_reflection(2, 0, 0, (30, 0, 10, 60))
k_020 = kryptonite.add_reflection(0, 2, 0, (30, 90, 10, 60))
kryptonite.compute_UB(k_200, k_020)

vibranium = sample_vibranium(e4cv)
assert len(vibranium.reflections) == 0
v_003 = vibranium.add_reflection(0, 0, 3, (20.33, 4.33, 8.33, 40.33))
v_033 = vibranium.add_reflection(0, 3, 3, (20.33, -94.33, 8.33, 40.33))
vibranium.compute_UB(v_003, v_033)

silicon = sample_silicon(e4cv)
assert len(silicon.reflections) == 0
s_440 = silicon.add_reflection(4, 4, 0, (34, 44, 54, 64))
s_444 = silicon.add_reflection(4, 4, 4, (34, 134, 54, 64))
silicon.compute_UB(s_440, s_444)

n_saved_reflections = 2
assert len(main.reflections) == n_saved_reflections
assert len(kryptonite.reflections) == n_saved_reflections
assert len(silicon.reflections) == n_saved_reflections
assert len(vibranium.reflections) == n_saved_reflections
# same test, using diffractometer sample dictionary now.
for sample in e4cv.calc._samples.values():
assert len(sample.reflections) == n_saved_reflections, f"{sample.name=}"
assert len(e4cv.calc._samples) == 4

agent = DiffractometerConfiguration(e4cv)
assert agent is not None
config = agent.export()
assert isinstance(config, str)

# Restore the configuration without clearing the diffractometer first.
# This should not change the number of samples or the number of
# reflections for any of the samples.
agent.restore(config, clear=False)

assert len(e4cv.calc._samples) == 4
for sample in e4cv.calc._samples.values():
assert len(sample.reflections) == 2 * n_saved_reflections
6 changes: 3 additions & 3 deletions hkl/tests/test_tardis.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

@pytest.fixture(scope="function")
def kcf_sample(tardis):
from . import new_sample
from .tools import new_sample

# note: orientation matrix (below) was pre-computed with this wavelength
# wavelength units must match lattice unit cell length units
Expand Down Expand Up @@ -90,7 +90,7 @@ def test_params(tardis):
"""
Make sure the parameters are set correctly
"""
from . import TARDIS_TEST_MODE
from .tools import TARDIS_TEST_MODE

calc = tardis.calc
assert calc.pseudo_axis_names == "h k l".split()
Expand Down Expand Up @@ -319,7 +319,7 @@ def test_sample1(sample1, tardis):

def test_sample1_calc_only():
"""Comparisons start with the Tardis' calc support (no Diffractometer object)."""
from . import TARDIS_TEST_MODE
from .tools import TARDIS_TEST_MODE

tardis_calc = hkl_calc.CalcE6C()

Expand Down
38 changes: 38 additions & 0 deletions hkl/tests/tools.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
Common code, setups, constants, ... for these tests.
Avoids direct imports of __init__.py.
"""

import logging

import numpy

from ..util import new_lattice

logger = logging.getLogger("ophyd_session_test")

TARDIS_TEST_MODE = "lifting_detector_mu"
TWO_PI = 2 * numpy.pi


def new_sample(diffractometer, name, lattice):
return diffractometer.calc.new_sample(name, lattice=lattice)


def sample_kryptonite(diffractometer):
triclinic = new_lattice(4, 5, 6, 75, 85, 95)
return new_sample(diffractometer, "kryptonite", lattice=triclinic)


def sample_silicon(diffractometer):
from .. import SI_LATTICE_PARAMETER

cubic = new_lattice(SI_LATTICE_PARAMETER)
return new_sample(diffractometer, "silicon", lattice=cubic)


def sample_vibranium(diffractometer):
a0 = TWO_PI
cubic = new_lattice(a0)
return new_sample(diffractometer, "vibranium", lattice=cubic)

0 comments on commit 565d983

Please sign in to comment.