Skip to content

Commit

Permalink
DOC #25 #26
Browse files Browse the repository at this point in the history
  • Loading branch information
prjemian committed Oct 1, 2020
1 parent fd73726 commit f4d882d
Showing 1 changed file with 111 additions and 15 deletions.
126 changes: 111 additions & 15 deletions doc/source/diffract.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
diffract
--------

In most cases, a local subclass of the desired
diffractometer geometry is created to customize
the EPICS PVs used for the motor axes. Other
A local subclass of 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 after the source code documentation.

These are the diffractometer geometries defined:

=========================== ==========================
Expand Down Expand Up @@ -38,15 +40,27 @@ for further information on these geometries.

https://people.debian.org/~picca/hkl/hkl.html#org7ea41dd

## Examples
----

Source code documentation
+++++++++++++++++++++++++

.. automodule:: hkl.diffract
:members:

----

Examples
++++++++

Demonstrate the setup of diffractometers using the *hkl* package.

* ``sim6c`` : simulated 6-circle
* ``k4cv`` : kappa 4-circle with EPICS PVs for motors
* ``k4cve`` : ``k4cv`` with energy from local control system

### 6-circle with simulated motors
``sim6c``: 6-circle with simulated motors
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

It is useful, sometimes, to create a simulated
diffractometer where the motor axes are provided
Expand Down Expand Up @@ -91,7 +105,8 @@ Create an instance of this diffractometer with::

sim6c = SimulatedE6C('', name='sim6c')

### kappa 4-circle with EPICS motor PVs
``k4cv`` : kappa 4-circle with EPICS motor PVs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To control a kappa diffractometer (in 4-circle geometry
with vertical scattering plane)
Expand Down Expand Up @@ -120,8 +135,8 @@ Create the custom kappa 4-circle subclass::
import hkl.diffract
from ophyd import Component, PseudoSingle, EpicsMotor

class SimulatedE6C(hkl.diffract.K6CV):
"""E6C: kappa diffractometer in 4-circle geometry"""
class KappaK4CV(hkl.diffract.K4CV):
"""K4CV: kappa diffractometer in 4-circle geometry"""

h = Component(PseudoSingle, '')
k = Component(PseudoSingle, '')
Expand All @@ -134,15 +149,96 @@ Create the custom kappa 4-circle subclass::

Create an instance of this diffractometer with::

k4cv = SimulatedE6C('', name='k4cv')
k4cv = KappaK4CV('', name='k4cv')

### ``k4cv`` with energy from local control system
``k4cve`` : ``k4cv`` with energy from local control system
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

-tba-
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)
============== ====================

## Source code documentation
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).

.. automodule:: hkl.diffract
:members:
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, before
conversion of the units to *keV* and then setting the
diffractometer's *calc* engine energy (which then sets
the wavelength).

Create the custom kappa 4-circle subclass with energy::

import gi
gi.require_version('Hkl', '5.0')
# MUST come before `import hkl`
import hkl.diffract
from ophyd import Component, PseudoSingle, EpicsMotor

class KappaK4CV_Energy(hkl.diffract.K4CV):
"""K4CV: kappa diffractometer in 4-circle geometry with energy"""

h = Component(PseudoSingle, '')
k = Component(PseudoSingle, '')
l = Component(PseudoSingle, '')

komega = Component(EpicsMotor, "sky:m1")
kappa = Component(EpicsMotor, "sky:m2")
kphi = Component(EpicsMotor, "sky:m3")
tth = Component(EpicsMotor, "sky:m4")

energy = Component(EpicsSignal, "optics:energy")
energy_EGU = Component(EpicsSignal, "optics:energy.EGU")
energy_update_calc = Component(EpicsSignal, "optics:energy_locked")
energy_offset = Component(Signal, value=0)

def _energy_changed(self, value=None, **kwargs):
'''
Callback indicating that the energy signal was updated
'''
if energy_update_calc.get() in (1, "Yes", "locked", "OK"):
# energy_offset has same units as energy
local_energy = value + self.energy_offset.get()

# either get units from control system
units = self.energy_EGU.get()
# or define as a constant here
# units = "eV"

logger.debug(
'{0.name} energy changed: {1} {2}'.format(
self, value, units))
keV = pint.Quantity(local_energy, units).to("keV")
self._calc.energy = keV
self._update_position()

Create an instance of this diffractometer with::

k4cve = KappaK4CV_Energy('', name='k4cv')

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(k4cve.energy.get())

0 comments on commit f4d882d

Please sign in to comment.