Diffcalc User and Developer Guide

Author:Rob Walton
Contact:rob.walton (at) diamond.ac.uk
Web site:https://github.com/DiamondLightSource/diffcalc

Diffcalc: A Diffraction Condition Calculator for Diffractometer Control

See also the quickstart guide at github.

Diffcalc User Guide (You Engine)

Diffcalc: A diffraction condition calculator for diffractometer control

Author:Rob Walton
Contact:rob.walton (at) diamond (dot) ac (dot) uk
Website:https://github.com/DiamondLightSource/diffcalc

See also the quickstart guide at github

Introduction

This manual assumes that you are running Diffcalc within OpenGDA or have started it using IPython. It assumes that Diffcalc has been configured for the six circle diffractometer pictured here:

_images/4s_2d_diffractometer.png

4s + 2d six-circle diffractometer, from H.You (1999)

Your Diffcalc configuration may have been customised for the geometry of your diffractometer and possibly the types of experiment you perform. For example, a five-circle diffractometer might be missing the nu circle above.

The laboratory frame is shown above. With all settings at zero as shown the crystal cartesian frame aligns with the laboratory frame. Therefore a cubic crystal mounted squarely in a way that the U matrix (defined below) is unitary will have h||a||x, k||b||y & l||c||z, crystal and reciprocal-lattice coordinate frames are defined with respect to the beam and to gravity to be (for a cubic crystal):

Overview

The following assumes that the diffractometer has been properly levelled, aligned with the beam and zeroed. See the SPEC fourc manual.

Before moving in hkl space you must calculate a UB matrix by specifying the crystal’s lattice parameters (which define the B matrix) and finding two reflections (from which the U matrix defining any mismount can be inferred); and, optionally for surface-diffraction experiments, determine how the surface of the crystal is oriented with respect to the phi axis.

Once a UB matrix has been calculated, the diffractometer may be driven in hkl coordinates. A valid diffractometer setting maps easily into a single hkl value. However for a diffractometer with more than three circles there are excess degrees of freedom when calculating a diffractometer setting from an hkl value. Diffcalc provides modes for using up the excess degrees of freedom.

Diffcalc does not perform scans directly. Instead, Scannables that use diffcalc to map between reciprocal lattice space and real diffractometer settings are scanned using the Gda’s (or minigda’s) generic scan mechanism.

Theory

Thanks to Elias Vlieg for sharing his DOS based DIF software that Diffcalc has borrowed heavily from. The version of Diffcalc described here is based on papers by pHH. You. [You1999] and Busing & Levy [Busing1967]. (See also the THANKS.txt file.)

Getting Help

There are few commands to remember. If a command is called without arguments in some cases Diffcalc will prompt for arguments and provide sensible defaults which can be chosen by pressing enter.

Orientation. The helpub command lists all commands related with crystal orientation and the reference vector (often used with surfaces). See the Orientation Commands section at the end of this manual:

>>> help ub
...

HKL movement. The help hkl list all commands related to moving in reciprocal-lattice space. See the Motion Commands section at the end of this manual:

>>> help hkl
...

Call help on any command. e.g.:

>>> help loadub
loadub (diffcalc command):
loadub 'name' | num -- load an existing ub calculation

Diffcalc’s Scannables

To list and show the current positions of your beamline’s scannables use pos with no arguments:

>>> pos

Results in:

Energy and wavelength scannables:

energy    12.3984
wl:       1.0000

Diffractometer scannables, as a group and in component axes (in the real GDA these have limits):

sixc:     mu: 0.0000 delta: 0.0000 gamma: 0.0000 omega: 0.0000 chi: 0.0000 phi: 0.0000
mu:       0.0000
chi:      0.0000
delta:    0.0000
gamma:    0.0000
omega:    0.0000
phi:      0.0000

Dummy counter, which in this example simply counts at 1hit/s:

ct:      0.0000

Hkl scannable, as a group and in component:

hkl:      Error: No UB matrix
h:        Error: No UB matrix
k:        Error: No UB matrix
l:        Error: No UB matrix

Parameter scannables, used in some modes, these provide a scannable alternative to the Motion section. Some constrain of these constrain virtual angles:

alpha:    ---
beta:     ---
naz:      ---
psi:      ---
qaz:      ---

and some constrain physical angles:

phi_con:  ---
chi_con:  ---
delta_con:---
eta_con:  ---
gam_con:  ---
mu_con:   ---

Crystal orientation

Before moving in hkl space you must calculate a UB matrix by specifying the crystal’s lattice parameters (which define the B matrix) and finding two reflections (from which the U matrix can be inferred); and, optionally for surface-diffraction experiments, determine how the surface of the crystal is oriented with respect to the phi axis.

Start a new UB calculation

A UB calculation contains the description of the crystal-under-test, any saved reflections, reference angle direction, and a B & UB matrix pair if they have been calculated or manually specified. Starting a new UB calculation will clear all of these.

Before starting a UB-calculation, the ub command used to summarise the state of the current UB-calculation, will reflect that no UB-calculation has been started:

>>> ub
<<< No UB calculation started >>>

A new UB-calculation calculation may be started and lattice specified explicitly:

>>> newub 'example'
>>> setlat '1Acube' 1 1 1 90 90 90

or interactively:

>>> newub
calculation name: example
crystal name: 1Acube
crystal system
1) Triclinic
2) Monoclinic
3) Orthorhombic
4) Tetragonal
5) Rhombohedral
6) Hexagonal
7) Cubic
[1]: 7
    a[1]: 1

where a is unit cell basis vector in Angstroms for cubic crystal system.

The ub command will show the state of the current UB-calculation (and the current energy for reference):

>>> ub
UBCALC

   name:       example

REFERNCE

   n_hkl:      1.00000   0.00000   0.00000 <- set

SURFACE NORMAL

   n_phi:      0.00000   0.00000   1.00000 <- set

CRYSTAL

   name:        1Acube

   a, b, c:    1.00000   1.00000   1.00000
              90.00000  90.00000  90.00000  Cubic

   B matrix:   6.28319   0.00000   0.00000
               0.00000   6.28319   0.00000
               0.00000   0.00000   6.28319

UB MATRIX

   <<< none calculated >>>

REFLECTIONS

   <<< none specified >>>

CRYSTAL ORIENTATIONS

   <<< none specified >>>

Load a UB calculation

To load the last used UB-calculation:

>>> lastub
Loading ub calculation: 'mono-Si'

To load a previous UB-calculation:

>>> listub
UB calculations in: /Users/walton/.diffcalc/i16

0) mono-Si            15 Feb 2017 (22:32)
1) i16-32             13 Feb 2017 (18:32)

>>> loadub 0

Generate a U matrix from two reflections

The normal way to calculate a U matrix is to find the position of two reflections with known hkl values. Diffcalc allows many reflections to be recorded. After adding first two reflections UB matrix will be calculated automatically. If there are multiple recorded reflections, the indices or tags can be provided to calcub command as arguments to calculate UB matrix from any two given reflections.

Find U matrix from two reflections:

>>> pos wl 1
wl:        1.0000
>>> c2th [0 0 1]
59.99999999999999

>>> pos sixc [0 60 0 30 90 0]
sixc:     mu:  0.0000 delta:  60.0000 gam:  0.0000 eta:  30.0000 chi:  90.0000 phi:  0.0000
>>> addref [0 0 1]

>>> pos sixc [0 90 0 45 45 90]
sixc:     mu:  0.0000 delta:  90.0000 gam:  0.0000 eta:  45.0000 chi:  45.0000 phi:  90.0000
>>> addref [0 1 1]
Calculating UB matrix.

Check that it looks good:

>>> checkub

     ENERGY     H     K     L    H_COMP   K_COMP   L_COMP     TAG
 1  12.3984  0.00  0.00  1.00    0.0000   0.0000   1.0000
 2  12.3984  0.00  1.00  1.00    0.0000   1.0000   1.0000

After adding another reflection we can use the first and the third reflections to recalculate UB matrix:

>>> addref [1 0 1]

>>> calcub 1 3

>>> checkub

     ENERGY     H     K     L    H_COMP   K_COMP   L_COMP     TAG
 1  12.3984  0.00  0.00  1.00    0.0000   0.0000   1.0000
 2  12.3984  0.00  1.00  1.00    0.0000   1.0000   1.0000
 3  12.3984  1.00  0.00  1.00    1.0000   0.0000   1.0000

