/*
                         F O U R L I B

 This is a library of routines for doing transformations between the 
 various coordinate systems used on a four circle diffractometer as 
 used for neutron or X-ray diffraction. The coordinate systems used are
 described in  Busing, Levy, Acta Cryst (1967),22, 457 ff.

 Generally we have:
 
 Z = [OM][CHI][PHI][UB]h

 where: Z is  a vector in the diffractometer coordinate system
        OM CHI PHI are rotation matrices around the respective angles
        UB is the UB matrix
        h is the reciprocal lattice vector. 

 The vector Z cannot only be expressed in terms of the angles stt, om, chi,
 and phi put also by polar coordinates gamma and nu.

 This code is a reimplementation based on a F77 code from Gary McIntyre, ILL
 and code extracted from the ILL MAD control program. 

  Mark Koennecke, November-December 2001
*/
#include <stdio.h>
#include <assert.h>
#include <math.h>
#include "fortify.h"
#include "fourlib.h"

#define PI 3.141592653589793
#define RD 57.30
#define ABS(x) (x < 0 ? -(x) : (x)) 

/*------------------------------------------------------------------------
 a safe routine for calculating the atan of y/x
 ------------------------------------------------------------------------*/
static double myatan(double y, double x){
  if(ABS(x) < 0.0001){
    if(y > .0){
      return PI/2;
    }else {
      return -PI/2;
    }
  }

  if(x > .0){
      return atan(y/x);
  } else {
      if(y > .0){
	return PI + atan(y/x);
      } else {
	return -PI + atan(y/x);
      } 
  } 
}
/*-------------------------------------------------------------------------*/
static double rtan(double y, double x){
  double val;

  if( (x == 0.) && (y == 0.) ) {
    return .0;
  }       
  if( x == 0.) {
      if(y < 0.){
         return -PI/2.;
      } else {
	return PI/2.;
     }
  }
  if(ABS(y) < ABS(x)) {
    val = atan(ABS(y/x));
    if(x < 0.) {
      val =  PI - val;
    }
    if(y < 0.){
        val = -val;
    } 
    return val;
  } else {
      val  = PI/2. - atan(ABS(x/y));
      if(x < 0.) {
      val = PI - val;
      }
      if( y < 0.) {
      val = - val;
      }
  }
  return val;
}
/*----------------------------------------------------------------------
 clear3x3 sets a 3x3 matrix to 0
 -----------------------------------------------------------------------*/
static void clear3x3(MATRIX target){
  int i, j;
  for(i = 0; i < 3; i++){
    for(j = 0; j < 3; j++){
      target[i][j] = .0;
    }
  }
}
/*---------------------------------------------------------------------*/
MATRIX vectorToMatrix(double z[3]){
  int i;
  MATRIX res;

  res = mat_creat(3,1,ZERO_MATRIX);
  for(i = 0; i < 3; i++){
    res[i][0] = z[i];
  }
  return res;
}
/*---------------------------------------------------------------------*/
void matrixToVector(MATRIX zm, double z[3]){
  int i;
  for(i = 0; i < 3; i++){
    z[i] = zm[i][0];
  }
}
/*----------------------------------------------------------------------
  A Busing & levy PSI matrix
  ----------------------------------------------------------------------*/
static void psimat(MATRIX target, double psi){
  double psird = psi/RD;

  clear3x3(target);

  target[0][0] = 1.;
  target[1][1] = cos(psird);
  target[1][2] = sin(psird);
  target[2][1] = -target[1][2];
  target[2][2] = target[1][1];
}
/*----------------------------------------------------------------------
  A Busing & levy CHI matrix
  ----------------------------------------------------------------------*/
void chimat(MATRIX target, double chi){
  double chird = chi/RD;

  clear3x3(target);

  target[0][0] = cos(chird);
  target[0][2] = sin(chird);
  target[1][1] = 1.;
  target[2][0] = -target[0][2];
  target[2][2] = target[0][0];
}
/*----------------------------------------------------------------------
  A Busing & levy PHI matrix
  ----------------------------------------------------------------------*/
