Skip to content

Commit

Permalink
Merge branch 'main' into 290-docs-constraints
Browse files Browse the repository at this point in the history
  • Loading branch information
prjemian authored Nov 22, 2023
2 parents cedc797 + bb4ac84 commit 06e0aad
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 64 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/conda_unit_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
max-parallel: 5

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4

- name: Create Python ${{ matrix.python-version }} environment
uses: mamba-org/setup-micromamba@v1
Expand Down
15 changes: 10 additions & 5 deletions .github/workflows/publish-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,21 @@ jobs:
run: |
echo "The docs will be published from this workflow run."
- name: Install Python ${{ matrix.python-version }} Conda environment with micromamba from env-dev.yml
uses: mamba-org/provision-with-micromamba@main
- name: Create Python documentation environment
uses: mamba-org/setup-micromamba@v1
with:
environment-file: env-dev.yml
environment-name: test
environment-name: documentation
condarc: |
channel-priority: flexible
init-shell: bash
cache-environment: true
cache-environment-key: env-key

- name: Install the package locally
shell: bash -l {0}
run: |
pip install -e .
pip install --no-deps -e . -vv
- name: Diagnostics
shell: bash -l {0}
Expand All @@ -72,7 +77,7 @@ jobs:
conda list
env | sort | grep -i CONDA
- name: Build Docs
- name: Build Docs with Sphinx
shell: bash -l {0}
run: |
make -C docs clean html
Expand Down
1 change: 1 addition & 0 deletions RELEASE_NOTES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ New Features and/or Enhancements
* Add ``SoleilNanoscopiumRobot`` diffractometer geometry.
* Add ``SoleilSixsMed2p3v2`` diffractometer geometry.
* Export and restore diffractometer configuration as JSON string, YAML string, Python dictionary, or file.
* Add ``user.current_diffractometer()`` function.

Fixes
-----
Expand Down
2 changes: 1 addition & 1 deletion env-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ dependencies:
- apischema
- black
- bluesky
- databroker =1.2
- databroker
- flake8
- hkl
- ipython
Expand Down
1 change: 0 additions & 1 deletion environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ dependencies:
- python >=3.8,<3.12
- apischema
- bluesky
- databroker =1.2
- hkl
- numpy
- ophyd
Expand Down
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 @@ -261,12 +263,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 @@ -282,18 +284,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 @@ -550,6 +552,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)
16 changes: 12 additions & 4 deletions hkl/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
~cahkl
~cahkl_table
~calc_UB
~current_diffractometer
~list_samples
~new_sample
~or_swap
Expand All @@ -29,6 +30,7 @@
cahkl_table
calc_UB
change_sample
current_diffractometer
list_samples
new_sample
or_swap
Expand Down Expand Up @@ -124,6 +126,11 @@ def change_sample(sample):
show_sample(sample)


def current_diffractometer():
"""Return the currently-selected diffractometer (or ``None``)."""
return _geom_


def list_samples(verbose=True):
"""List all defined crystal samples."""
_check_geom_selected()
Expand Down Expand Up @@ -256,9 +263,10 @@ def show_sample(sample_name=None, verbose=True):

def show_selected_diffractometer(instrument=None):
"""Print the name of the selected diffractometer."""
if _geom_ is None:
geom = current_diffractometer()
if geom is None:
print("No diffractometer selected.")
print(_geom_.name)
print(geom.name)


def update_sample(a, b, c, alpha, beta, gamma):
Expand All @@ -278,10 +286,10 @@ def update_sample(a, b, c, alpha, beta, gamma):
def pa():
"""Report (all) the diffractometer settings."""
_check_geom_selected()
_geom_.pa()
current_diffractometer().pa()


def wh():
"""Report (brief) where is the diffractometer."""
_check_geom_selected()
_geom_.wh()
current_diffractometer().wh()
Loading

0 comments on commit 06e0aad

Please sign in to comment.