Diffractometer Axis Names#
In hklpy2, the names of diffractometer axes (pseudos and reals) are not required to match any particular Solver library. Users are free to use any names allowed by ophyd.
User-defined axis names#
Let’s a few examples of diffractometers built with user-defined names.
Pre-built Diffractometer class with automatic mapping
Custom Diffractometer class with automatic mapping
Custom Diffractometer with additional axes where direct the mapping
See also
Pre-built Diffractometer class#
The pre-built diffractometer simulators automatically
map axis names from diffractometer to Solver. Let’s show this
cross-reference map in an IPython console with just a few commands
(using SimulatedTheta2Theta
):
In [6]: from hklpy2 import SimulatedTheta2Theta
In [7]: twoc = SimulatedTheta2Theta(name="twoc")
In [8]: twoc.operator.axes_xref
Out[8]: {'q': 'q', 'theta': 'th', 'ttheta': 'tth'}
Custom Diffractometer class#
Construct a 2-circle diffractometer, one axis for the sample
and one axis for the detector. We can use the
MixinQ
class to define a q
pseudo-axis.
In addition to defining the diffractometer axes, we can choose the
Solver to use with our diffractometer.
The th_tth
Solver has a ThTthSolver
with a "TH TTH Q"
geometry that fits our design.
We set that up in the __init__()
method of our new class:
import hklpy2
from ophyd import Component
from ophyd import SoftPositioner
class S1D1(hklpy2.DiffractometerBase, hklpy2.MixinQ):
sample = Component(SoftPositioner, init_pos=0)
detector = Component(SoftPositioner, init_pos=0)
def __init__(self, *args, **kwargs):
super().__init__(
*args,
solver="th_tth", # solver name
geometry="TH TTH Q", # solver geometry
**kwargs,
)
self.operator.auto_assign_axes() # assign axes
Create a Python object that uses this class:
twoc = S1D1(name="twoc")
Show the mapping between user-defined axes and axis names used by the Solver:
>>> print(twoc.operator.axes_xref)
{'q': 'q', 'sample': 'th', 'detector': 'tth'}
Custom Diffractometer with additional axes#
Consider this example for a two-circle class (with additional axes).
The "TH TTH Q"
Solver geometry expects q
as
the only pseudo axis and th
and tth
as the two real axes
(no extra axes).
We construct this example so that we’ll need to override the
automatic assignment of axes. Look for the pseudos=["q"]
and reals=["theta", "ttheta"]
parts where we define the mapping.
from ophyd import Component, PseudoSingle, SoftPositioner
import hklpy2
class MyTwoC(hklpy2.DiffractometerBase):
# sorted alphabetically for this example
another = Component(PseudoSingle)
horizontal = Component(SoftPositioner, init_pos=0)
q = Component(PseudoSingle)
theta = Component(SoftPositioner, init_pos=0)
ttheta = Component(SoftPositioner, init_pos=0)
vertical = Component(SoftPositioner, init_pos=0)
def __init__(self, *args, **kwargs):
super().__init__(
*args,
solver="th_tth",
geometry="TH TTH Q",
pseudos=["q"],
reals=["theta", "ttheta"],
**kwargs
)
Create the diffractometer:
twoc = MyTwoC(name="twoc")
What are the axes names used by this diffractometer?:
>>> twoc.pseudo_axis_names
['another', 'q']
>>> twoc.real_axis_names
['horizontal', 'theta', 'ttheta', 'vertical']
Show the twoc
diffractometer’s Solver:
>>> twoc.operator.solver
ThTthSolver(name='th_tth', version='0.0.14', geometry='TH TTH Q')
What are the axes expected by this Solver?:
>>> twoc.operator.solver.pseudo_axis_names
['q']
>>> twoc.operator.solver.real_axis_names
['th', 'tth']
>>> twoc.operator.solver.extra_axis_names
[]
Show the cross-reference mapping from diffractometer to Solver axis names (as defined in our MyTwoC class above):
>>> twoc.operator.axes_xref
{'q': 'q', 'theta': 'th', 'ttheta': 'tth'}
Auto-assignment#
In hklpy2, the names of diffractometer axes are not required to match any particular Solver library.
Auto-assignment assigns the first pseudo(s), real(s), and extra(s) defined by the diffractometer as needed by the Solver.
See also
In our diffractometer class (MyTwoC), the axes are sorted alphabetically.
Auto-assignment of axes would not have been correct, because we did not
define the q
axis Component as the first pseudo and theta
& ttheta
as the first real axis Components. Let’s show what auto-assignment
chooses in this case:
>>> twoc.auto_assign_axes()
>>> twoc.operator.axes_xref
{'another': 'q', 'horizontal': 'th', 'theta': 'tth'}