void phimat(MATRIX target, double phi){
  double phird = phi/RD;

  clear3x3(target);

  target[0][0] = cos(phird);
  target[0][1] = sin(phird);
  target[1][0] = -target[0][1];
  target[1][1] = target[0][0];
  target[2][2] = 1.;
}
/*------------------- PSD specific code ----------------------------*/
void det2pol(psdDescription *psd, int x, int y, double *gamma, double *nu) {
  double xobs, yobs, b, z, d;

  assert(ABS(psd->distance ) > .001);

  xobs = (x - psd->xZero)*psd->xScale;
  yobs = (y - psd->yZero)*psd->yScale;

  b = psd->distance*cos(yobs/psd->distance);
  z = psd->distance*sin(yobs/psd->distance);
  d = sqrt(xobs*xobs + b*b);
  *gamma = psd->gamma + myatan(xobs,b)*RD;
  *nu =    psd->nu + myatan(z,d)*RD;
}
/*----------------------------------------------------------------------*/
void pol2det(psdDescription *psd, double gamma, double nu, int *x, int *y){
  double delga, delnu, td, tn, e, f, g, zobs, xobs;

  delga = gamma - psd->gamma;
  delnu = nu    - psd->nu;
  td = tan(delga/RD);
  tn = tan(delnu/RD);
  e = sqrt(1. + td*td);
  f = tn*e;
  g = psd->distance*(1. + tn*tn +tn*tn*td*td);
  zobs = psd->distance*(atan(tn*e) + asin(f/g));
  xobs = td*(psd->distance*cos(zobs/psd->distance));
  *y = (int)nint(psd->yZero + zobs/psd->yScale);
  *x = (int)nint(psd->xZero + xobs/psd->xScale);
}

/*--------------- bisecting geometry code -----------------------------*/

/*
  turn chi and phi in order to get Z1 into the equatorial plane
*/
static void turnEquatorial(MATRIX z1, double *chi, double *phi){
  if(ABS(z1[0][0]) < .0001 || ABS(z1[1][0]) < .0001){
    *phi = .0;
    *chi = 90.;
    if(z1[2][0] < .0){
      *chi = - *chi;
    }
  } else {
    *phi = myatan(z1[1][0],z1[0][0])*RD;
    *chi = myatan(z1[2][0],
           sqrt(z1[0][0]*z1[0][0] + z1[1][0]*z1[1][0]))*RD;
  }
}
/*----------------------------------------------------------------------
calculate d-spacing and theta from  z1
-----------------------------------------------------------------------*/
static int calcTheta(double lambda, MATRIX z1, double *d, double *theta){
  double dstar, sintheta;

  dstar = sqrt(z1[0][0]*z1[0][0] + z1[1][0]*z1[1][0] + z1[2][0]*z1[2][0]);
  if(dstar < .0001){
    *d = .0;
    *theta = 0;
    return 0;
  }

  *d = 1./dstar;
  sintheta = lambda * dstar/2.;
  if(ABS(sintheta) > 1.0){
    *d = .0;
    *theta = .0;
    return 0;
  }
  *theta = asin(sintheta)*RD;
  return 1;
}
/*-------------------------------------------------------------------*/
int z1ToBisecting(double lambda, double z1[3], double *stt, double *om,
		    double *chi, double *phi) {
  MATRIX zz1;
  int status;

  zz1 = vectorToMatrix(z1);
  status = z1mToBisecting(lambda,zz1,stt,om,chi,phi);
  mat_free(zz1);
  return status;
}
/*------------------------------------------------------------------------*/
int z1mToBisecting(double lambda, MATRIX z1, double *stt, double *om,
		    double *chi, double *phi) {
  double d;
  int status;
  
  status = calcTheta(lambda,z1,&d,om);
  if(!status){
    *stt = .0;
    *om = .0;
    *chi = .0;
    *phi = .0;
    return status;
  }
  turnEquatorial(z1,chi,phi);
  *stt = *om*2.;
  *chi = 180. - *chi;
  *phi = 180. + *phi;

  return 1;
}
/*---------------------------------------------------------------------*/
int z1ToAnglesWithOffset(double lambda, MATRIX z1m,double omOffset,
                         double *stt,  double *om, 
                         double *chi, double *phi){
  int status, i;
  double d, delOm, sinchi, q, cosp, sinp, dstar;
  MATRIX z1;

  status = calcTheta(lambda,z1m,&d,om);
  if(!status){
    *stt = .0;
    *om = .0;
    *chi = .0;
    *phi = .0;
    return status;
  }
  *stt = 2. * *om;
  *om += omOffset;

  z1 = mat_copy(z1m); /* routine messes z1m up! */
  dstar = sqrt(z1[0][0]*z1[0][0] + z1[1][0]*z1[1][0] + z1[2][0]*z1[2][0]);
  for(i = 0; i < 3; i++){
       z1[i][0] /= dstar;
  }

  delOm = -omOffset/RD;
  sinchi = z1[2][0]/cos(delOm);
  if(ABS(sinchi) > 1.){
    mat_free(z1);
    return 0;
  }
  *chi = asin(sinchi);
  *chi = PI - *chi;
  if(*chi > PI){
    *chi = *chi - 2* PI;
  }
  

  q = cos(delOm)*cos(*chi);
  cosp = (sin(delOm)*z1[0][0] + q*z1[1][0])/
    (sin(delOm)*sin(delOm) + q*q);
  sinp = (z1[0][0] - sin(delOm)*cosp)/ q;
  *phi = rtan(cosp,sinp);

  *phi *= RD;
  *chi *= RD;

  mat_free(z1);
  return 1;  
}
/*---------------------------------------------------------------------*/
int psiForOmegaOffset(MATRIX z1m, double omOffset, 
			       double chi, double phi, double *psi){
  double chibi, sinps, cosps, sinchi, dstar;  
  MATRIX z1;

  z1 = mat_copy(z1m); /* routine messes z1m up! */
  dstar = sqrt(z1[0][0]*z1[0][0] + z1[1][0]*z1[1][0] + z1[2][0]*z1[2][0]);
  z1[2][0] /= dstar;

  omOffset /= RD;
  if(-z1[2][0] == 1.){
    *psi = phi;
  } else {
    chibi = PI - asin(-z1[2][0]);
    if(chibi > PI){
      chibi -= 2*PI;
    }
    sinps = tan(chibi)*tan(-omOffset);
    sinchi = -z1[2][0]/cos(-omOffset);
    if(ABS(sinchi) > 1.){
      mat_free(z1);
      return 0;
    }
    cosps = (cos(chibi) - sinps*sin(-omOffset)*sinchi)/cos(chi/RD);
    *psi = -rtan(sinps,cosps)*RD;
  }
  mat_free(z1);
  return 1;    

}