Generate a U matrix from one reflection

To estimate based on first reflection only:

>>> trialub
resulting U angle: 0.00000 deg
resulting U axis direction: [-1.00000,  0.00000,  0.00000]
Recalculating UB matrix from the first reflection only.
NOTE: A new UB matrix will not be automatically calculated when the orientation reflections are modified.

Edit reflection list

Use showref to show the reflection list:

>>> showref
     ENERGY     H     K     L        MU    DELTA      GAM      ETA      CHI      PHI  TAG
   1 12.398  0.00  0.00  1.00    0.0000  60.0000   0.0000  30.0000  90.0000   0.0000
   2 12.398  0.00  1.00  1.00    0.0000  90.0000   0.0000  45.0000  45.0000  90.0000

Use swapref to swap reflections:

>>> swapref 1 2
Not calculating UB matrix as it has been manually set. Use 'calcub' to explicitly recalculate it.
Recalculating UB matrix.

Use delref to delete a reflection:

>>> delref 1

Generate a U matrix from two lattice directions

Another approach to calculate a U matrix is to provide orientation of two crystal lattice directions using addorient command after aligning sample in laboratory frame of reference. The first lattice direction should be aligned along the selected direction in the laboratory frame. For the purpose of finding azimuthal orientation in U matrix calculation it is sufficient for the projection of the second lattice direction to be aligned to the given orientation in the laboratory frame in the plane perpendicular to the first lattice orientation.

Find U matrix from two lattice directions:

>>> addorient [0 0 1] [0 0 1]

>>> addorient [1 0 0] [1 1 0]
Calculating UB matrix.

Calculate a UB matrix

Unless a U or UB matrix has been manually specified, a new UB matrix will be calculated after the second reflection has been found, or whenever one of the first two reflections is changed.

Use the command calcub to force the UB matrix to be calculated from the first two reflections. In case of using lattice orientations instead of reflections, use command orientub to force the UB matrix to be calculated from the first two orientations.

UB matrix can be calculated from any combination of two reflections and/or orientations by providing corresponding reflection/orientation tags or numbers as an argument to calcub. In case of using one reflection and one orientation it is recommended to use tags to avoid ambiguity.

If you have misidentified a reflection used for the orientation the resulting UB matrix will be incorrect. Always use the checkub command to check that the computed reflection indices agree with the estimated values:

>>> checkub

     ENERGY     H     K     L    H_COMP   K_COMP   L_COMP     TAG
 1  12.3984  0.00  1.00  1.00    0.0000   1.0000   1.0000
 2  12.3984  0.00  0.00  1.00    0.0000   0.0000   1.0000

Calculate a U matrix from crystal mismount

U matrix can be defined from crystal mismount by using a rotation matrix calculated from a provided mismount angle and axis. setmiscut command defines new U matrix by setting it to a rotation matrix calculated from the specified angle and axis parameters. addmiscut command applies the calculated rotation matrix to the existing U matrix, i.e. adds extra mismount to the already existing one:

>>> setmiscut 5 [1 0 0]
n_phi: -0.00000  -0.08716   0.99619
n_hkl:  0.00000   0.00000   1.00000 <- set
normal:
   angle:  5.00000
   axis:  1.00000  -0.00000   0.00000

Manually specify U matrix

Set U matrix manually (pretending sample is squarely mounted):

>>> setu [[1 0 0] [0 1 0] [0 0 1]]
Recalculating UB matrix.
NOTE: A new UB matrix will not be automatically calculated when the orientation reflections are modified.

Refining UB matrix with one reflection

UB matrix elements can be refined to match diffractometer settings and crystal orientation experimentally found for a given reflection with the corresponding reflection indices. refineub command rescales crystal unit cell dimensions to match with the found scattering angle value and recalculates mismount parameters to update U matrix:

>>> refineub [1 0 0]
current pos[y]: y
Unit cell scaling factor:  0.99699
Refined crystal lattice:
   a, b, c:  0.99699   0.99699   0.99699
             90.00000  90.00000  90.00000

Update crystal settings?[y]: y
Warning: the old UB calculation has been cleared.
         Use 'calcub' to recalculate with old reflections or
         'orientub' to recalculate with old orientations.
Miscut parameters:
      angle:  2.90000
       axis: -0.00000   1.00000  -0.00000
Apply miscut parameters?[y]: y
   n_phi:  0.67043  -0.00000   0.74198
   n_hkl:  0.00000   0.00000   1.00000 <- set
   normal:
      angle: 42.10000
      axis:  0.00000   1.00000   0.00000

Calculate UB matrix from multiple reflections

Using fitub command UB matrix can be optimised to find best fit for the selected list of reference reflections . For triclinic crystal system optimal solution is found by solving multivariate linear regression model, while for the higher symmetry systems it is found by running numerical optimiser:

>>> fitub 1 2 3 4
Fitting crystal lattice parameters...
Fitting orientation matrix...
Refined crystal lattice:
   a, b, c: 10.56348  10.56348  10.81364
             90.00000  90.00000  90.00000
Update crystal settings?[y]: y
Refined U matrix:  0.94559  -0.32489   0.01762
                   0.32487   0.94575   0.00437
                  -0.01809   0.00160   0.99984
Update U matrix?[y]: y
...
...
...
REFLECTIONS

  ENERGY     H     K     L       PHI      CHI      ETA       MU    DELTA      GAM  TAG
1  8.000  0.00  0.00  8.00  -26.3000  89.0000  17.3034   0.0005  33.3569  -0.0042  None
2  8.000  4.00  4.00  8.00   62.4273  53.4451  45.2680   0.0000  90.0825   0.0000  None
3  8.000  0.00  0.00  8.00   13.3485  89.0097  35.0408   0.0000  69.9326   0.0000  None
4  8.000  4.00  4.00  8.00   63.2008  53.4096  44.9007   0.0000  90.1107   0.0000  None

Set the reference vector

The reference vector can be used to define azimuthal direction within the crystal with which we want to orient the incident or diffracted beam. Orientation of the reference vector w.r.t the incident and diffracted beam is indicated using alpha and beta angles.

By default the reference vector is set parallel to the theta axis. That is, along the x-axis of the laboratory coordinate frame.

The ub command shows the current reference vector at the top its report (or it can be shown by calling setnphi or setnhkl with no args):

>>> ub
...
   REFERNCE

   n_phi:      1.00000   0.00000   0.00000
   n_hkl:      1.00000   0.00000   0.00000 <- set
...

The <- set label here indicates that the reference vector is set in the reciprocal lattice space. In this case, therefore, its direction in the laboratory coordinate frame is inferred from the UB matrix.

To set the reference vector in the phi coordinate frame use:

>>> setnphi [1 0 0]
...

To set the reference vector in the crystal’s reciprocal lattice space use:

>>> setnhkl [1 0 0]
...

Set the surface normal vector

The orientation of the sample surface can be set using the surface normal vector defined either in laboratory coordinate system or reciprocal space. Orientation of the surface normal vector w.r.t the incident and diffracted beam is indicated using betain and betaout angles.

By default the surface normal vector is set parallel to the phi axis. That is, along the z-axis of the laboratory coordinate frame.

The ub command shows the current surface normal vector at the top its report (or it can be shown by calling surfnphi or surfnhkl with no args):

>>> ub
...
   SURFACE NORMAL

   n_phi:      0.00000   0.00000   1.00000 <- set
   n_hkl:      0.00000   0.00000   1.00000
...

The <- set label here indicates that the surface normal vector is set in the laboratory coordinate frame. In this case, therefore, its direction in the crystal’s reciprocal lattice space is inferred from the UB matrix.

To set the surface normal vector in the phi coordinate frame use:

>>> surfnphi [0 0 1]
...

To set the surface normal vector in the crystal’s reciprocal lattice space use:

>>> surfnhkl [0 0 1]
...

Motion

Once a UB matrix has been calculated, the diffractometer may be driven in hkl coordinates. A given diffractometer setting maps easily into a single hkl value. However for a diffractometer with more than three circles there are excess degrees of freedom when calculating a diffractometer setting from an hkl value. Diffcalc provides many for using up the excess degrees of freedom.

By default Diffcalc selects no mode.

Constraining solutions for moving in hkl space

To get help and see current constraints:

