diffract#

Import: hklpy2.diffract

Base class for all diffractometers

creator(*, prefix, name, solver, geometry, ...)

Factory function to create a diffractometer instance.

diffractometer_class_factory(*, solver, ...)

Build a custom class for this diffractometer geometry.

DiffractometerBase([prefix, solver, ...])

Base class for all diffractometers.

Hklpy2PseudoAxis([prefix, limits, egu, ...])

Override to allow auxiliary pseudos.

Module Contents#

hklpy2.diffract.DEFAULT_PHOTON_ENERGY_KEV = 8.0[source]#
class hklpy2.diffract.DiffractometerBase(prefix: str = '', *, solver: str | None = None, geometry: str | None = None, solver_kwargs: dict = {}, pseudos: list[str] = [], reals: list[str] = [], reals_units: str | None = None, forward_solution_function: Callable | None = None, **kwargs)[source]#

Import: hklpy2.diffract.DiffractometerBase

Bases: ophyd.PseudoPositioner

Base class for all diffractometers.

PARAMETERS

solverstr

Name of Solver library. (default: unspecified)

geometrystr

Name of Solver geometry. (default: unspecified)

solver_kwargsDict(str, Any)

Any additional keyword arguments needed by Solver library. (default: empty)

pseudosList[str]

List of diffractometer axis names to be used as pseudo axes. (default: unspecified)

realsList[str]

List of diffractometer axis names to be used as real axes. (default: unspecified)

forward_solution_functionCallable

Function to pick one solution from list of possibilities. Used by forward(). (default: pick_first_solution())

reals_unitsstr

The units for the real axes. (default: “degrees”)

(ophyd) Components

Python Attributes

_forward_solution(solutions)

Choose first solution from list.

Python Methods

add_reflection(pseudos[, reals, wavelength, ...])

Add a new reflection with this geometry to the selected sample.

add_sample(name, a[, b, c, alpha, beta, ...])

Add a new sample.

export(file[, comment])

Export the diffractometer configuration to a YAML file.

forward(pseudos[, wavelength])

Compute real-space coordinates from pseudos (hkl -> angles).

full_position([digits])

Return dict with positions of pseudos, reals, & extras.

inverse(reals[, wavelength])

Compute pseudo-space coordinates from reals (angles -> hkl).

move_dict(axes)

(plan) Move diffractometer axes to positions in 'axes'.

move_forward_with_extras(pseudos, extras)

(plan stub) Compute forward solution at fixed pseudos and extras.

move_inverse_with_extras(reals, extras)

(plan stub) Compute inverse solution at fixed reals and extras.

move_reals(reals)

(not a plan) Move the real-space axes as specified in 'real_positions'.

restore(config[, clear, ...])

Restore diffractometer configuration.

scan_extra(detectors, *args[, num, pseudos, ...])

Scan extra diffractometer parameter(s), such as 'psi'.

wh([digits, full])

Concise report of the current diffractometer positions.

Python Properties

auxiliary_axis_names

Names of all auxiliary positioners, in order of appearance.

configuration

Diffractometer configuration (orientation).

is_simulator

True when every real positioner is an ophyd.SoftPositioner.

pseudo_axis_names

Names of all the pseudo axes, in order of appearance.

real_axis_names

Names of all the real axes, in order of appearance.

reals_units

Engineering units for the reals (rotational) axes

sample

Current sample object.

samples

Dictionary of samples.

add_reflection(pseudos, reals=None, wavelength: float | None = None, wavelength_units: str | None = None, name: str | None = None, replace: bool = False) Reflection[source]#

Add a new reflection with this geometry to the selected sample.

PARAMETERS

pseudos various:

Pseudo-space axes and values.

reals various:

Dictionary of real-space axes and values.

wavelength float:

Wavelength of incident radiation. If None, diffractometer’s current wavelength will be assigned.

wavelength_units str:

Optional units for the supplied wavelength (e.g. “angstrom”). If None, the diffractometer’s current beam units are used.

name str:

Reference name for this reflection. If None, a random name will be assigned.

replace bool:

If True, replace existing reflection matching this name. (default: False)

add_sample(name: str, a: float, b: float | None = None, c: float | None = None, alpha: float = 90.0, beta: float | None = None, gamma: float | None = None, digits: int = 4, replace: bool = False) Sample[source]#

Add a new sample.

property auxiliary_axis_names: list[str][source]#

Names of all auxiliary positioners, in order of appearance.

Auxiliary axes are all components using (subclasses of ‘ophyd.PositionerBase’) that are not pseudos or reals. This includes nested ophyd.PseudoPositioner sub-devices; their structured .position values are rendered inline by wh() (see issue issue #385).

Example:

>>> fourc.auxiliary_axis_names
['h2', 'k2', 'l2']
beam[source]#

Incident monochromatic beam.

property configuration: KeyValueMap[source]#

Diffractometer configuration (orientation).

core[source]#
property digits: int[source]#

Number of decimal digits used when rendering position tuples.

This is a per-instance property. Reading returns the instance value if set, otherwise the class default. Setting updates the instance value and re-wraps the instance’s PseudoPosition/RealPosition classes so the new digit count is used for their string representations.

export(file, comment='') None[source]#

Export the diffractometer configuration to a YAML file.

Example:

import hklpy2

e4cv = hklpy2.creator(name="e4cv")
e4cv.export("e4cv-config.yml", comment="example")
forward(pseudos: dict, wavelength: float | None = None) NamedTuple[source]#

Compute real-space coordinates from pseudos (hkl -> angles).

full_position(digits=4) KeyValueMap[source]#

Return dict with positions of pseudos, reals, & extras.

inverse(reals: tuple, wavelength: float | None = None) NamedTuple[source]#

Compute pseudo-space coordinates from reals (angles -> hkl).

property is_simulator: bool[source]#

True when every real positioner is an ophyd.SoftPositioner.

Computed once in __init__; this is a classification of the components, not a liveness check. Used by restore() to choose conservative defaults on hardware-backed diffractometers.

move_dict(axes: AxesDict) BlueskyPlanType[source]#

(plan) Move diffractometer axes to positions in ‘axes’.

move_forward_with_extras(pseudos: AnyAxesType, extras: AxesDict) BlueskyPlanType[source]#

(plan stub) Compute forward solution at fixed pseudos and extras.

EXAMPLE:

RE(
    diffractometer.move_forward_with_extras(
        pseudos=dict(h=2, k=1, l=0),
        extras=dict(h2=2, k2=2, l2=0, psi=25),
    )
)
move_inverse_with_extras(reals: AnyAxesType, extras: AxesDict) BlueskyPlanType[source]#

(plan stub) Compute inverse solution at fixed reals and extras.

EXAMPLE:

RE(
    move_inverse_with_extras(
        diffractometer,
        reals=dict(omega=10, chi=0, phi=0, phi=20),
        extras=dict(h2=2, k2=2, l2=0, psi=25),
    )
)
move_reals(reals: AnyAxesType) None[source]#

(not a plan) Move the real-space axes as specified in ‘real_positions’.

property pseudo_axis_names: None[source]#

Names of all the pseudo axes, in order of appearance.

Example:

>>> fourc.pseudo_axis_names
['h', 'k', 'l']
property real_axis_names: None[source]#

Names of all the real axes, in order of appearance.

Example:

>>> fourc.real_axis_names
['omega', 'chi, 'phi', 'tth']
property reals_units: str[source]#

Engineering units for the reals (rotational) axes

restore(config, clear=None, restore_constraints=None, restore_wavelength=None, restore_mode=None, restore_samples=None, restore_extras=None, restore_presets=None) None[source]#

Restore diffractometer configuration.

Example:

import hklpy2

e4cv = hklpy2.creator(name="e4cv")
e4cv.restore("e4cv-config.yml")

restore() itself never moves a motor. However, several of the sections it can apply (samples / U / UB, extras, wavelength, solver mode) are inputs to the next forward() call and would change the angles a subsequent move would target. To prevent that from happening silently when the diffractometer is hardware-backed (self.is_simulator == False), each restore_* kwarg defaults to None and is resolved as follows:

  • simulator (is_simulator == True): all restore_* default to True except restore_mode which defaults to False. This preserves the historic behavior used by simulator_from_config().

  • hardware-backed (is_simulator == False): restore_constraints and restore_presets default to True (these only narrow the search space or pre-load extras when a mode is later entered). restore_samples, restore_extras, restore_wavelength, restore_mode, and clear default to False. A single UserWarning is emitted listing the sections that were skipped, so the user can opt back in by passing the corresponding kwarg(s) explicitly.

Passing any restore_* kwarg explicitly (True or False) always honors that value regardless of is_simulator.

PARAMETERS

configdict, str, or pathlib object

Dictionary with configuration, or name (str or pathlib object) of diffractometer configuration YAML file.

clearbool, optional

If True, reset constraints and samples to defaults before restoring. If False, sample reflections from the configuration are appended to existing ones; existing reflections are not changed. Default depends on is_simulator (see above).

restore_constraintsbool, optional

If True, restore constraints. Default depends on is_simulator (see above).

restore_wavelengthbool, optional

If True, restore wavelength / energy. Default depends on is_simulator (see above).

restore_modebool, optional

If True, the saved solver mode is applied. Use with caution on hardware-backed diffractometers — changing mode can cause forward() to target axes that were previously held fixed. Default depends on is_simulator (see above); a warning is emitted when defaults skip the mode and the saved mode differs from the current mode.

restore_samplesbool, optional

If True, restore samples (lattice, reflections, U, UB, and the active sample name). Default depends on is_simulator (see above).

restore_extrasbool, optional

If True, restore solver extras (e.g. h2, k2, l2, psi). Default depends on is_simulator (see above).

restore_presetsbool, optional

If True, restore per-mode axis presets. Default depends on is_simulator (see above).

Note: Can’t name this method “import”, it’s a reserved Python word.

property sample: None | Sample[source]#

Current sample object.

property samples: dict[str, Sample][source]#

Dictionary of samples.

scan_extra(detectors: Iterable[Readable], *args: Movable | Any, num: int | None = 2, pseudos: dict | None = None, reals: dict | None = None, extras: dict | None = None, fail_on_exception: bool | None = False, md: dict | None = None) BlueskyPlanType[source]#

Scan extra diffractometer parameter(s), such as ‘psi’.

  • iterate extra positions as described:
    • set extras

    • solution = forward(pseudos)

    • move to solution

    • acquire (trigger) all controls

    • read and record all controls

Parameters

detectors: Iterable[Readable]

List of readable objects.

args: Any

Specification of scan axes.

The ‘args’ specification is a repeating pattern of axis (str), start (float), stop (float).

In general:

axis1, start1, stop1, axis2, start2, stop2, ..., axisN, startN,
stopN

Axis is any extra axis name supported by the current diffractometer geometry and mode.

num: int

Number of points.

pseudos: dict

Dictionary of pseudo axes positions to be held constant during the scan.

reals: dict

Dictionary of real axes positions to be held constant during the scan.

extras: dict

Dictionary of extra axes positions to be held constant during the scan.

fail_on_exception: bool

When True (deafult: False), scan will raise any exceptions. When False, all exceptions during the scan will be printed to console.

md: dict

Dictionary of user-supplied metadata.

wh(digits=4, full=False) None[source]#

Concise report of the current diffractometer positions.

hklpy2.diffract.H_OR_N[source]#
class hklpy2.diffract.Hklpy2PseudoAxis(prefix='', *, limits=None, egu='', parent=None, name=None, source='computed', target_initial_position=False, **kwargs)[source]#

Import: hklpy2.diffract.Hklpy2PseudoAxis

Bases: ophyd.PseudoSingle

Override to allow auxiliary pseudos.

property position: NamedTuple[source]#

The current position of the positioner in its engineering units

Return type:

position

hklpy2.diffract.T[source]#
hklpy2.diffract.creator(*, prefix: str = '', name: str = '', solver: str = 'hkl_soleil', geometry: str = 'E4CV', beam_kwargs: dict[str, object] = None, solver_kwargs: dict[str, object] = {}, _pseudo: Sequence[str] | None = None, pseudos: list = [], _real: Sequence[str] | None = None, reals: Sequence[str] | KeyValueMap | None = {}, motor_labels: Sequence[str] | None = ['motors'], labels: list = ['diffractometer'], class_name: str = 'Hklpy2Diffractometer', class_bases: list = [DiffractometerBase], forward_solution_function: str | None = None, **kwargs) DiffractometerBase[source]#

Import: hklpy2.diffract.creator

Factory function to create a diffractometer instance.

EXAMPLES:

Four-circle diffractometer, vertical orientation, Eulerian rotations, canonical real axis names, EPICS motor PVs:

e4cv = creator(name="e4cv",
    solver="hkl_soleil", geometry="E4CV",
    reals=dict(omega="IOC:m1", chi="IOC:m2", phi="IOC:m3", tth="IOC:m4"),
)

Four-circle diffractometer, vertical orientation, Eulerian rotations, custom real axis names, simulated positioners:

sim4c = creator(name="sim4c",
    solver="hkl_soleil", geometry="E4CV",
    reals=dict(uno=None, dos=None, tres=None, cuatro=None),
)

The same sim4c diffractometer, but the reals are specified in a different order. In this case, _real declares the order of these axes as expected by the solver:

sim4c = creator(name="sim4c",
    solver="hkl_soleil", geometry="E4CV",
    reals=dict(cuatro=None, dos=None, tres=None, uno=None),
    _real=["uno", "dos", "tres", "cuatro"],
)

(Simplest case to get a simulator.) Four-circle diffractometer, vertical orientation, Eulerian rotations, canonical real axis names, simulated positioners (all default settings):

sim4c = creator(name="sim4c")

Kappa six-circle diffractometer, simulated motors:

simk6c = creator(name="simk6c",
    solver="hkl_soleil", geometry="K6C"
)

PARAMETERS

prefixstr

EPICS PV prefix (default: empty string)

namestr

Name of the ophyd diffractometer object to be created. (default: ‘””’)

solverstr

Name of the backend solver providing the geometry. (default: ‘“hkl_soleil”’)

geometrystr

Name of the diffractometer geometry. (default: ‘“E4CV”’)

beam_kwargsdict[str, object]

Additional configuration for the incident beam. (default: ‘{“class”: “hklpy2.incident.WavelengthXray”}’)

solver_kwargsdict[str, object]

Additional configuration for the solver. (default: ‘{“engine”: “hkl”}’)

_pseudo: list[str]

Names which (and in what order of appearance) any of the ‘pseudos’ is to be used. The list is necessary when the ‘pseudos’ are provided in an order different than expected by the solver’s ‘forward()’ and ‘inverse()’ methods.

pseudoslist

Specification of the names of any pseudo axis positioners in addition to the ones provided by the solver.

(default: ‘[]’ which means no additional pseudo axes)

_real: list[str]

Names which (and in what order of appearance) any of the ‘reals’ is to be used. The list is necessary when the ‘reals’ are provided in an order different than expected by the solver’s ‘forward()’ and ‘inverse()’ methods.

realsdict

Specification of the real axis motors. Dictionary keys are the motor names, values are the EPICS motor PV for that axis. If the PV is ‘None’, use a simulated positioner.

The dictionary can be empty or must have at least the canonical number of real axes. The order of the axes is important. The names provided will be mapped to the canonical order defined by the solver. Components will be created for any extra reals.

(default: ‘{}’ which means use the canonical names for the real axes and use simulated positioners)

motor_labelslist

Ophyd object labels for each real positioner. (default: ‘[“motors”]’)

labelslist

Ophyd object labels for the diffractometer object. (default: ‘[“diffractometer”]’)

class_namestr

Name to use for the diffractometer class. (default: ‘“Hklpy2Diffractometer”’)

class_baseslist

List of base classes to use for the diffractometer class. (default: ‘[DiffractometerBase]’)

forward_solution_functionstr

Name of function to pick one solution from list of possibilities. Used by forward(). (default: pick_first_solution())

Will be assigned to hklpy2.diffract.DiffractometerBase._forward_solution.

kwargsany

Additional keyword arguments will be added when constructing the new diffractometer object.

hklpy2.diffract.diffractometer_class_factory(*, solver: str = 'hkl_soleil', geometry: str = 'E4CV', beam_kwargs: dict[str, object] = None, solver_kwargs: dict[str, object] = {'engine': 'hkl'}, _pseudo: Sequence[str] | None = None, pseudos: list = [], _real: Sequence[str] | None = None, reals: list[str] | dict[str, str | None] = {}, motor_labels: Sequence[str] | None = ['motors'], class_name: str = 'Hklpy2Diffractometer', class_bases: list = [DiffractometerBase], forward_solution_function: str | None = None) DiffractometerBase[source]#

Import: hklpy2.diffract.diffractometer_class_factory

Build a custom class for this diffractometer geometry.

PARAMETERS

solverstr

Name of the backend solver providing the geometry. (default: ‘“hkl_soleil”’)

geometrystr

Name of the diffractometer geometry. (default: ‘“E4CV”’)

beam_kwargsdict[str, object]

Additional configuration for the incident beam. (default: ‘{“class”: “hklpy2.incident.WavelengthXray”}’)

solver_kwargsstr

Additional configuration for the solver. (default: ‘{“engine”: “hkl”}’)

_pseudo: list[str]

Names which (and in what order of appearance) any of the ‘pseudos’ is to be used. The list is necessary when the ‘pseudos’ are provided in an order different than expected by the solver’s ‘forward()’ and ‘inverse()’ methods.

pseudoslist

Specification of the names of any pseudo axis positioners in addition to the ones provided by the solver.

(default: ‘[]’ which means no additional pseudo axes)

_real: list[str]

Names which (and in what order of appearance) any of the ‘reals’ is to be used. The list is necessary when the ‘reals’ are provided in an order different than expected by the solver’s ‘forward()’ and ‘inverse()’ methods.

realsdict or list or None

Specification of the real axis motors.

None or empty means use the canonical names for the real axes and use simulated positioners (ophyd.SoftPositioner) for each. Otherwise, you must specify at least the number of real axes expected by the solver geometry.

list:

Specify the names of the real axis motors. The names will be matched, in order, to the names used by the solver. The default class will be ophyd.SoftPositioner.

dict:
Keys: The names of the real axis motors. The names will be

matched, in order, to the names used by the solver.

Values:
  • A string representing the EPICS motor PV.

  • None for a simulated positioner using ophyd.SoftPositioner.

  • A dictionary with additional specifications for the motor constructor. Use this case for any case where either a string or None are insufficient to specify all necessary parameters.

motor_labelslist

Ophyd object labels for each real positioner. (default: ‘[“motors”]’)

class_namestr

Name to use for the diffractometer class. (default: ‘“Hklpy2Diffractometer”’)

class_baseslist

List of base classes to use for the diffractometer class. (default: ‘[DiffractometerBase]’)

forward_solution_functionstr

Name of function to pick one solution from list of possibilities. Used by forward(). (default: pick_first_solution())

Will be assigned to hklpy2.diffract.DiffractometerBase._forward_solution.