spec

Software for Diffraction

4.13. - Least-Squares Refinement of Lattice Parameters



In the previous sections, the procedure described for determining the orientation matrix required a knowledge of the lattice parameters of the crystal and the position of two reflections. When such information is unknown, the orientation matrix can be fit to an unlimited number of observed peak positions using a least-squares procedure. ( J. Matthews and R.L. Walker, Mathematical Methods of Physics, (Benjamin, Menlo Park, 1970), p. 391. ) Lattice parameters derived from the fitted orientation matrix can then be calculated, although such lattice parameters are not constrained to exhibit any symmetry whatsoever.

In spec's implementation of least square refinement, three macros are used to create a file that contains the observed peak positions. That file is eventually run as a command file, and the least squares analysis is performed.


The reflex_beg macro initializes the reflections file:
global REFLEX   # Variable for file name
# Open the file, save old one as .bak and write header
def reflex_beg '{
      if ("$1" == "0") {
              if (REFLEX == ")
                      REFLEX = "reflex"
              REFLEX = getsval("Reflections file", REFLEX)
      } else
              REFLEX = "$1"

      if (open(REFLEX))
              exit
      close(REFLEX)
      if (file_info(REFLEX, "-s"))
              unix(sprintf("mv %s %s.bak", REFLEX, REFLEX))
      fprintf(REFLEX,"# %s\n\n_begUB\n\n",date())
}'


The reflex macro adds lines to the file that contain the (H,K,L) and (2θ,θ,χ,φ) of each reflection:
# Add reflection to the file
def reflex '
      if ($# != 3) {
              print "Usage:  reflex H K L"
              exit
      }
      if (REFLEX == ") {
              REFLEX = getsval("Reflections file", "reflex")
              if (REFLEX == ")
                      exit
      }
      waitmove; get_angles; calcHKL
      fprintf(REFLEX,"H = %g;  K = %g;  L = %g\n",$1,$2,$3)
      {
        local i

        for (i=0; i<_numgeo; i++)
              fprintf(REFLEX,"A[%s]=%9.4f;  ",motor_mne(mA[i]),A[mA[i]])
        fprintf(REFLEX,"\n")
      }
      fprintf(REFLEX,"# counts = %g\n", S[DET])
      fprintf(REFLEX,"_addUB\n\n")
'



Finally, the reflex_end macro puts the proper trailer on the file:
# Add trailer to file
def reflex_end '
      fprintf(REFLEX,"_fitUB\n")
      printf("Type \"qdo %s\" to calculate new orientation matrix\n",\
              REFLEX)
'


When you are ready to calculate the orientation matrix, simply run the command file. There is no limit to the number of reflections contained in the file. You can also edit the file by hand to add or subtract reflections.

The calculated orientation matrix will remain valid until you type calcG, or invoke a macro that calls calcG. Those macros are or0, or1, or_swap and setlat.

The six original lattice parameters will remain unchanged when using the above macros to fit the orientation matrix to the reflections. The calcL macro can be invoked to calculate the lattice parameters derived from the fitted orientation matrix and place their values in the appropriate elements of the parameter array. The old lattice parameters will be lost.

Here is a sketch of the commands you use to perform the least squares refinement of the lattice parameters.
1.FOURC> reflex_beg
Reflections file (reflex)? <return> 2.FOURC> (find and move to a reflection ...)
3.FOURC> reflex 2 2 0
4.FOURC> (find and move to another reflection ...)
5.FOURC> reflex 2 0 2
6.FOURC> ...
7.FOURC> reflex_end
Type "qdo reflex" to recalculate orientation matrix. 8.FOURC> qdo reflex
Opened command file `reflex' at level 1. 9.FOURC>



At least three reflections must be used for the least-squares fitting to work.


To calculate the new lattice parameters, use the calcL macro:
1.FOURC> calcL
2.FOURC> pa
Four-Circle Geometry, Omega fixed (mode 1) Frozen values: Omega = 5 Sector 0 Primary Reflection (at lambda 1.54): tth th chi phi = 74.212 42.106 89.898 -80.2141 H K L = 2 2 0 Secondary Reflection (at lambda 1.54): tth th chi phi = 24.631 17.3155 135.315 -82.9029 H K L = 0 1 0 Lattice Constants (lengths / angles): real space = 4.127 4.123 4.111 / 90.04 89.98 90.12 reciprocal space = 1.523 1.524 1.528 / 89.96 90.02 89.88 Azimuthal Reference: H K L = 0 0 1 Cut Points: tth th chi phi -180 -180 -180 -180 3.FOURC>

Here is a typical reflections file created by the above macros:
# Wed Jan 31 21:55:01 1990

_begUB

H = 2;  K = 2;  L = 0
A[tth]=  63.8185;  A[th]=  36.9320;  A[chi]=  89.8765;  A[phi]= -80.0815
# counts = 3456
_addUB

H = 2;  K = 0;  L = 2
A[tth]=  63.8335;  A[th]=  36.8920;  A[chi]= 145.4185;  A[phi]=  42.8145
# counts = 6345
_addUB

H = 0;  K = 2;  L = -1
A[tth]=  49.4100;  A[th]=  29.6725;  A[chi]=  35.8180;  A[phi]=  45.9070
# counts = 5634
_addUB

H = 0;  K = 2;  L = -1
A[tth]=  49.3550;  A[th]=  29.7225;  A[chi]=  35.9380;  A[phi]=  45.9070
# counts = 4563
_addUB

_fitUB
Within this file, the calc() function codes defined by the macros _begUB, _addUB and _fitUB are used to access the C code that performs the least squares operations.