>>> help con
...

>>> con
   DET             REF             SAMP
   -----------     -----------     -----------
   delta           a_eq_b          mu
   gam             alpha           eta
   qaz             beta            chi
   naz             psi             phi
                   bin_eq_bout     mu_is_gam
                   betain          bisect
                   betaout         omega

   !   3 more constraints required

       Type 'help con' for instructions

Three constraints can be given: zero or one from the DET and REF columns and the remainder from the SAMP column. Not all combinations are currently available. Use help con to see a summary if you run into troubles.

To configure four-circle vertical scattering:

>>> con gam 0 mu 0 a_eq_b
    gam  : 0.0000
    a_eq_b
    mu   : 0.0000

In the following the scattering plane is defined as the plane including the scattering vector, or momentum transfer vector, and the incident beam.

DETECTOR COLUMN:

  • delta - physical delta setting (vertical detector motion) del=0 is equivalent to qaz=0
  • gam - physical gamma setting (horizontal detector motion) gam=0 is equivalent to qaz=90
  • qaz - azimuthal rotation of scattering vector (about the beam, from horizontal)
  • naz - azimuthal rotation of reference vector (about the beam, from horizontal)

REFERENCE COLUMN:

  • alpha - incident angle to reference vector
  • beta - exit angle from reference vector
  • psi - azimuthal rotation about scattering vector of reference vector (from scattering plane)
  • a_eq_b - bisecting mode with alpha=beta. Equivalent to psi=90
  • betain - incident angle to sample surface
  • betaout - exit angle from sample surface
  • bin_eq_bout - bisecting mode with betain=betaout

SAMPLE COLUMN:

  • mu, eta, chi & phi - physical settings
  • mu_is_gam - force mu to follow gamma (results in a 5-circle geometry)
  • bisect - bisecting mode with scattering vector in chi-circle plane
  • omega - bisecting mode with omega angle between scattering vector and chi-circle plane

Diffcalc will report two other (un-constrainable) virtual angles:

  • theta - half of 2theta, the angle through the diffracted beam bends
  • tau - longitude of reference vector from scattering vector (in scattering plane)

Example constraint modes

There is sometimes more than one way to get the same effect.

Vertical four-circle mode:

>>> con gam 0 mu 0 a_eq_b   # or equivalently:
>>> con qaz 90 mu 0 a_eq_b

>>> con alpha 1             # replaces a_eq_b

Horizontal four-circle mode:

>>> con del 0 eta 0 alpha 1   # or equivalently:
>>> con qaz 0 mu 0 alpha 1

Surface vertical mode:

>>> con naz 90 mu 0 betain 1

Surface horizontal mode:

>>> con naz 0 eta 0 betain 1

Z-axis mode (surface horizontal):

>>> con chi (-sigma) phi (-tau) betain 1

where sigma and tau are the offsets required in chi and phi to bring the surface normal parallel to eta. betain will determine mu directly leaving eta to orient the planes. Or:

>>> con naz 0 phi 0 betain 1  # or any another sample angle

Z-axis mode (surface vertical):

>>> con naz 0 phi 0 betain 1  # or any another sample angle

Changing constrained values

Once constraints are chosen constrained values may be changed directly:

>>> con mu 10
    gam  : 0.0000
    a_eq_b
    mu   : 10.0000

or via the associated scannable:

>>> pos mu_con 10
mu_con:   10.00000

Configuring limits and cuts

Diffcalc uses motor limits set in GDA when used from GDA client running on a beamline. The standalone console version maintains its own limits on axes. These limits will be used when choosing solutions. If more than one detector solution exists Diffcalc will ask you to reduce the the limits until there is only one. However if more than one solution for the sample settings is available it will choose one that is closest to the current diffractometer orientation.

Use the hardware command to see the current limits and cuts:

>>> hardware
               mu           (cut: -180.0)
            delta           (cut: -180.0)
              gam           (cut: -180.0)
              eta           (cut: -180.0)
              chi           (cut: -180.0)
              phi           (cut:    0.0)
Note: When auto sector/transforms are used,
       cuts are applied before checking limits.

To set the limits in standalone Diffcalc session:

>>> setmin delta -1
>>> setmax delta 145

To set a cut:

>>> setcut phi -180

This causes requests to move phi to be between the configured -180 and +360 degress above this. i.e. it might dive to -10 degrees rather than 350.

Moving in hkl space

Configure a mode, e.g. four-circle vertical:

>>> con gam 0 mu 0 a_eq_b
    gam  : 0.0000
    a_eq_b
    mu   : 0.0000

Simulate moving to a reflection:

>>> sim hkl [0 1 1]
sixc would move to:
     mu :    0.0000
  delta :   90.0000
    gam :    0.0000
    eta :   45.0000
    chi :   45.0000
    phi :   90.0000

  alpha :   45.0000
   beta :   45.0000
 betain :   30.0000
betaout :   30.0000
    naz :   35.2644
    psi :   90.0000
    qaz :   90.0000
    tau :   45.0000
  theta :   45.0000
 ttheta :   90.0000

Move to reflection:

>>> pos hkl [0 1 1]
hkl:      h: 0.00000 k: 1.00000 l: 1.00000

>>> pos sixc
sixc:     mu:  0.0000 delta:  90.0000 gam:  0.0000 eta:  45.0000 chi:  45.0000 phi:  90.0000

Simulate moving to a location:

>>> pos sixc [0 60 0 30 90 0]
sixc:     mu:  0.0000 delta:  60.0000 gam:  0.0000 eta:  30.0000 chi:  90.0000 phi:  0.0000

Scanning in hkl space

All scans described below use the same generic scanning mechanism provided by the GDA system or by minigda. Here are some examples.

Fixed hkl scans

In a ‘fixed hkl scan’ something (such as energy or Bin) is scanned, and at each step hkl is ‘moved’ to keep the sample and detector aligned. Also plonk the diffractometer scannable (sixc) on there with no destination to monitor what is actually happening and then throw on a detector (ct) with an exposure time if appropriate:

>>> #scan scannable_name start stop step [scannable_name [pos or time]]..

>>> scan en 9 11 .5 hkl [1 0 0] sixc ct 1

>>> scan en 9 11 .5 hklverbose [1 0 0] sixc ct 1

>>> scan betain 4 5 .2 hkl [1 0 0] sixc ct 1

>>> scan alpha_par 0 10 2 hkl [1 0 0] sixc ct 1

Scanning hkl

Hkl, or one component, may also be scanned directly:

>>> scan h .8 1.2 .1 hklverbose sixc ct 1

At each step, this will read the current hkl position, modify the h component and then move to the resulting vector. There is a danger that with this method k and l may drift. To get around this the start, stop and step values may also be specified as vectors. So for example:

>>> scan hkl [1 0 0] [1 .3 0] [1 0.1 0] ct1

is equivilant to:

>>> pos hkl [1 0 0]
>>> scan k 0 .3 .1 ct1

but will not suffer from drifting. This method also allows scans along any direction in hkl space to be performed.

Multidimension scans

Two and three dimensional scans:

>>> scan en 9 11 .5 h .9 1.1 .2 hklverbose sixc ct 1
>>> scan h 1 3 1 k 1 3 1 l 1 3 1 hkl ct 1

Commands

Orientation Commands

