Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wish list: get wavelength from beam line controls #26

Closed
prjemian opened this issue Sep 2, 2020 · 2 comments · Fixed by #41
Closed

wish list: get wavelength from beam line controls #26

prjemian opened this issue Sep 2, 2020 · 2 comments · Fixed by #41
Assignees
Labels

Comments

@prjemian
Copy link
Contributor

prjemian commented Sep 2, 2020

Other things we need to consider are:

  • ability to convert the RBV of beamline

Also, convert energy units appropriately (soft x-ray beamlines at NSLS-II use eV, not keV). In other words, rely on EPICS UNITS to decide how to convert.

If we continue to require a manual setting of the hklpy calculation energy, then these things are transparent. I am just anticipating something more sophisticated as I am not sure how much you want to change.

Originally posted by @ambarb in #17 (comment)

@prjemian prjemian changed the title wish list: wish list: get wavelength from beam line controls Sep 2, 2020
@prjemian
Copy link
Contributor Author

prjemian commented Oct 1, 2020

In #29 (comment), it was shown how to get photon energy from beam line controls. The same steps could be used to get wavelength instead.

Internally, the calc module stores only the wavelength (angstroms). It converts energy to wavelength when energy is set. Here's the code:

hklpy/hkl/calc.py

Lines 136 to 152 in 14463c4

@property
def wavelength(self):
'''The wavelength associated with the geometry, in angstrom'''
return self._geometry.wavelength_get(self._units)
@wavelength.setter
def wavelength(self, wavelength):
self._geometry.wavelength_set(wavelength, self._units)
@property
def energy(self):
'''The energy associated with the geometry, in keV'''
return A_KEV / self.wavelength
@energy.setter
def energy(self, energy):
self.wavelength = A_KEV / energy

example

This user operation sets the energy: fourc.calc.energy = 8.04 (the units are keV). The setter part sets the internal wavelength fourc.calc._wavelength by calculating A_KEV/energy. When the users asks for the current energy, it is recalculated from the internal wavelength (A_KEV/wavelength).

@prjemian prjemian self-assigned this Oct 1, 2020
@prjemian
Copy link
Contributor Author

prjemian commented Oct 1, 2020

It is recommended to get either the energy or wavelength from the beam line controls, but not both. This is always a local customization to the specific instrument so it is not appropriate to add into the code here. (This example could be part of the documentation, however.)

There is already code in place to use an energy ophyd.Signal (and a default Diffractometer._energy_changed() method) to set energy and wavelength in the calc attribute. Override the energy Signal with an ophyd.EpicsSignal and connect to the desired energy PV. An example is provided (from #29 (comment) & #29 (comment)). The example also shows unit conversion (using thepint package) and a Signal for energy offset (as requested in #25). (If the offset is an EPICS PV, then use EpicsSignal and the PV instead).

import gi
gi.require_version('Hkl', '5.0')
import hkl.diffract
from ophyd import Component, EpicsSignal, Signal
import pint

class LocalDiffractometer(hkl.diffract.Diffractometer):
    # ...
    energy = Component(EpicsSignal, "EPICS:diffractometer:energy")
    energy_EGU = Component(EpicsSignal, "EPICS:diffractometer:energy.EGU")
    energy_update_calc = Component(EpicsSignal, "EPICS:diffractometer:energy_update_hkl")
    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"):
            local_energy = value + self.energy_offset.get()
            units = self.energy_EGU.get()   # get units from EPICS
            # units = "eV"    # alternative: from control system always gives "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()

prjemian added a commit that referenced this issue Oct 1, 2020
prjemian added a commit that referenced this issue Oct 1, 2020
prjemian added a commit that referenced this issue Oct 1, 2020
prjemian added a commit that referenced this issue Oct 1, 2020
prjemian added a commit that referenced this issue Oct 2, 2020
prjemian added a commit that referenced this issue Oct 2, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant