Module: diffract
#
A local subclass of hkl.diffract.Diffractometer
for the desired
diffractometer geometry must be created to define the reciprocal-space
axes and customize the EPICS PVs used for the motor axes. Other
capabilities are also customized in a local subclass.
Examples are provided in the Geometries Examples section.
Common Diffractometer Geometries#
These are the diffractometer geometries provided by the libhkl library [1]:
Special-use Diffractometer Geometries#
These special-use geometries are also provided by the libhkl library [1]:
APS POLAR 6-circle diffractometer. |
|
6-circle Used at Petra3 P09 |
|
4-circle Used at Petra3 P23 |
|
7-circle Used at Petra3 P23 |
|
Used at Soleil |
|
Used at Soleil |
|
Used at Soleil |
|
Used at Soleil |
|
Used at Soleil |
|
Used at Soleil |
|
Used at Soleil |
In all cases, see the libhkl documentation for further information on these geometries.
Energy#
The monochromatic X-ray energy used by the diffractometer is defined as
an ophyd Signal
. The .energy
signal may be used as-provided, as
a constant or the Component may be replaced by an ophyd.EpicsSignal
in a custom subclass of Diffractometer
, to
connect with an EPICS PV from the instrument’s control system. There is
no corresponding .wavelength
signal at the diffractometer level.
The .energy_offset
signal is used to allow for a difference between
the reported energy of .energy
and the energy used for
diffractometer operations .calc.energy
.
These are the terms:
term |
meaning |
---|---|
|
nominal energy (such as value reported by control system) |
|
adjustment from nominal to calibrated energy for diffraction |
|
engineering units to be used for |
|
energy for diffraction (used to compute wavelength) |
|
used for diffraction calculations |
These are the relationships:
.calc.energy = in_keV(.energy + .energy_offset)
.calc.wavelength = A*keV / .calc.energy
For use with other types of radiation (such as neutrons or electrons),
the conversion between energy and wavelength must be changed by editing
the energy and wavelength methods in the hkl.calc.CalcRecip
class.
When the Diffractometer .energy
signal is written (via
.energy.put(value)
operation), the .energy_offset
is added.
This result is converted to keV
as required by the lower-level
hkl.calc
module, and then written to .calc.energy
which in
turn writes the .calc.wavelength
value. Likewise, when
.energy.get()
reads the energy, it takes its value from
.calc.energy
, converts into .energy_units
, and then applies
.energy_offset
.
Tip
How to set energy, offset, and units
To change energy, offset, & units, do it in this order:
First, set units and offset
Finally, set energy
Example for a e4cv
diffractometer:
e4cv.energy_units.put("eV")
e4cv.energy_offset.put(1.5)
e4cv.energy.put(8000)
# now, e4cv.calc.energy = 8.0015 keV
Engineering Units#
The geometries
module is the main user interface, providing
the various diffractometer geometries provided by libhkl as ophyd
PseudoPositioner Devices [2]. Each of these geometries is built from
the base class Diffractometer
, where a feature
has been added to allow the energy units to be set by the user.
Internally, Diffractometer
will apply any
necessary units conversion when interacting with the values from the
calc
module.
In the calc
module (lower level than
Diffractometer
), the units for energy and
wavelength are keV
and angstrom
, respectively. These
engineering units are not changeable by the user since the libhkl code
requires a consistent set of units (it does not anticipate the need to
do a units conversion).
The Python pint package [3] is used to apply any unit conversion.
This table summarizes the units for the energy and wavelength terms for all diffractometer geometries.
diffractometer attribute |
engineering units |
---|---|
|
set by value of |
|
|
|
does not exist in |
|
|
ophyd PseudoPositioner Device: https://blueskyproject.io/ophyd/positioners.html#pseudopositioner
pint (for engineering units conversion): https://pint.readthedocs.io
Control System Energy#
One way to connect the control system energy is to replace the energy
attribute in the custom subclass of hkl.diffract.Diffractometer()
,
connecting it as either ophyd.EpicsSignal
, ophyd.EpicsSignalRO
, or
ophyd.EpicsSignalWithRBV
. In the next example, the monochromator energy,
engineering units, and offset are provided by EPICS. Also, another EPICS PV
controls whether the energy of the diffractometer object should be updated by
changes in the EPICS energy. Note that the
_energy_changed()
method is already
subscribed to updates in the energy
signal. It is not necessary to do this
in the custom subclass. Don’t forget to add the definitions for the real and
pseudo positioners.
1from hkl import E4CV
2import logging
3from ophyd import Component
4from ophyd import EpicsMotor
5from ophyd import EpicsSignal
6from ophyd import PseudoSingle
7
8logger = logging.getLogger(__name__)
9
10class LocalDiffractometer(E4CV):
11 h = Component(PseudoSingle, '', kind="hinted")
12 k = Component(PseudoSingle, '', kind="hinted")
13 l = Component(PseudoSingle, '', kind="hinted")
14
15 omega = Component(EpicsMotor, "EPICS:m1", kind="hinted")
16 chi = Component(EpicsMotor, "EPICS:m2", kind="hinted")
17 phi = Component(EpicsMotor, "EPICS:m3", kind="hinted")
18 tth = Component(EpicsMotor, "EPICS:m4", kind="hinted")
19
20 energy = Component(EpicsSignal, "EPICS:energy")
21 energy_units = Component(EpicsSignal, "EPICS:energy.EGU")
22 energy_offset = Component(EpicsSignal, "EPICS:energy:offset")
23 energy_update_calc_flag = Component(EpicsSignal, "EPICS:energy:lock")
24
25fourc = LocalDiffractometer("", name="fourc")
26fourc.wait_for_connection()
27fourc._energy_changed() # force the callback to update
Source code documentation#
diffract#
Common Support for diffractometers
|
Diffractometer pseudopositioner |
- class hkl.diffract.Diffractometer(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Diffractometer pseudopositioner
PUBLIC API
The calculation instance
The calculation engine associated with the diffractometer
forward
(pseudo)Calculate the real positions given the pseudo positions (hkl -> angles).
inverse
(real)Calculate the pseudo positions given the real positions (angles -> hkl).
forward_solutions_table
(reflections[, full, ...])Return table of computed solutions for each supplied (hkl) reflection.
apply_constraints
(constraints)Constrain the solutions of the diffractometer's forward() computation.
get_axis_constraints
(axis)Show the constraints for one axis.
Set constraints back to initial settings.
show_constraints
([fmt, printing])Print the current constraints in a table.
Remove the current constraints additions, restore previous.
pa
([all_samples, printing])Report (all) the diffractometer settings.
wh
([printing])Report (brief) where is the diffractometer.
Print a table describing this diffractometer geometry.
PRIVATE API
return boolean True if permitted
Return the constraints.
Return the constraints for databroker.
_energy_changed
([value])Callback indicating that the energy signal was updated
_energy_offset_changed
([value])Callback indicating that the energy offset signal was updated.
_energy_units_changed
([value])Callback indicating that the energy units signal was updated.
push current constraints onto the stack
_set_constraints
(constraints)set diffractometer's constraints
_update_calc_energy
([value])writes
self.calc.energy
fromvalue
orself.energy
.A Diffractometer has a corresponding calculation engine from hklpy that does forward and inverse calculations.
If instantiating a specific diffractometer class such as E4C, E6C, neither the calc_inst or the calc_kw parameters are required.
However, there is the option to either pass in a calculation instance (with calc_inst) or keywords for the default calculation class (using calc_kw) to instantiate a new one.
- Parameters:
prefix (str) – PV prefix for all components
calc_kw (dict, optional) – Initializer arguments for the calc class
decision_fcn (callable, optional) – The decision function to use when multiple solutions exist for a given forward calculation. Defaults to arbitrarily picking the first solution.
engine (str, optional) – Calculation engine name. Default:
hkl
read_attrs (list, optional) – Read attributes default to all pseudo and real positioners
configuration_attrs (list, optional) – Defaults to the UB matrix and energy
parent (Device, optional) – Parent device
name (str, optional) – Device name
- calc_class#
Reciprocal calculation class used with this diffractometer. If
None
(as used in hkl.diffract.Diffractometer), calc_inst must be specified upon initialization.- Type:
sub-class of CalcRecip
- max_forward_iterations#
Maximum allowed number of iterations in the
forward()
method before failing to find a forward() solution.- Type:
ophyd.Signal
(default value: 100)
See also
E4CH
E4CV
E6C
K4CV
K6C
Petra3_p09_eh2
Petra3_p23_4c
Petra3_p23_6c
SoleilMars
SoleilNanoscopiumRobot
SoleilSiriusKappa
SoleilSiriusTurret
SoleilSixsMed1p2
SoleilSixsMed2p2
SoleilSixsMed2p3
SoleilSixsMed2p3v2
Zaxis
- property _calc_energy_update_permitted#
return boolean True if permitted
- property _constraints_dict#
Return the constraints.
- property _constraints_for_databroker#
Return the constraints for databroker.
Cannot write a dictionary from bluesky because all values must be of the same data type, chosen from the first item in the list. Just write the values (the boolean will be written as a float.) The constraints will be written in the order of the real positioners.
- _energy_changed(value=None, **kwargs)[source]#
Callback indicating that the energy signal was updated
Note
The energy signal is subscribed to this method in the
Diffractometer.__init__()
method.
- _energy_offset_changed(value=None, **kwargs)[source]#
Callback indicating that the energy offset signal was updated.
Note
The
energy_offset
signal is subscribed to this method in theDiffractometer.__init__()
method.
- _energy_units_changed(value=None, **kwargs)[source]#
Callback indicating that the energy units signal was updated.
Note
The
energy_units
signal is subscribed to this method in theDiffractometer.__init__()
method.
- property _reflections#
Return the list of reflections as a [[float]]
- _update_calc_energy(value=None, **kwargs)[source]#
writes
self.calc.energy
fromvalue
orself.energy
.
- apply_constraints(constraints)[source]#
Constrain the solutions of the diffractometer’s forward() computation.
This action will first save the current constraints onto a stack, enabling both undo and reset features.
- property calc#
The calculation instance
- check_value(pos)[source]#
Raise exception if pos is not within limits.
In a scan, a subset of the pseudo axes may be directed, which are given in a dict from a set message from the bluesky RunEngine.
It is not permitted to scan both pseudo and real positioners.
- property engine#
The calculation engine associated with the diffractometer
- forward(pseudo)[source]#
Calculate the real positions given the pseudo positions (hkl -> angles).
Return the default solution using the
_decision_fcn()
.
- forward_solutions_table(reflections, full=False, digits=5)[source]#
Return table of computed solutions for each supplied (hkl) reflection.
The solutions are calculated using the current UB matrix & constraints.
- pa(all_samples=False, printing=True)[source]#
Report (all) the diffractometer settings.
EXAMPLE:
In [1]: from hkl import SimulatedK4CV In [2]: k4cv = SimulatedK4CV('', name='k4cv') In [3]: k4cv.pa() # FIXME lines are too long to include in source code ===================== ==================================================================== term value ===================== ==================================================================== diffractometer k4cv geometry K4CV class SimulatedK4CV energy (keV) 8.05092 wavelength (angstrom) 1.54000 calc engine hkl mode bissector positions ====== ======= name value ====== ======= komega 0.00000 kappa 0.00000 kphi 0.00000 tth 0.00000 ====== ======= sample: main ================ =================================================== term value ================ =================================================== unit cell edges a=1.54, b=1.54, c=1.54 unit cell angles alpha=90.0, beta=90.0, gamma=90.0 [U] [[1. 0. 0.] [0. 1. 0.] [0. 0. 1.]] [UB] [[ 4.07999046e+00 -2.49827363e-16 -2.49827363e-16] [ 0.00000000e+00 4.07999046e+00 -2.49827363e-16] [ 0.00000000e+00 0.00000000e+00 4.07999046e+00]] ================ =================================================== ===================== ==================================================================== Out[3]: <pyRestTable.rest_table.Table at 0x7f5c16503e20>
- wh(printing=True)[source]#
Report (brief) where is the diffractometer.
EXAMPLE:
In [1]: from hkl import SimulatedK4CV In [2]: k4cv = SimulatedK4CV('', name='k4cv') In [3]: k4cv.wh() ===================== ========= ========= term value axis_type ===================== ========= ========= diffractometer k4cv sample name main energy (keV) 8.05092 wavelength (angstrom) 1.54000 calc engine hkl mode bissector h 0.0 pseudo k 0.0 pseudo l 0.0 pseudo komega 0 real kappa 0 real kphi 0 real tth 0 real ===================== ========= ========= Out[3]: <pyRestTable.rest_table.Table at 0x7f55c4775cd0>
compare with similar function in SPEC:
1117.KAPPA> wh H K L = 0 0 1.7345 Alpha = 20 Beta = 20 Azimuth = 90 Omega = 32.952 Lambda = 1.54 Two Theta Theta Chi Phi K_Theta Kappa K_Phi 40.000000 20.000000 90.000000 57.048500 77.044988 134.755995 114.093455