\subsection{Crystallographic Computations}
The HKL object performs standard four circle calculations. I.e., given a UB
matrix it calculates the four circle diffractometer setting angles required
for a reflection with index hkl. The UB must be determined from a set of
reflections found manually or automatically. This is done in an offline
program. The code in this module is a direct reimplementation of  fortran code
provided by Jean Allibon, ILL with the MAD four circle diffractometer
control program in  ANSI-C. For theory, see the contribution by 
W.C. Hamilton in the International Tables for Crystallography, 1974 edition.

The object uses the following object data structure:
@d hkldat @{
   typedef struct __HKL {
                         pObjectDescriptor pDes;
                         double fUB[9];
                         MATRIX UBinv;
                         double fLambda;
                         int iManual;
                         double fLastHKL[5];
                         int iNOR;
                         int iQuad;
	                 int iHM;
                         pMotor pTheta;
                         pMotor pOmega;
                         pMotor pChi;
                         pMotor pPhi;
                         pMotor pNu;
                         pSelVar pMono;
                         long lID;
                         } HKL;
@}

The fields are more or less self explaining:
\begin{description}
\item[pDes] The standard object descriptor.
\item[fUB] The UB matrix.
\item[iUB] is a flag which spcifies if a UB is specified.
\item[fLambda] The wavelength of the neutrons.
\item[iManual] A flag which defines if the wavelength has been set manually
or is updated automatically from a wavelength variable.
\item[fLastHKL] the HKL of the last reflection calculated.
\item[iNor] a flag for normal beam calculation mode.
\item[iHM] a flag for histogram memory mode. In this mode two theta
limits are checked  alos for detector 2 and 3.
\item[pTheta] The two theta motor. All motor are needed for boundary
checking.
\item[pOmega] The omega axis motor.
\item[pChi] The chi axis motor.
\item[pPhi] the phi axis motor.
\item[pNu] the nu axis motor for normal beam geometry. 
 This is detector tilt.
\item[pMono] The selector variable doing the wavelength. 
\end{description}

The wavelength is a bit tricky. As it would be to time consuming to read two
motors each time a calculation is performed, the lambda variable is updated
by registering a callback with the selector variable handling the
monochromator wavelength. As TriCS will be run with two monochromators on a
lift a means has to be provided to change the selector variable online. An
additonal feature is that the wavelength can be manipulated manually. This
adresses the issue that automatic wavelength may be inaccurate due to
lazy instrument scientists not   adjusting their instruments.

In terms of an interface the following functions will be provided by this
module:

@d hklint @{
   typedef struct __HKL *pHKL;
/*-------------------------------------------------------------------------*/
   pHKL CreateHKL(pMotor pTheta, pMotor pOmega, 
                  pMotor pChi, pMotor  pPhi, pMotor pNu);
   void DeleteHKL(void *pData);
 
   int HKLFactory(SConnection *pCon, SicsInterp *pSics, void *pData,
                  int argc, char *argv[]);
/*------------------------------------------------------------------------*/
  int SetWavelengthVariable(SConnection *pCon, pHKL self, pSelVar pVar);
  int SetWavelengthManual(pHKL self, float fVal);
  int SetUB(pHKL self, float fUB[9]);
  int GetUB(pHKL self, float fUB[9]);
  int SetNOR(pHKL self, int iNOB);
  int GetLambda(pHKL self, float *fVal);
  int GetCurrentHKL(pHKL self, float fVal[3]);
  int GetCurrentPosition(pHKL self, SConnection *pCon, float fPosition[4]);

  int CalculateSettings(pHKL self, float fHKL[3], float fPsi, int iHamil,
                        float fSet[4],SConnection *pCon);
  int RunHKL(pHKL self, float fHKL[3], float fPsi, int iHamil, SConnection
             *pCon);
  int DriveHKL(pHKL self, float fHKL[3], float fPsi, int iHamil,
               SConnection *pCon);

  int DriveSettings(pHKL self, float fSet[4],SConnection *pCon);

  int HKLAction(SConnection *pCon, SicsInterp *pSics, void *pData,
                int argc, char *argv[]);  

@}
All functions return 0 on failure, 1 on success if not stated otherwise.
Most functions take a pointer to a HKL data structure as first parameter.
 The function in more detail:
\begin{description}
\item[CreateHKL] creates a HKL object. The parameters are pointers to the
four four circle motors. Returns NULL on failure, a pointer to the new
object on success.
\item[DeleteHKL] properly removes an HKL object from the system.
\item[HKLFactory] The factory function which initialises an HKL object from
the initialisation script.
\item[SetWavelengthVariable] sets a new wavelength variable. Installs all
 necesarry callbacks for automatic update.
\item[SetWaveLengthManual] deinstall all callbacks and forces the wavelength
to the value specified a second parameter.
\item[SetUB] sets the UB matrix.
\item[SetNOR] sets the normal beam calculation flag to iNOR.
\item[CalculateSettings] is the heart of this all. As the name suggests
calculates the settings for a four circle diffractometer. The parameters
are:
\begin{description}
\item[self] A pointer to a HKL data structure.
\item[fHKL] The reflection indices to calculate the settings for.
\item[fPsi] The psi value for the reflection. For psi scans. Set to 0 if not
used.
\item[iHamil] The index of the hamilton position to calculate. Can be an
integer between 0 to 8. 0 denotes the normal case.
\item[fSet] contains the required settings if the function returns with
success. 0 = two theta, 1 = omega, 2 = chi, 3 = phi.
\end{description}
The function returns 1 on success, a negative value on failure. Possible
error returns are:
\begin{description}
\item[HKLIMPOSSIBLE] the calculation was impossible.
\item[HKLTHETALIMIT] a setting could be calculated but can not be accessed
due to a limit on two theta. 
\end{description}
\item[DriveHKL] calculates a setting and drives to the position. The
parameters are the same as with CalculateSettings. With the addition of a
pointer to the connection object doing the command for error messages and
everything.  The error returns are the same as with CalculateSettings
well. With the addition of HKJMOTFAIL, which means that a motor failed to
drive properly.  
\item[DriveSettings] drives to the the settings given in fSet.
\item[HKLAction] is the interpreter wrapper function for the HKL object.
\end{description}

@o hkl.i @{
/*-------------------------------------------------------------------------
                                H K L

  Internal data structure description. See hkl.h, c,w for more details.

  Mark Koennecke, February 1998
----------------------------------------------------------------------------*/
@<hkldat@>

@}

@o hkl.h @{
/*---------------------------------------------------------------------------
                              H K L
 This SICS object performs angle setting calculations for a four circle 
 diffractometer. The heart of this code is a C transcriptions of routines
 written by Jean Allibon at ILL for the MAD program. Theory is explained in
 the article by W. C. Hamilton in International Tables for Crystallography,
 1974 edition.

 copyright: see copyright.h

 Mark Koennecke, February 1998

----------------------------------------------------------------------------*/
#ifndef SICSHKL
#define SICSHKL
#include "selector.h"
#include "selvar.h"
@<hklint@>
#endif  
@}