/*----------------------------------------------------------------------*/
void rotatePsi(double om, double chi, double phi, double psi,
               double *newom, double *newchi, double *newphi){
  MATRIX chim, phim, psim, r0, r0psi;

  chim = mat_creat(3,3,ZERO_MATRIX);
  chimat(chim,chi);
  phim = mat_creat(3,3,ZERO_MATRIX);
  phimat(phim,phi);
  r0 = mat_mul(chim,phim);
  psim = mat_creat(3,3,ZERO_MATRIX);
  psimat(psim,psi);
  r0psi = mat_mul(psim,r0);
  
  *newchi = rtan(sqrt(r0psi[2][0]*r0psi[2][0] + r0psi[2][1]*r0psi[2][1]),
	      r0psi[2][2])*RD;
  *newphi = rtan(-r0psi[2][1],-r0psi[2][0])*RD;
  *newom = om + rtan(-r0psi[1][2],r0psi[0][2])*RD;
  mat_free(chim);
  mat_free(phim);
  mat_free(psim);
  mat_free(r0);
  mat_free(r0psi);
}
/*--------------------------------------------------------------------
  calculate Z1 = [PHI]TZ3
  The T means transposed matrixes for the return calculation!
  ---------------------------------------------------------------------*/
static void z1fromz2(double z1[3], MATRIX z2, 
                     double phi){
  MATRIX phim, phimt, zz1;

  phim = mat_creat(3,3,ZERO_MATRIX);
  phimat(phim, phi);
  phimt = mat_tran(phim);
  zz1 = mat_mul(phimt,z2);
  matrixToVector(zz1,z1);
  mat_free(phim);
  mat_free(phimt);
  mat_free(zz1);
}
/*--------------------------------------------------------------------
  calculate Z1 = [PHI]T*[CHI]T*Z3
  The T means transposed matrixes for the return calculation!
  ---------------------------------------------------------------------*/
static void z1fromz3(double z1[3], MATRIX z3, double chi,
                     double phi){
  MATRIX chim, chimt, z2;

  chim = mat_creat(3,3,ZERO_MATRIX);
  chimat(chim, chi);
  chimt = mat_tran(chim);
  z2 = mat_mul(chimt,z3);
  z1fromz2(z1,z2,phi);
  mat_free(chim);
  mat_free(chimt);
  mat_free(z2);
}
/*--------------------------------------------------------------------
  calculate Z1 = [PHI]T*[CHI]T*[OM]T*Z4
  The T means transposed matrixes for the return calculation!
  ---------------------------------------------------------------------*/
static void z1fromz4(double z1[3], MATRIX z4, double om, double chi,
                     double phi){
  MATRIX oma, oma2, z3;

  oma = mat_creat(3,3,ZERO_MATRIX);
  phimat(oma, om);
  oma2 = mat_tran(oma);
  z3 = mat_mul(oma2,z4);
  z1fromz3(z1,z3,chi,phi);
  mat_free(oma);
  mat_free(oma2);
  mat_free(z3);
}
/*---------------------------------------------------------------------*/
void z1FromAngles(double lambda, double stt, double om, 
		  double chi, double phi, double z1[3]){
  MATRIX z4;
  double th;

  z4 = mat_creat(3,1,ZERO_MATRIX);
  th = (stt/2.)/RD;
  z4[0][0] =  (2. * sin(th)*cos(th))/lambda;
  z4[1][0] = (-2. *sin(th)*sin(th))/lambda;
  z4[2][0] = .0;
  z1fromz4(z1,z4,om,chi,phi);
  mat_free(z4);
}
/*----------------------------------------------------------------------
  Normal Beam geometry specific calculations. This means the reflection is
  expressed through the three angles omega, gamma (two theta detector) and
  nu (detector tilt). 

  bisToNormalBeam was lifted from HKLGEN.
  -----------------------------------------------------------------------*/
