Module: geometries
#
See examples in the Diffractometer Examples section.
Source code documentation#
diffract#
Support for diffractometer instances.
SUPPORT
|
Defines h, k, & l pseudo-positioners. |
DIFFRACTOMETER GEOMETRIES
|
Eulerian 4-circle, horizontal scattering plane |
|
Eulerian 4-circle, vertical scattering plane |
|
Eulerian 6-circle, vertical scattering plane |
|
Kappa 4-circle, vertical scattering plane |
|
Kappa 6-circle, vertical scattering plane |
|
Z-axis geometry |
|
SimulatedE4CV: Eulerian 4-circle diffractometer, vertical |
|
SimulatedE6C: Eulerian 6-circle diffractometer |
|
SimulatedK4CV: Kappa 4-circle diffractometer, vertical |
|
SimulatedK6C: Kappa 6-circle diffractometer |
SPECIAL-USE DIFFRACTOMETER GEOMETRIES
|
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 |
|
Used at Soleil |
- class hkl.geometries.ApsPolar(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
APS POLAR 6-circle diffractometer.
- class hkl.geometries.E4CH(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Eulerian 4-circle, horizontal scattering plane
- class hkl.geometries.E4CV(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Eulerian 4-circle, vertical scattering plane
- class hkl.geometries.E6C(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Eulerian 6-circle, vertical scattering plane
- class hkl.geometries.K4CV(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Kappa 4-circle, vertical scattering plane
- class hkl.geometries.K6C(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Kappa 6-circle, vertical scattering plane
- class hkl.geometries.Petra3_p09_eh2(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
6-circle Used at Petra3 P09
- class hkl.geometries.Petra3_p23_4c(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
4-circle Used at Petra3 P23
- class hkl.geometries.Petra3_p23_6c(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
7-circle Used at Petra3 P23
- class hkl.geometries.SimMixin(prefix='', *, name, kind=None, read_attrs=None, configuration_attrs=None, parent=None, **kwargs)[source]#
Defines h, k, & l pseudo-positioners.
Use this mixin class with any of the diffractometer geometries to create your own simulator. Follow one of the simulators below, such as
SimulatedE4CV
. You should replaceE4CV
with your geomtry’s name. And, you will need to create SoftPositioner components for each of the real-space axes, in the order required by that geometry.
- class hkl.geometries.SimulatedE4CV(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
SimulatedE4CV: Eulerian 4-circle diffractometer, vertical
- class hkl.geometries.SimulatedE6C(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
SimulatedE6C: Eulerian 6-circle diffractometer
- class hkl.geometries.SimulatedK4CV(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
SimulatedK4CV: Kappa 4-circle diffractometer, vertical
- class hkl.geometries.SimulatedK6C(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
SimulatedK6C: Kappa 6-circle diffractometer
- class hkl.geometries.SoleilMars(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Used at Soleil
- class hkl.geometries.SoleilNanoscopiumRobot(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Used at Soleil
- class hkl.geometries.SoleilSiriusKappa(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Used at Soleil
- class hkl.geometries.SoleilSiriusTurret(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Used at Soleil
- class hkl.geometries.SoleilSixsMed1p2(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Used at Soleil
- class hkl.geometries.SoleilSixsMed2p2(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Used at Soleil
- class hkl.geometries.SoleilSixsMed2p3(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Used at Soleil
- class hkl.geometries.SoleilSixsMed2p3v2(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Used at Soleil
- class hkl.geometries.Zaxis(prefix, calc_kw=None, decision_fcn=None, calc_inst=None, engine='hkl', *, configuration_attrs=None, read_attrs=None, **kwargs)[source]#
Z-axis geometry
Examples#
Demonstrate the setup of diffractometers using the hkl package.
The Module: sample Examples section describes how to setup a crystal sample with an orientation matrix.
sim6c
: Eulerian 6-circle with simulated motors#
It is useful, sometimes, to create a simulated diffractometer where the motor axes are provided by software simulations, [1] rather than using the actual motors provided by the diffractometer.
Load the simulated 6-circle geometry from hklpy:
1from hkl import SimulatedE6C
Create an instance of this diffractometer with:
sim6c = SimulatedE6C("", name="sim6c")
k4cv
: kappa 4-circle with EPICS motor PVs#
To control a kappa diffractometer (in 4-circle geometry with vertical
scattering plane) where the motor axes are provided by EPICS PVs, use
ophyd.EpicsMotor
. [2]
In this example, we know from our local control system that the kappa motors have these PVs:
kappa axis |
EPICS PVs |
---|---|
komega |
sky:m1 |
kappa |
sky:m2 |
kphi |
sky:m3 |
tth |
sky:m4 |
ophyd.EpicsMotor
:
https://blueskyproject.io/ophyd/builtin-devices.html?highlight=epicsmotor#ophyd.epics_motor.EpicsMotor
In this case, we must first create a custom kappa 4-circle subclass and connect our motor PVs to the positioners for the real axes:
1import hkl
2from ophyd import Component
3from ophyd import EpicsMotor
4from ophyd import PseudoSingle
5
6class KappaK4CV(hkl.K4CV):
7 """K4CV: kappa diffractometer in 4-circle geometry"""
8
9 h = Component(PseudoSingle, "")
10 k = Component(PseudoSingle, "")
11 l = Component(PseudoSingle, "")
12
13 komega = Component(EpicsMotor, "sky:m1")
14 kappa = Component(EpicsMotor, "sky:m2")
15 kphi = Component(EpicsMotor, "sky:m3")
16 tth = Component(EpicsMotor, "sky:m4")
Create an instance of this diffractometer with:
k4cv = KappaK4CV("", name="k4cv")
k4cve
: k4cv
with energy from local control system#
Extend the k4cv
example above to use the energy as provided by the
local control system. In this example, assume these are the PVs to be
used:
signal |
EPICS PV |
---|---|
energy |
optics:energy |
energy units |
optics:energy.EGU |
energy locked? |
optics:energy_locked |
energy offset |
no PV, same units as energy (above) |
The energy locked? signal is a flag controlled by the user that controls whether (or not) the energy signal will update the wavelength of the diffractometer’s calc engine. We expect this to be either 1 (update the calc engine) or 0 (do NOT update the calc engine).
We’ll also create a (non-EPICS) signal to provide for an energy offset
(in the same units as the control system energy). This offset will be
added to the control system energy (in
_update_calc_energy()
), before
conversion of the units to keV and then setting the diffractometer’s
calc engine energy:
calc engine energy (keV) = in_keV(control system energy + offset)
which then sets the wavelength:
calc engine wavelength (angstrom) = \(h\nu\) / calc engine energy
(\(h\nu=\) 12.39842 angstrom \(\cdot\) keV) and account for the
units of the control system energy. To combine all this, we define a
new python class starting similar to KappaK4CV
above, and adding the
energy signals. Create the custom kappa 4-circle subclass with energy:
1import hkl
2from ophyd import Component
3from ophyd import PseudoSingle
4from ophyd import EpicsMotor
5from ophyd import EpicsSignal
6from ophyd import Signal
7import pint
8
9class KappaK4CV_Energy(hkl.K4CV):
10 """
11 K4CV: kappa diffractometer in 4-circle geometry with energy
12 """
13
14 h = Component(PseudoSingle, "")
15 k = Component(PseudoSingle, "")
16 l = Component(PseudoSingle, "")
17
18 komega = Component(EpicsMotor, "sky:m1")
19 kappa = Component(EpicsMotor, "sky:m2")
20 kphi = Component(EpicsMotor, "sky:m3")
21 tth = Component(EpicsMotor, "sky:m4")
22
23 energy = Component(EpicsSignal, "optics:energy")
24 energy_units = Component(EpicsSignal, "optics:energy.EGU")
25 energy_offset = Component(Signal, value=0)
26 energy_update_calc_flag = Component(
27 EpicsSignal,
28 "optics:energy_locked")
Create an instance of this diffractometer with:
k4cve = KappaK4CV_Energy("", name="k4cve")
Note
If you get a log message such as this on the console:
W Fri-09:12:16 - k4cve not fully connected, k4cve.calc.energy not updated
this informs you the update cannot happen until all EPICS PVs are connected. The following code, will create the object, wait for all PVs to connect, then update the calc engine:
k4cve = KappaK4CV_Energy("", name="k4cve")
k4cve.wait_for_connection()
k4cve._energy_changed(k4cve.energy.get())
To set the energy offset from the command line:
%mov k4cve.energy_offset 50
which means the diffractometer (assuming the control system uses “eV”
units) will use an energy that is 50 eV higher than the control system
reports. The diffractometer’s calc engine will only be updated
when the energy signal is next updated. To force an update to the calc
engine, call _energy_changed()
directly with the energy value as the
argument:
k4cve._energy_changed()
But this only works when the optics:energy_locked
PV is 1 (permitted
to update the calc engine energy). To update the diffractometer’s calc
engine energy and bypass the k4cve.energy_update_calc_flag
signal,
call this command:
k4cve._update_calc_energy()
Finally, to set the energy of the diffractometer’s calc engine, use one of these two methods:
|
command |
---|---|
obey signal |
|
ignore signal |
|
Each of these two methods will accept an optional value
argument
which, if provided, will be used in place of the energy
signal from
the control system.