STATE
– newub {‘name’} start a new ub calculation name
– loadub ‘name’ | num load an existing ub calculation
– lastub load the last used ub calculation
– listub list the ub calculations available to load
– rmub ‘name’ | num remove existing ub calculation
– saveubas ‘name’ save the ub calculation with a new name
LATTICE
– setlat interactively enter lattice parameters (Angstroms and Deg)
– setlat name a assumes cubic
– setlat name a b assumes tetragonal
– setlat name a b c assumes ortho
– setlat name a b c gamma assumes mon/hex with gam not equal to 90
– setlat name a b c alpha beta gamma arbitrary
– c2th [h k l] calculate two-theta angle for reflection
– hklangle [h1 k1 l1] [h2 k2 l2] calculate angle between [h1 k1 l1] and [h2 k2 l2] crystal planes
REFERENCE
– setnphi {[x y z]} sets or displays n_phi reference
– setnhkl {[h k l]} sets or displays n_hkl reference
SURFACE NORMAL
– surfnphi {[x y z]} sets or displays surface normal vector in lab space
– surfnhkl {[h k l]} sets or displays surface normal vector in reciprocal space
REFLECTIONS
– showref shows full reflection list
– addref add reflection interactively
– addref [h k l] {‘tag’} add reflection with current position and energy
– addref [h k l] (p1, .., pN) energy {‘tag’} add arbitrary reflection
– editref num interactively edit a reflection
– delref num deletes a reflection (numbered from 1)
– clearref deletes all the reflections
– swapref swaps first two reflections used for calculating U matrix
– swapref num1 num2 swaps two reflections (numbered from 1)
CRYSTAL ORIENTATIONS
– showorient shows full list of crystal orientations
– addorient add crystal orientation interactively
– addorient [h k l] [x y z] {‘tag’} add crystal orientation in laboratory frame
– editorient num interactively edit a crystal orientation
– delorient num deletes a crystal orientation (numbered from 1)
– clearorient deletes all the crystal orientations
– swaporient swaps first two crystal orientations used for calculating U matrix
– swaporient num1 num2 swaps two crystal orientations (numbered from 1)
UB MATRIX
– fitub ref1 ref2 ref3 .. fit UB matrix to match list of provided reference reflections
– checkub show calculated and entered hkl values for reflections
– setu {[[..][..][..]]} manually set u matrix
– setub {[[..][..][..]]} manually set ub matrix
– calcub (re)calculate u matrix from ref1 and ref2
– calcub idx1 idx2 (re)calculate U matrix from reflections and/or orientations referred by indices and/or tags idx1 and idx2
– orientub (re)calculate U matrix from reflections and/or orientations
– orientub idx1 idx2 (re)calculate U matrix from the first two orientations referred by indices and/or tags idx1 and idx2
– trialub (re)calculate U matrix from the first reflection (check carefully)
– trialub idx1 (re)calculate U matrix from reflection with index or tag idx only (check carefully)
– refineub {[h k l]} {pos} refine unit cell dimensions and U matrix to match diffractometer angles for a given hkl value
– addmiscut angle {[x y z]} apply miscut to U matrix using a specified miscut angle in degrees and a rotation axis (default: [0 1 0])
– setmiscut angle {[x y z]} manually set U matrix using a specified miscut angle in degrees and a rotation axis (default: [0 1 0])

Motion commands

CONSTRAINTS
– con list available constraints and values
– con <name> {val} constrains and optionally sets one constraint
– con <name> {val} <name> {val} <name> {val} clears and then fully constrains
– uncon <name> remove constraint
HKL
– allhkl [h k l] print all hkl solutions ignoring limits
HARDWARE
– hardware show diffcalc limits and cuts
– setcut {name {val}} sets cut angle
– setmin {axis {val}} set lower limits used by auto sector code (None to clear)
– setmax {name {val}} sets upper limits used by auto sector code (None to clear)
MOTION
– sim hkl scn simulates moving scannable (not all)
– sixc show Eularian position
– pos sixc [mu, delta, gam, eta, chi, phi] move to Eularian position(None holds an axis still)
– sim sixc [mu, delta, gam, eta, chi, phi] simulate move to Eulerian positionsixc
– hkl show hkl position
– pos hkl [h k l] move to hkl position
– pos {h | k | l} val move h, k or l to val
– sim hkl [h k l] simulate move to hkl position

Good luck — RobW

References

[You1999]H. You. Angle calculations for a ‘4S+2D’ six-circle diffractometer. J. Appl. Cryst. (1999). 32, 614-623. (pdf link).
[Busing1967]W. R. Busing and H. A. Levy. Angle calculations for 3- and 4-circle X-ray and neutron diffractometers. Acta Cryst. (1967). 22, 457-464. (pdf link).

Diffcalc User Guide (Deprecated Vlieg Engine)

Author:Rob Walton
Contact:rob.walton (at) diamond (dot) ac (dot) uk
Website:http://www.opengda.org/

Diffcalc: A diffraction condition calculator for diffractometer control

Introduction

Warning

This manual refers to the ‘Vlieg’ calculation available in Diffcalc I. By default Diffcalc II now uses its ‘You’ engine. This manual will be updated soon. For now the developer guide shows how the new constraint system works.

This manual assumes that you are running Diffcalc within the external framework of the GDA or Minigda and that Diffcalc has been configured for the six circle diffractometer pictured here:

_images/sixcircle_gamma_on_arm.png

Gamma-on-delta six-circle diffractometer, modified from Elias Vlieg & Martin Lohmeier (1993)

Your Diffcalc configuration will have been customised for the geometry of your diffractometer and possibly the types of experiment you perform. For example: a five-circle diffractometer might be missing the Gamma circle above, some six-circle modes and the option to fix gamma that would otherwise exist in some modes.

The laboratory, crystal and reciprocal-lattice coordinate frames are defined with respect to the beam and to gravity to be (for a cubic crystal):

_images/fix.png

Laboratory and illustratrive crystal coordinate frames for a cubic crystal

The crystal lattice basis vectors are defined within the Cartesian crystal coordinate frame to be:

_images/unit_cell.png

Unit cell defined in crystal coordinate frame

Overview

The following assumes that the diffractometer has been properly levelled, aligned with the beam and zeroed. See the SPEC fourc manual.

Before moving in hkl space you must calculate a UB matrix by specifying the crystal’s lattice parameters (which define the B matrix) and finding two reflections (from which the U matrix can be inferred); and, optionally for surface-diffraction experiments, determine how the surface of the crystal is oriented with respect to the phi axis.

Once a UB matrix has been calculated, the diffractometer may be driven in hkl coordinates. A valid diffractometer setting maps easily into a single hkl value. However for a diffractometer with more than three circles there are excess degrees of freedom when calculating a diffractometer setting from an hkl value. Diffcalc provides modes for using up the excess degrees of freedom.

Diffcalc does not perform scans directly. Instead, scannables that use diffcalc to map between reciprocal lattice space and real diffractometer settings are scanned using the Gda’s (or minigda’s) generic scan mechanism.

Theory

Thanks to Elias Vlieg for sharing his dos based DIF software that Diffcalc has borrowed heavily from. (See also the THANKS.txt file).

See the papers (included in docs/ref):

  • Busing & Levi (1966), “Angle Calculations for 3- and 4- Circle X-ray and Neutron Diffractometers”, Acta Cryst. 22, 457
  • Elias Vlieg & Martin Lohmeier (1993), “Angle Calculations for a Six-Circle Surface X-ray Diffractometer”, J. Appl. Cryst. 26, 706-716

Getting Help

There are few commands to remember. If a command is called without arguments, Diffcalc will prompt for arguments and provide sensible defaults which can be chosen by pressing enter.

The helpub and helphkl commands provide help with the crystal orientation and hkl movement phases of an experiment respectively:

>>> helpub

      Diffcalc
      --------
        helpub  ['command']        - lists all ub commands, or one if command is given
       helphkl  ['command']        - lists all hkl commands, or one if command is given

      UB State
      --------
         newub  'name'             - starts a new ub calculation with no lattice or
                                     reflection list
        loadub  'name'             - loads an existing ub calculation: lattice and
                                     reflection list
      saveubas  'name'             - saves the ubcalculation with a new name (other
                                     changes autosaved)
            ub                     - shows the complete state of the ub calculation

    UB lattice
    ----------
        setlat                     - prompts user to enter lattice parameters (in
                                     Angstroms and Deg.)
        setlat  'name' a           - assumes cubic
        setlat  'name' a b         - assumes tetragonal
        setlat  'name' a b c       - assumes ortho
        setlat  'name' a b c gam   - assumes mon/hex with gam not equal to 90
        setlat  'name' a b c alpha beta gamma  - arbitrary

    UB surface
    ----------
        sigtau  [sigma tau]        - sets sigma and tau

UB reflections
--------------
       showref                     - shows full reflection list
        addref                     - add reflection
        addref  h k l ['tag']      - add reflection with hardware position and energy
        addref  h k l (p1,p2...pN) energy ['tag']- add reflection with specified position
                                                   and energy
        delref  num                - deletes a reflection (numbered from 1)
       swapref                     - swaps first two reflections used for calculating U
       swapref  num1 num2          - swaps two reflections (numbered from 1)

UB calculation
--------------
          setu  [((,,),(,,),(,,))] - manually set u matrix
         setub  ((,,),(,,),(,,))   - manually set ub matrix
        calcub                     - (re)calculate u matrix from ref1 and ref2
       checkub                     - show calculated and entered hkl values for reflections

>>> helphkl

      Diffcalc
      --------
       helphkl  [command]          - lists all hkl commands, or one if command is given
        helpub  [command]          - lists all ub commands, or one if command is given

      Settings
      --------
       hklmode  [num]              - changes mode or shows current and available modes
                                     and all settings
      setalpha  [num]              - fixes alpha, or shows all settings if no num given
      setgamma  [num]              - fixes gamma, or shows all settings if no num given
     setbetain  [num]              - fixes betain, or shows all settings if no num given
    setbetaout  [num]              - fixes betaout, or shows all settings if no num given
    trackalpha  [boolean]          - determines wether alpha parameter will track alpha axis
    trackgamma  [boolean]          - determines wether gamma parameter will track gamma axis
      trackphi  [boolean]          - determines wether phi parameter will track phi axis
  setsectorlim  [omega_high omega_low phi_high phi_low]- sets sector limits

        Motion
        ------
           pos   hkl [h k l]       - move diffractometer to hkl, or read hkl position.
                                     Use None to hold a value still
           sim  hkl [h k l]        - simulates moving hkl
           hkl                     - shows loads of info about current hkl position
           pos  sixc [alpha, delta, gamma, omega, chi, phi,]- move diffractometer to Eularian
                                                              position. Use None to hold a
                                                              value still
           sim  sixc [alpha, delta, gamma, omega, chi, phi,]- simulates moving sixc
          sixc                     - shows loads of info about current sixc position

Diffcalc’s Scannables

Please see Moving in hkl space and Scanning in hkl space for some relevant examples.

To list and show the current positions of your beamline’s scannables use pos with no arguments:

>>> pos

Results in:

Energy and wavelength scannables:

energy    12.3984
wl:       1.0000

Diffractometer scannables, as a group and in component axes (in the real GDA these have limits):

sixc:     alpha: 0.0000 delta: 0.0000 gamma: 0.0000 omega: 0.0000 chi: 0.0000 phi: 0.0000
alpha:    0.0000
chi:      0.0000
delta:    0.0000
gamma:    0.0000
omega:    0.0000
phi:      0.0000

Dummy counter, which in this example simply counts at 1hit/s:

cnt:      0.0000

Hkl scannable, as a group and in component:

hkl:      Error: No UB matrix
h:        Error: No UB matrix
k:        Error: No UB matrix
l:        Error: No UB matrix

Parameter scannables, used in some modes, these provide a scannable alternative to the series of fix commands described in Moving in hkl space.:

   alpha_par:0.00000
   azimuth:  ---
   betain:   ---
   betaout:  ---
   gamma_par:0.00000
   phi_par:  ---

Note that where a parameter corresponds with a physical
diffractometer axis, it can also be set to track that axis
directly. See `Tracking axis`_ below.

Crystal orientation

Before moving in hkl space you must calculate a UB matrix by specifying the crystal’s lattice parameters (which define the B matrix) and finding two reflections (from which the U matrix can be inferred); and, optionally for surface-diffraction experiments, determine how the surface of the crystal is oriented with respect to the phi axis (see Overview).

Starting a UB calculation

A UB-calculation contains the description of the crystal-under-test, any saved reflections, sigma & tau (both default to 0), and a B & UB matrix pair if they have been calculated or manually specified. Starting a new UB calculation will clear all of these.

Before starting a UB-calculation, the ub command used to summarise the state of the current UB-calculation, will reflect that no UB-calculation has been started:

>>> ub
No UB calculation started.
Wavelength: 1.239842
    Energy: 10.000000

A new UB-calculation calculation may be started and lattice specified explicitly:

>>> newub 'b16_270608'
>>> setlat 'xtal' 3.8401 3.8401 5.43072 90 90 90

or interactively:

>>> newub
calculation name: b16_270608
crystal name: xtal
       a [1]: 3.8401
  b [3.8401]: 3.8401
  c [3.8401]: 5.43072
  alpha [90]: 90
   beta [90]: 90
  gamma [90]: 90

where a,b and c are the lengths of the three unit cell basis vectors in Angstroms, and alpha, beta and gamma the typically used angles (defined in the figure above) in Degrees.

The ub command will show the state of the current UB-calculation (and the current energy for reference):

UBCalc:     b16_270608
======

Crystal
-------
name:          xtal

lattice:                   a ,b ,c  =  3.84010,  3.84010,  5.43072
               alpha, beta , gamma  = 90.00000, 90.00000, 90.00000

reciprocal:             b1, b2, b3  =  1.63620,  1.63620,  1.15697
               beta1, beta2, beta3  =  1.57080,  1.57080,  1.57080

B matrix:      1.6362035642769  -0.0000000000000   -0.000000000000
               0.0000000000000   1.6362035642769   -0.000000000000
               0.0000000000000   0.0000000000000    1.156970955450

Reflections
-----------
energy h    k    l     alpha    delta    gamma    omega    chi      phi       tag

UB matrix
---------
none calculated

Sigma: 0.000000
Tau:   0.000000
Wavelength: 1.000000
Energy:    12.398420

Specifying Sigma and Tau for surface diffraction experiments

Sigma and Tau are used in modes that fix either the beam exit or entry angle with respect to the crystal surface, or that keep the surface normal in the horizontal laboratory plane. For non surface-diffraction experiments these can safely be left at zero.

For surface diffraction experiments, where not only the crystal’s lattice planes must be oriented appropriately but so must the crystal’s optical surface, two angles _Tau_ and _Sigma_ define the orientation of the surface with respect to the phi axis. Sigma is (minus) the amount of chi axis rotation and Tau (minus) the amount of phi axis rotation needed to move the surface normal parallel to the omega circle axis. These angles are often determined by reflecting a laser from the surface of the Crystal onto some thing and moving chi and tau until the reflected spot remains stationary with movements of omega.

Use sigtau with no args to set interactively:

>>> pos chi -3.1
chi:      -3.1000
>>> pos phi 10.0
phi:      10.0000
>>> sigtau
sigma, tau = 0.000000, 0.000000
  chi, phi = -3.100000, 10.000000
sigma[  3.1]: 3.1
  tau[-10.0]: 10.0

Sigma and Tau can also be set explicitly:

>>>sigtau 0 0

Managing reflections

The normal way to calculate a UB matrix is to find the position of two reflections with known hkl values. Diffcalc allows many reflections to be recorded but currently only uses the first two when calculating a UB matrix.

Add reflection at current location

It is normal to first move to a reflection:

>>> pos en 10
en:       10.0000
>>> pos sixc [5.000, 22.790, 0.000, 1.552, 22.400, 14.255]
sixc:     alpha: 5.0000 delta: 22.7900 gamma: 0.0000 omega: 1.5520 chi: 22.4000 phi: 14.2550

and then use the addref command either explicitly:

addref  1 0 1.0628 'optional_tag'

or interactively:

>>> addref
h: 1
k: 0
l: 1.0628
current pos[y]: y
tag: 'tag_string'

to add a reflection.

Add a reflection manually

If a reflection cannot be reached but its position is known (or if its position has been previously determined), a reflection may be added without first moving to it either explicitly:

>>> addref 0 1 1.0628 [5.000, 22.790, 0.000,4.575, 24.275, 101.320] 'optional_tag'

or interactively:

>>> addref
h: 0
k: 1
l: 1.0628
current pos[y]: n
  alpha[5.000]:
  delta[22.79]:
  gamma[0.000]:
  omega[1.552]: 4.575
    chi[22.40]: 24.275
    phi[14.25]: 101.320
     en[9.998]:
    tag: optional_tag2
Edit reflection list

Use showref to show the reflection list:

>>> showref
     energy h    k    l     alpha    delta    gamma    omega    chi      phi       tag
  1  9.999  1.00 0.00 1.06  5.0000   22.7900  0.0000   1.5520   22.4000  14.2550   1st
  2  9.999  0.00 1.00 1.06  5.0000   22.7900  0.0000   4.5750   24.2750  101.32000 2nd

Use swapref to swap reflections:

>>> swapref 1 2
Recalculating UB matrix.
>>> showref
      energy h    k    l     alpha    delta    gamma    omega    chi      phi       tag
   1  9.999  0.00 1.00 1.06  5.0000   22.7900  0.0000   4.5750   24.2750  101.3200  2nd
   2  9.999  1.00 0.00 1.06  5.0000   22.7900  0.0000   1.5520   22.4000  14.2550   1st

