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.

See also

Auto-assignment

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.

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'}