bluesky / hklpy

Diffractometer computation library with ophyd pseudopositioner support
https://blueskyproject.io/hklpy
BSD 3-Clause "New" or "Revised" License
2 stars 11 forks source link

geometry mode updates which axes? #305

Closed prjemian closed 6 months ago

prjemian commented 7 months ago

What axes are calculated by Diffractometer.forward() for a given geometry mode?

The documentation names the modes available for each geometry. There are details which could be provided as useful guidance on selecting a mode (such as when deciding how to hold a certain axis constant). The details for each mode are in the libhkl source. Here are definitions of bissector and constant_omega modes for the E4C geometry:

static HklMode *bissector(void)
{
        static const char* axes[] = {OMEGA, CHI, PHI, TTH};
        static const HklFunction *functions[] = {&bissector_func};
        static const HklModeAutoInfo info = {
                HKL_MODE_AUTO_INFO(__func__, axes, axes, functions),
        };

        return hkl_mode_auto_new(&info,
                                 &hkl_full_mode_operations,
                                 TRUE);
}

static HklMode *constant_omega(void)
{
        static const char* axes_r[] = {OMEGA, CHI, PHI, TTH};
        static const char* axes_w[] = {CHI, PHI, TTH};
        static const HklFunction *functions[] = {&RUBh_minus_Q_func};
        static const HklModeAutoInfo info = {
                HKL_MODE_AUTO_INFO(__func__, axes_r, axes_w, functions),
        };

        return hkl_mode_auto_new(&info,
                                 &hkl_full_mode_operations,
                                 TRUE);
}

The list of axes to be updated by a mode are defined by either axes or axes_w (when the list differs from the readable axes). Add this list as an additional column to the table for each geometry.

prjemian commented 7 months ago

There are a couple keys calls available from the libhkl interface. They can be used to re-create the tables on that page of the documentation. Here's a fragment of the code that creates a goniometer instance from hkl.calc, setting the gonio for each mode, then gets the axes used for the forward computation (axes_r) and the axes that are computed (changed) by the forward computation (axes_w).

        gonio = getattr(calc, f"Calc{gname}")(engine=engine)
        for mode in sorted(modes):
            gonio.engine.mode = mode  #
            axes_r = format_name_list(gonio.engine._engine.axis_names_get(0))
            axes_w = format_name_list(gonio.engine._engine.axis_names_get(1))
prjemian commented 7 months ago

Here's an example of the (new) table for E6C:

Geometry: E6C
  real axes: mu, omega, chi, phi, gamma, delta
  pseudo axes: depends on the engine

========= ============================= ================== ================================= ========================== ================
engine    mode                          pseudo axes        axes read                         axes written               extra parameters
========= ============================= ================== ================================= ========================== ================
emergence emergence                     emergence, azimuth mu, omega, chi, phi, gamma, delta                            x, y, z         
hkl       bissector_horizontal          h, k, l            mu, omega, chi, phi, gamma, delta mu, omega, chi, phi, gamma                 
hkl       bissector_vertical            h, k, l            mu, omega, chi, phi, gamma, delta omega, chi, phi, delta                     
hkl       constant_chi_vertical         h, k, l            mu, omega, chi, phi, gamma, delta omega, phi, delta                          
hkl       constant_mu_horizontal        h, k, l            mu, omega, chi, phi, gamma, delta chi, phi, gamma                            
hkl       constant_omega_vertical       h, k, l            mu, omega, chi, phi, gamma, delta chi, phi, delta                            
hkl       constant_phi_vertical         h, k, l            mu, omega, chi, phi, gamma, delta omega, chi, delta                          
hkl       double_diffraction_horizontal h, k, l            mu, omega, chi, phi, gamma, delta mu, chi, phi, gamma        h2, k2, l2      
hkl       double_diffraction_vertical   h, k, l            mu, omega, chi, phi, gamma, delta omega, chi, phi, delta     h2, k2, l2      
hkl       lifting_detector_mu           h, k, l            mu, omega, chi, phi, gamma, delta mu, gamma, delta                           
hkl       lifting_detector_omega        h, k, l            mu, omega, chi, phi, gamma, delta omega, gamma, delta                        
hkl       lifting_detector_phi          h, k, l            mu, omega, chi, phi, gamma, delta phi, gamma, delta                          
hkl       psi_constant_horizontal       h, k, l            mu, omega, chi, phi, gamma, delta omega, chi, phi, gamma     h2, k2, l2, psi 
hkl       psi_constant_vertical         h, k, l            mu, omega, chi, phi, gamma, delta omega, chi, phi, delta     h2, k2, l2, psi 
incidence incidence                     incidence, azimuth mu, omega, chi, phi                                          x, y, z         
psi       psi_vertical                  psi                mu, omega, chi, phi, gamma, delta omega, chi, phi, delta     h2, k2, l2      
q2        q2                            q, alpha           gamma, delta                      gamma, delta                               
qper_qpar qper_qpar                     qper, qpar         gamma, delta                      gamma, delta               x, y, z         
tth2      tth2                          tth, alpha         gamma, delta                      gamma, delta                               
========= ============================= ================== ================================= ========================== ================

This would make a useful addition to the hkl.diffract.Diffractometer() class. To provide documentation at the command line for the current diffractometer.

prjemian commented 7 months ago

example:

In [1]: from hkl import SimulatedK4CV

In [2]: sim4k = SimulatedK4CV("", name="sim4k")

In [3]: sim4k.geometry_table()
Geometry: K4CV
  real axes: komega, kappa, kphi, tth
  pseudo axes: depends on the engine

========= ================== ================== ======================== ======================== ================
engine    pseudo axes        mode               axes read                axes written             extra parameters
========= ================== ================== ======================== ======================== ================
emergence emergence, azimuth emergence          komega, kappa, kphi, tth                          x, y, z         
eulerians omega, chi, phi    eulerians          komega, kappa, kphi      komega, kappa, kphi      solutions       
hkl       h, k, l            bissector          komega, kappa, kphi, tth komega, kappa, kphi, tth                 
hkl       h, k, l            constant_chi       komega, kappa, kphi, tth komega, kappa, kphi, tth chi             
hkl       h, k, l            constant_omega     komega, kappa, kphi, tth komega, kappa, kphi, tth omega           
hkl       h, k, l            constant_phi       komega, kappa, kphi, tth komega, kappa, kphi, tth phi             
hkl       h, k, l            double_diffraction komega, kappa, kphi, tth komega, kappa, kphi, tth h2, k2, l2      
hkl       h, k, l            psi_constant       komega, kappa, kphi, tth komega, kappa, kphi, tth h2, k2, l2, psi 
incidence incidence, azimuth incidence          komega, kappa, kphi                               x, y, z         
psi       psi                psi                komega, kappa, kphi, tth komega, kappa, kphi, tth h2, k2, l2      
q         q                  q                  tth                      tth                                      
========= ================== ================== ======================== ======================== ================