Use delref to delete a reflection:

>>> delref 1
>>> showref
      energy h    k    l     alpha    delta    gamma    omega    chi      phi       tag
   1  9.999  1.00 0.00 1.06  5.0000   22.7900  0.0000   1.5520   22.4000  14.2550   1st

Calculating a UB matrix

Unless a U or UB matrix has been manually specified, a new UB matrix will be calculated after the second reflection has been found, or whenever one of the first two reflections is changed.

Use the command calcub to force the UB matrix to be calculated from the first two reflections.

If you have misidentified a reflection used for the orientation the resulting UB matrix will be incorrect. Always use the checkub command to check that the computed values agree with the estimated values:

>>>checkub
   energy h    k    l     h_comp k_comp l_comp  tag
1  9.9987 1.00 0.00 1.06  1.0000 0.0000 1.0628  1st
2  9.9987 0.00 1.00 1.06 -0.0329 1.0114 1.0400  2nd

Notice that the first reflection will always match, but that the second will not match exactly. (The system of equations used to calculate the U matrix is overdetermined and some information from the second reflection is thrown away.)

Manually setting U and UB

To help find the initial reflections it may be useful to set the U matrix manually—to the identity matrix for example. Use the setu command to do this. Once set the diffractometer may be driven to the ideal location of a reflection and then the actual reflection sought. Normally this would be done in the default mode, four-circle-bisecting, (see Moving in hkl space). In the following example this has been done by setting the alpha to 5 and leaving gamma at 0 (it would be normal to leave alpha at 0):

>>> hklmode 1
1) fourc bisecting
   alpha: 0.0
   gamma: 0.0

>>> setalpha 5
alpha: 0 --> 5.000000
>>> setu
row1[1 0 0]:
row2[0 1 0]:
row3[0 0 1]:
>>> sim hkl [1,0,1.0628] # Check it all makes sense
sixc would move to:
   alpha :   5.00000 deg
   delta :  22.79026 deg
   gamma :   0.00000 deg
   omega :   5.82845 deg
     chi :  24.57658 deg
     phi :   6.14137 deg

   theta : 70702.991919
  2theta : 23.303705
     Bin : 6.969151
    Bout : 6.969151
 azimuth : 7.262472

>>> pos hkl [1,0,1.0628]
hkl:      h: 1.00000 k: 0.00000 l: 1.06280

>>> # scan about to find actual reflection

>>> addref
h[0.0]: 1
k[0.0]: 0
l[0.0]: 1.0628
current pos[y]: y
tag: 'ref1'
>>>

There is currently no way to refine a manually specified U matrix by inferring as much as possible from just one found reflection.

Moving in hkl space

Once a UB matrix has been calculated, the diffractometer may be driven in hkl coordinates. A given diffractometer setting maps easily into a single hkl value. However for a diffractometer with more than three circles there are excess degrees of freedom when calculating a diffractometer setting from an hkl value. Diffcalc provides many for using up the excess degrees of freedom.

By default Diffcalc selects four-circle bisecting mode (see below).

Note that to play along with the following run the file in example/session/sixc_example.py to configure the UB-calculation.

Modes

Use the command hklmode to summarise the state of Diffcalc’s angle calculator. It shows a list the available modes for your diffractometer and the parameters that must be fixed for each, the current mode and the current parameter settings:

>>> hklmode
Available modes:
 0) fourc fixed-bandlw (alpha, gamma, blw) (Not impl.)
 1) fourc bisecting (alpha, gamma)
 2) fourc incoming  (alpha, gamma, betain)
 3) fourc outgoing  (alpha, gamma, betaout)
 4) fourc azimuth   (alpha, gamma, azimuth) (Not impl.)
 5) fourc fixed-phi (alpha, gamma, phi) (Not impl.)
10) fivec bisecting (gamma)
11) fivec incoming  (gamma, betain)
12) fivec outgoing  (gamma, betaout)
13) fivec bisecting (alpha)
14) fivec incoming  (alpha, betain)
15) fivec outgoing  (alpha, betaout)
20) zaxis bisecting ()
21) zaxis incoming  (betain)
22) zaxiz outgoing  (betaout)

Current mode:

1) fourc bisecting
Parameters:

   alpha: 0.0
   gamma: 0.0
  betain: --- (not relevant in this mode)
 betaout: --- (not relevant in this mode)
 azimuth: --- (not relevant in this mode)
     phi: --- (not relevant in this mode)
     blw: --- (not relevant in this mode)

Note that ‘Not impl.’ is short for ‘not implemented’. Standby.

Your output may differ. For example:

  • When listed with a typical five-circle diffractometer with no gamma circle: the fourc modes will have no gamma parameter to fix (actually it will have been fixed under the covers to 0), there will be no gamma or alpha parameters to fix in the five circle modes (again, under the covers gamma will have been fixed) and there will be no zaxis modes (as these require six circles, or an actual z-axis diffractometer).
  • When listed with a typical four-circle diffractometer with no alpha or gamma circle, the four-circle modes will appear with no alpha or gamma parameters (again, they are fixed under the covers), and there will be no five circle or zaxis modes.

To change the current mode, call hklmode with an argument:

>>> hklmode 2
2) fourc incoming
   alpha: 0.0
   gamma: 0.0
  betain: ---

(The dashes next to the betain parameter indicate that a parameter has not yet been set.)

Mode parameters

A parameter can be set using either one of the series of {{{set}}} commands, by moving one of the scannables associated with each parameter or, where appropriate, by asking that a parameter track an axis.

Set commands

Use the series of commands set<param_name> to set a parameter:

>>> setalpha 3
alpha: 0 --> 3.000000
>>> setbetain 5
WARNING: The parameter betain is not used in mode 1
betain: --- --> 5.000000
>>> setalpha    # With no args, the current value is displayed
alpha: 3
>>> setbetain
betain: ---
Parameter Scannables

In most installations there will be a scannable for each parameter. In this example installation, the parameters which correspond to physical axes have had ‘_par’ appended to their names to prevent clashes. These may be used to change a parameter either with the pos command or by using them within a scan (see Scanning in hkl space).:

>>> pos betain
betain:   0.00000
>>> pos betain 5
betain:   5.00000
>>> setbetain
betain: 5

>>> pos alpha_par
alpha_par:3.00000
>>> setalpha
alpha: 3
Tracking Axis

Where a parameter matches an axis name, that parameter may be set to track that axis:

>>> pos alpha
alpha:    5.0000

>>> hklmode 1
1) fourc bisecting
   alpha: 0.0
   gamma: 0.0

>>> trackalpha
alpha: 5

>>> pos alpha
alpha:    6.0000

>>> hklmode 1
1) fourc bisecting
   alpha: 6.0  (tracking physical axis)
   gamma: 0.0

Although convenient, there is a danger with this method that in geometries where the axes are built from other axes (such as in a kappa geometry), the position of an axis may drift slightly during a scan.

Sectors

When mapping from reciprocal lattice space to a set of diffractometer settings, there is normally a choice of solutions for the sample orientation. The selected sector mode will determine which solution is used. There is currently only one sector mode:

Sector mode: Find first solution within sector limits

In this sector mode, taken from ‘DIF’, the first solution found within the ‘sector limits’ is chosen. These are different from the physical or software limits on the axes and can be checked/modified using setsectorlim:

>>> setsectorlim
omega_high[270]:
 omega_low[-90]:
  phi_high[180]:
   phi_low[-180]:

The hkl scannable

Once a UB matrix has been calculated, a mode chosen and parmeters set, use the hkl scannable to move to a point in reciprocal lattice space:

>>> pos hkl [1,0,0]
hkl:      h: 1.00000 k: -0.00000 l: -0.00000
>>> pos sixc
sixc:     alpha: 3.0000 delta: 17.2252 gamma: 4.0000 omega: 7.5046 chi: -24.6257 phi: 4.8026
>>> pos hkl
hkl:      h: 1.00000 k: -0.00000 l: -0.00000
>>> hkl
hkl:
       h : 1.000000
       k : -0.000000
       l : -0.000000
  2theta : 18.582618
     Bin : -0.387976
    Bout : -0.387976
 azimuth : 1.646099