double sign(double a, double b){
  if(b >= .0){
    return ABS(a);
  } else {
    -ABS(a);
  }
}
/*----------------------------------------------------------------------*/
int bisToNormalBeam(double twotheta, double omega, double chi, double phi,
		double *omeganb, double *gamma, double *nu){
  double tth, fom, fchi, fphi, sint, sinnu, del;

  tth = twotheta/RD;
  fom = omega/RD;
  fchi = chi/RD;
  fphi = phi/RD;
 

  /* nu calculation */
  sint = sin(tth/2.);
  *nu = 2. * sin(fchi)*sint;
  if(*nu > 1.){
    return 0;
  }
  *nu = asin(*nu);
  *nu = ABS(*nu)*sign(1.,fchi);
  sinnu = sin(*nu);

  /* gamma calculation */
  *gamma = cos(tth)/cos(*nu);
  if(ABS(*gamma) > 1.0){
    return 0;
  }
  *gamma = acos(*gamma);
  *gamma = *gamma * sign(1.,tth);

  /* omega normal beam */
  del = asin(sint/cos(fchi));
  *omeganb = del + fphi;
   
  *omeganb *= RD;
  *gamma *= RD;
  *nu *= RD;

  if(ABS(*omeganb) > 180.){
    if(*omeganb < -180.){
      *omeganb += 360.;
    }
    if(*omeganb > 180.){
      *omeganb -= 360.;
    }
  }
  return 1;
}
/* --------------------------------------------------------------------*/
static void z4FromNormalBeam(MATRIX z4, double lambda, double gamma,
			     double nu){

  double gar, nur;

  gar = gamma/RD;
  nur = nu/RD;

  /*
    this is basically a conversion from polar coordinates to
    x,y,z coordinates. However, sin and cos are exchanged in
    comparison to textbook formulas for this conversion. But this
    is only a shift of origin
  */
  z4[0][0] = (sin(gar) * cos(nur))/lambda;
  z4[1][0] = (cos (gar) * cos(nur) -1.)/lambda;
  z4[2][0] = (sin(nur))/lambda; 
}
/*----------------------------------------------------------------------*/
void z1FromNormalBeam(double lambda, double omega, double gamma, 
		      double nu, double z1[3]){
  MATRIX z4, omm, omt, z1m;

  z4 = mat_creat(3,1,ZERO_MATRIX);
  z4FromNormalBeam(z4,lambda, gamma,nu);
  omm = mat_creat(3,3,ZERO_MATRIX);
  phimat(omm,omega);
  omt = mat_tran(omm);
  z1m = mat_mul(omt,z4);
  matrixToVector(z1m,z1);
  mat_free(z4);
  mat_free(omm);
  mat_free(omt);
  mat_free(z1m);
}
/*--------------------------------------------------------------------*/
double circlify(double val){
  while(val > 360.){
    val -= 360.;
  }
  while(val < 0.){
    val += 360.; 
  }
  return val;
}
/*----------------------------------------------------------------------*/
void z1FromAllAngles(double lambda, double omega , double gamma, 
		     double nu, double chi, double phi, double z1[3]){
  MATRIX z3;

  z1FromNormalBeam(lambda, omega, gamma, nu, z1);  
  z3 = vectorToMatrix(z1);
  z1fromz3(z1,z3,chi,phi);
  mat_free(z3);    
}
/*------------------- a test program ------------------------------------*/
#ifdef TESTCODE
int main(int argc, char *argv[]){
  psdDescription psd;
  double gamma,nu, lambda, stt, om, chi, phi, z1[3], psi;
  double psiom, psichi, psiphi;
  double sttex, omex, chiex, phiex;
  int x, y, status, i;
  MATRIX UB, UBinv, zz1,zz1b, hkl, hklback;
  double gaex, omnbex, nuex, omeganb;

  /* initializations */
  UB = mat_creat(3,3,ZERO_MATRIX);
  UB[0][0] = 0.016169;
  UB[0][1] = 0.011969;
  UB[0][2] = 0.063195;
  UB[1][0] = -.000545;
  UB[1][1] = 0.083377;
  UB[1][2] = -0.009117;
  UB[2][0] = -0.162051;
  UB[2][1] = 0.000945;
  UB[2][2] = 0.006321;
  UBinv = mat_inv(UB);
  lambda = 1.179;
  

  /* test PSD code */
  psd.xScale = .7;
  psd.yScale = 1.4;
  psd.xZero = 128;
  psd.yZero = 64;
  psd.distance = 450.;
  psd.gamma = 43.;
  psd.nu    = 12.3;

  det2pol(&psd,200, 111,&gamma, &nu);
  pol2det(&psd,gamma,nu, &x, &y);
  if(x == 200 && y == 111){
    printf("PSD test: OK\n");
  }

  /* test bisecting calculations. The tests were taken from a system known
     to work
  */
  status = 1;
  sttex = 30.58704;
  omex =  15.293520;
  chiex = 129.053604;
  phiex = 134.191132;
  hkl = mat_creat(3,1,ZERO_MATRIX);
  hkl[0][0] = -2.;
  hkl[1][0] = -2.;
  hkl[2][0] = 4.;
  zz1 = mat_mul(UB,hkl);
  z1mToBisecting(lambda,zz1,&stt,&om,&chi,&phi);
  if(ABS(stt - sttex)  > .01 || 
     ABS(om - omex)   > .01  ||
     ABS(chi - chiex)  > .01 ||
     ABS(phi - phiex) > .01){
    printf("Bisecting Angles calculation FAILED!!!!!!!!!\n");
    printf("Expected: %12.4f %12.4f %12.4f %12.4f\n", sttex, omex, chiex,phiex);
    printf("Got:       %12.4f %12.4f %12.4f %12.4f\n", stt,om,chi,phi);
    status = 0;
  }
  z1FromAngles(lambda,sttex,omex,chiex,phiex,z1);
  for(i = 0; i < 3; i++){
   if(ABS(zz1[i][0] - z1[i]) > .0001){
     printf("Calculation of Z1 from Angles FAILED!!!!\n");
     printf("Expected: %8.4f %8.4f %8.4f\n", zz1[0][0], zz1[1][0],
             zz1[2][0]);
     printf("GOT:     %8.4f %8.4f %8.4f\n",z1[0],z1[1],z1[2]);
     status = 0;
   }
  }
  hklback = mat_mul(UBinv,zz1);
  for(i = 0; i < 3; i++){
   if(ABS(hklback[i][0] - hkl[i][0]) > .0001){
      printf("Back Calculation of HKL FAILED!!!!!!!!!\n");
     printf("Expected: %8.4f %8.4f %8.4f\n", hkl[0][0], hkl[1][0],
             hkl[2][0]);
     printf("GOT:      %8.4f %8.4f %8.4f\n",hklback[0][0],
                             hklback[1][0],hklback[2][0]);
     status = 0;
   }
  }
  if(status == 1){
     printf("Bisecting test: OK\n");
  }



  /* try turning in psi */
  rotatePsi(omex,chiex,phiex,30.,&psiom,&psichi,&psiphi);
  omex = 37.374298;
  chiex = 123.068192;
  phiex = 170.8209099;
  if(ABS(psiom - omex)   > .01  ||
     ABS(psichi - chiex)  > .01 ||
     ABS(psiphi - phiex) > .01){
    printf("Psi Rotation test FAILED!!!!!!!!!\n");
    printf("Expected: %12.4f %12.4f %12.4f\n", omex, chiex,phiex);
    printf("Got:       %12.4f %12.4f %12.4f\n", psiom,psichi,psiphi);
    status = 0;
  } else {
    printf("Psi rotation test: OK\n");
  }

  /*
    try to calculate a psi for a given omega offset
  */
  omex =  15.293520;
  chiex = 129.053604;
  phiex = 134.191132;
  if(psiForOmegaOffset(zz1,-5.,chiex, phiex, &psi) != 1){
    printf("Failed to calculate PSI for a Omega Offset\n");
  } else {
    rotatePsi(omex,chiex,phiex,psi,&psiom,&psichi,&psiphi);
    if(ABS(psiom +5. - omex) > .5){
      printf("Failed to reach desired omega with calculated psi\n"); 
      printf("Expected: %12.4f Got: %12.4f PSI = %12.4f\n", omex -10.,
	     psiom, psi);
    } else {
      printf("Psi for Omega Offset: OK\n");
    }
  }

  /*
    try to calculate angles with a omega offset
  */
  omex = 10.29;
  chiex = 128.78;
  phiex = 126.24;
  sttex = 30.59;
  z1ToAnglesWithOffset(lambda, zz1, -5., &stt, &om, &chi, &phi);
  if(ABS(stt - sttex)  > .01 || 
     ABS(om - omex)   > .01  ||
     ABS(chi - chiex)  > .01 ||
     ABS(phi - phiex) > .01){
    printf("Angles calculation with Omega Offset FAILED!!!!!!!!!\n");
    printf("Expected: %12.4f %12.4f %12.4f %12.4f\n", sttex, omex, chiex,phiex);
    printf("Got:       %12.4f %12.4f %12.4f %12.4f\n", stt,om,chi,phi);
    status = 0;
  } else {
    printf("Angles with Omega Offset: OK\n");
  }
  

  /*
    test normal beam codes 
  */
  omex = 37.374298;
  gaex = 19.322;
  omnbex =  -21.057;
  nuex  =  24.186;
  z1mToBisecting(lambda,zz1,&stt,&om,&chi,&phi);
  chi = 50.949;
  phi = -45.8088;
  if(!bisToNormalBeam(stt,om,chi,phi,
		      &omeganb, &gamma, &nu)){
    printf("Error on normal beam calculation!!\n");
  }
  if(ABS(omeganb - omnbex)   > .01  ||
     ABS(gamma - gaex)  > .01 ||
     ABS(nu - nuex) > .01){
    printf("Normal Beam Calculation test FAILED!!!!!!!!!\n");
    printf("Expected: %12.4f %12.4f %12.4f\n", omnbex, gaex,nuex);
    printf("Got:       %12.4f %12.4f %12.4f\n", omeganb,gamma,nu);
  } else {
    printf("Normal Beam Angle Calculation: OK\n");
  }

  z1FromNormalBeam(lambda, omnbex, gaex, nuex,z1);
  status = 1;
  for(i = 0; i < 3; i++){
   if(ABS(zz1[i][0] - z1[i]) > .0001){
     printf("Calculation of Z1 from Normal Beam Angles FAILED!!!!\n");
     printf("Expected: %8.4f %8.4f %8.4f\n", zz1[0][0], zz1[1][0],
             zz1[2][0]);
     printf("GOT:     %8.4f %8.4f %8.4f\n",z1[0],z1[1],z1[2]);
     break;
     status = 0;
   }
  }
  if(status){
    printf("Normal Beam Backwards Calculation: OK\n");
  }

  /* 
    for interest: try to see how normal beam angles go if we rotate psi
  */
  /*
  sttex = 30.58704;
  om =  15.293520;
  chi = 50.949;
  phi = -45.8088;
  printf("        PSI        Omega      Gamma          Nu\n");
  for(i = 0; i < 36; i++){
    psi = i*10.;
    rotatePsi(om,chi,phi,psi,&psiom,&psichi,&psiphi);
    status = bisToNormalBeam(sttex,psiom,psichi,psiphi,&omeganb, &gamma, &nu);    
    if(status){
      printf("%12.4f%12.4f%12.4f%12.4f\n",psi,omeganb,gamma,nu);
    }
  }
  */

}

#endif



