Notice that typing hkl will also display some virtual angles (such as twotheta and Bin), that checking the position with pos hkl will not.

To get this extra information into a scan use the scannable hklverbose instead of hkl:

>>> pos hklverbose [1,0,0]
hklverbose:      h: 1.00000 k: -0.00000 l: -0.00000  2theta : 18.582618 Bin : -0.387976
                 Bout :-0.387976  azimuth : 1.646099

The sim command will report, without moving the diffractometer, where an hkl position would be found:

>>> sim hkl [1,0,0]
sixc would move to:
   alpha :   3.00000 deg
   delta :  17.22516 deg
   gamma :   4.00000 deg
   omega :   7.50461 deg
     chi : -24.62568 deg
     phi :   4.80260 deg

   theta : 70702.991919
  2theta : 18.582618
     Bin : -0.387976
    Bout : -0.387976
 azimuth : 1.646099
Moving out of range

Not every hkl position can be reached:

>>> pos hkl [10,10,10]
Exception: Could not compute delta for this hkl position

The diffractometer scannable (sixc)

We’ve seen this before, but it also works with sim:

gda>>>sim sixc [3, 17.22516, 4, 7.50461,  -24.62568, 4.80260]
hkl would move to:
  h : 1.000000
  k : 0.000000
  l : -0.000000

Scanning in hkl space

All scans described below use the same generic scanning mechanism provided by the GDA system or by minigda. Here are some examples.

Fixed hkl scans

In a ‘fixed hkl scan’ something (such as energy or Bin) is scanned, and at each step hkl is ‘moved’ to keep the sample and detector aligned. Also plonk the diffractometer scannable (sixc) on there with no destination to monitor what is actually happening and then throw on a detector (cnt) with an exposure time if appropriate:

>>> #scan scannable_name start stop step [scannable_name [pos or time]]..

>>> scan en 9 11 .5 hkl [1,0,0] sixc cnt 1

>>> scan en 9 11 .5 hklverbose [1,0,0] sixc cnt 1

>>> scan betain 4 5 .2 hkl [1,0,0] sixc cnt 1

>>> scan alpha_par 0 10 2 hkl [1,0,0] sixc cnt 1

>>> trackalpha
>>> scan alpha 0 10 2 hkl [1,0,0] sixc cnt 1 # Equivalent to last scan

Scanning hkl

Hkl, or one component, may also be scanned directly:

>>> scan h .8 1.2 .1 hklverbose sixc cnt 1

At each step, this will read the current hkl position, modify the h component and then move to the resulting vector. There is a danger that with this method k and l may drift. To get around this the start, stop and step values may also be specified as vectors. So for example:

>>> scan hkl [1,0,0] [1,.3,0] [1,0.1,0] cnt1

is equivilant to:

>>> pos hkl [1,0,0]
>>> scan k 0 .3 .1 cnt1

but will not suffer from drifting. This method also allows scans along any direction in hkl space to be performed.

Multidimension scans

Two and three dimensional scans:

>>> scan en 9 11 .5 h .9 1.1 .2 hklverbose sixc cnt 1
>>> scan h 1 3 1 k 1 3 1 l 1 3 1 hkl cnt 1

Good luck — RobW

Indices and tables

Diffcalc Developer Guide

Author:Rob Walton
Contact:rob.walton (at) diamond (dot) ac (dot) uk
Website:http://www.opengda.org/

Diffcalc: A diffraction condition calculator for diffractometer control

Introduction

Diffcalc is a diffraction condition calculator used for controlling diffractometers within reciprocal lattice space. It performs the same task as the fourc, sixc, twoc, kappa, psic and surf macros from SPEC.

Diffcalc’s standard calculation engine is an implementation of [You1999] . The first versions of Diffcalc were based on [Vlieg1993] and [Vlieg1998] and a ‘Vlieg’ engine is still available. The ‘You’ engine is more generic and the plan is to remove the old ‘Vlieg’ engine once beamlines have been migrated. New users should use the ‘You’ engine.

The foundations for this type of calculation were laid by by Busing & Levi in their classic paper [Busing1967]. Diffcalc’s orientation algorithm is taken from this paper. Busing & Levi also provided the original definition of the coordinate frames and of the U and B matrices used to describe a crystal’s orientation and to convert between Cartesian and reciprical lattice space.

Geometry plugins are used to adapt the six circle model used internally by Diffcalc to apply to other diffractometers. These contain a dictionary of the ‘missing’ angles which Diffcalc uses to constrain these angles internally, and a methods to map from external angles to Diffcalc angles and visa versa.

Options to use Diffcalc:

  • The User manual next to this developer manual or README file on github.
  • The quickstart-api section describes how to run up only the core in Python. This provides a base option for system integration.

Diffcalc will work with Python 2.7 or higher with numpy, or with Jython 2.7 of higher with Jama.

[*]The very small ‘Willmott’ engine currently handles the case for surface diffraction where the surface normal is held vertical [Willmott2011]. The ‘You’ engine handles this case fine, but currently spins nu into an unhelpful quadrant. We hope to remove the need for this engine soon.
[You1999]H. You. Angle calculations for a ‘4S+2D’ six-circle diffractometer. J. Appl. Cryst. (1999). 32, 614-623. (pdf link).
[Busing1967]W. R. Busing and H. A. Levy. Angle calculations for 3- and 4-circle X-ray and neutron diffractometers. Acta Cryst. (1967). 22, 457-464. (pdf link).
[Vlieg1993]Martin Lohmeier and Elias Vlieg. Angle calculations for a six-circle surface x-ray diffractometer. J. Appl. Cryst. (1993). 26, 706-716. (pdf link).
[Vlieg1998]Elias Vlieg. A (2+3)-type surface diffractometer: mergence of the z-axis and (2+2)-type geometries. J. Appl. Cryst. (1998). 31, 198-203. (pdf link).
[Willmott2011]C. M. Schlepütz, S. O. Mariager, S. A. Pauli, R. Feidenhans’l and P. R. Willmott. Angle calculations for a (2+3)-type diffractometer: focus on area detectors. J. Appl. Cryst. (2011). 44, 73-83. (pdf link).

Project Files & Directories

diffcalc
The main source package.
test
Diffcalcs unit-test package (use Nose to run them).
diffcmd
A spec-like openGDA emulator.
numjy
A very minimal implentation of numpy for jython. It supports only what Diffcalc needs.
doc
The documentation is written in reStructuredText and can be compiled into html and pdf using Python’s Sphinx. With Sphinx installed use make clean all from within the user and developer guide folders to build the documentation.
startup
Starup scripts called by diffcmd or openGDA to startup diffcalc
model
Vrml models of diffractometers and a hokey script for animating then and controlling them from diffcalc.

Warning

This documentation is out of date. The README and the user doc has been updated recently. For now if you need help with API, please contact me at Diamond. – Rob Walton

Quick-Start: Python API

This section describes how to run up only the core in Python or IPython. This provides an API which could be used to integrate Diffcalc into an existing data acquisition system; although the interface described in the README would normally provide a better starting point.

For a full description of what Diffcalc does and how to use it please see the ‘Diffcalc user manual’.

Setup environment

Change directory to the diffcalc project (python adds the current working directory to the path):

$ cd diffcalc
$ ls
COPYING  diffcalc  doc  example  mock.py  mock.pyc  model  numjy  test

If using Python make sure numpy and diffcalc can be imported:

$ python
Python 2.7.2+ (default, Oct  4 2011, 20:06:09)
[GCC 4.6.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import numpy
>>> import diffcalc

If using Jython make sure Jama and diffcalc can be imported:

$ jython -Dpython.path=<diffcalc_root>:<path_to_Jama>/Jama-1.0.1.jar

Jython 2.2.1 on java1.5.0_11
Type "copyright", "credits" or "license" for more information.
>>> import Jama
>>> import diffcalc

Start

With Python start the sixcircle_api.py example startup script (notice the -i and -m) and call demo_all():

$ python -i -m startup.api.sixcircle
>>> demo_all()

IPython requires:

$ ipython -i startup/api/sixcircle.py
>>> demo_all()

Alternatively start Python or IPython and cut and paste lines from the rest of this tutorial.

Configure a diffraction calculator

By default some exceptions are handled in a way to make user interaction friendlier. Switch this off with:

>>> import diffcalc.util
>>> diffcalc.util.DEBUG = True

To setup a Diffcalc calculator, first configure diffcalc.settings module:

>>> from diffcalc import settings
>>> from diffcalc.hkl.you.geometry import SixCircle
>>> from diffcalc.hardware import DummyHardwareAdapter
>>> settings.hardware = DummyHardwareAdapter(('mu', 'delta', 'gam', 'eta', 'chi', 'phi'))
>>> settings.geometry = SixCircle()  # @UndefinedVariable

The hardware adapter is used by Diffcalc to read up the current angle settings, wavelength and axes limits. It is primarily used to simplify commands for end users. It could be dropped for this API use, but it is also used for the important job of checking axes limits while choosing solutions.

Geometry plugins are used to adapt the six circle model used internally by Diffcalc to apply to other diffractometers. These contain a dictionary of the ‘missing’ angles which Diffcalc internally uses to constrain these angles, and a methods to map from external angles to Diffcalc angles and visa versa.

Calling the API

The diffcalc.dc.dcyou module (and others) read the diffcalc.settings module when first imported. Note that this means that changes to the settings will most likely have no effect unless diffcalc.dc.dcyou is reloaded:

>>> import diffcalc.dc.dcyou as dc

This includes the two critical functions:

def hkl_to_angles(h, k, l, energy=None):
    """Convert a given hkl vector to a set of diffractometer angles

    return angle tuple and virtual angles dictionary
    """

def angles_to_hkl(angle_tuple, energy=None):
    """Converts a set of diffractometer angles to an hkl position

    Return hkl tuple and virtual angles dictionary
    """

diffcalc.dc.dcyou also brings in all the commands from diffcalc.ub.ub, diffcalc.hardware and diffcalc.hkl.you.hkl. That is it includes all the commands exposed in the top level namespace when diffcalc is used interactively:

>>> dir(dc)

['__builtins__', '__doc__', '__file__', '__name__', '__package__',
'_hardware','_hkl', '_ub', 'addref', 'allhkl', 'angles_to_hkl', 'c2th',
'calcub', 'checkub', 'clearref', 'con', 'constraint_manager', 'delref',
'diffcalc', 'editref', 'energy_to_wavelength', 'hardware', 'hkl_to_angles',
'hklcalc', 'lastub', 'listub', 'loadub', 'newub', 'rmub', 'saveubas', 'setcut',
'setlat', 'setmax', 'setmin', 'settings', 'setu', 'setub', 'showref',
'swapref', 'trialub', 'ub', 'ub_commands_for_help', 'ubcalc', 'uncon']

This doesn’t form the best API to program against though, so it is best to use the four modules more directly. The example below assumes you have also imported:

>>> from diffcalc.ub import ub
>>> from diffcalc import hardware
>>> from diffcalc.hkl.you import hkl

Getting help

To get help for the diffcalc angle calculations, the orientation phase, the angle calculation phase, and the dummy hardware adapter commands:

>>> help(dc)
>>> help(ub)
>>> help(hkl)
>>> help(hardware)

Orientation

To orient the crystal for example (see the user manual for a fuller tutorial) first find some reflections:

# Create a new ub calculation and set lattice parameters
ub.newub('test')
ub.setlat('cubic', 1, 1, 1, 90, 90, 90)

# Add 1st reflection (demonstrating the hardware adapter)
hardware.settings.hardware.wavelength = 1
ub.c2th([1, 0, 0])                              # energy from hardware
settings.hardware.position = 0, 60, 0, 30, 0, 0 # mu del nu eta chi ph
ub.addref([1, 0, 0])                            # energy & pos from hardware

# Add 2nd reflection (this time without the hardware adapter)
ub.c2th([0, 1, 0], 12.39842)
ub.addref([0, 1, 0], [0, 60, 0, 30, 0, 90], 12.39842)

To check the state of the current UB calculation:

>>> ub.ub()

     UBCALC

        name:          test

        n_phi:      0.00000   0.00000   1.00000 <- set
        n_hkl:     -0.00000   0.00000   1.00000
        miscut:     None

     CRYSTAL

        name:         cubic

        a, b, c:    1.00000   1.00000   1.00000
                   90.00000  90.00000  90.00000

        B matrix:   6.28319   0.00000   0.00000
                    0.00000   6.28319   0.00000
                    0.00000   0.00000   6.28319

     UB MATRIX

        U matrix:   1.00000   0.00000   0.00000
                    0.00000   1.00000   0.00000
                    0.00000   0.00000   1.00000

        U angle:    0

        UB matrix:  6.28319   0.00000   0.00000
                    0.00000   6.28319   0.00000
                    0.00000   0.00000   6.28319

     REFLECTIONS

          ENERGY     H     K     L        MU    DELTA      GAM      ETA      CHI      PHI  TAG
        1 12.398  1.00  0.00  0.00    0.0000  60.0000   0.0000  30.0000   0.0000   0.0000
        2 12.398  0.00  1.00  0.00    0.0000  60.0000   0.0000  30.0000   0.0000  90.0000

And finally to check the reflections were specified acurately:

>>> dc.checkub()

    ENERGY     H     K     L    H_COMP   K_COMP   L_COMP     TAG
1  12.3984  1.00  0.00  0.00    1.0000   0.0000   0.0000
2  12.3984  0.00  1.00  0.00   -0.0000   1.0000   0.0000

Motion

Hkl positions and virtual angles can now be read up from angle settings (the easy direction!):

>>> dc.angles_to_hkl((0., 60., 0., 30., 0., 0.)) # energy from hardware

((1.0, 5.5511151231257827e-17, 0.0),
{'alpha': -0.0,
 'beta': 3.5083546492674376e-15,
 'naz': 0.0,
 'psi': 90.0,
 'qaz': 90.0,
 'tau': 90.0,
 'theta': 29.999999999999996})

Before calculating the settings to reach an hkl position (the trickier direction) hardware limits must be set and combination of constraints chosen. The constraints here result in a four circle like mode with a vertical scattering plane and incident angle ‘alpha’ equal to the exit angle ‘beta’:

>>> hkl.con('qaz', 90)
!   2 more constraints required
    qaz: 90.0000

>>> hkl.con('a_eq_b')
!   1 more constraint required
    qaz: 90.0000
    a_eq_b

>>> hkl.con('mu', 0)
    qaz: 90.0000
    a_eq_b
    mu: 0.0000

To check the constraints:

>>> hkl.con()
    DET        REF        SAMP
    ======     ======     ======
    delta  --> a_eq_b --> mu
    alpha      eta
--> qaz        beta       chi
    naz        psi        phi
                          mu_is_nu

    qaz: 90.0000
    a_eq_b
    mu: 0.0000

    Type 'help con' for instructions

Limits can be set to help Diffcalc choose a solution:

>>> hardware.setmin('delta', 0)       # used when choosing solution

Angles and virtual angles are then easily determined for a given hkl reflection:

>>> dc.hkl_to_angles(1, 0, 0)                        # energy from hardware
((0.0, 60.0, 0.0, 30.0, 0.0, 0.0),
 {'alpha': -0.0,
  'beta': 0.0,
  'naz': 0.0,
  'psi': 90.0,
  'qaz': 90.0,
  'tau': 90.0,
  'theta': 30.0}
 )

Development

The files are kept here on github. See bootcamp for an introduction to using github. To contribute please fork the project. Otherwise you can make a read-only clone or export.

Code format should follow pep8 guidelines. PyDev has a good pep8 checker.

To run the tests install nose, change directory into the test folder and run:

$ nosetests
.......... ...
----------------------------------------------------------------------
Ran 3914 tests in 9.584s

OK (SKIP=15)

Indices and tables

Acknowledgements

We would like to acknowledge the people who have made a direct impact on the Diffcalc project, knowingly or not, in terms of encouragement, suggestions, criticism, bug reports, code contributions, and related projects.

Names are ordered alphabetically by surname.

  • Allesandro Bombardi
  • Mark Booth
      1. Busing
  • Steve Collins
  • Mirian Garcia-Fernandez
      1. Levy
  • Martin Lohmier
  • Chris Nicklin
  • Elias Vlieg — writer of DIF software used as a model for Diffcalc
  • Robert Walton
    1. You
  • Fajin Yuan

Thank you!

Rob Walton & Irakli Sikharulidze

Indices and tables