#include <cstdio>
#include <cstdlib>
#include <cmath>

//#include <iostream>

#include "AdvNeutronManagerDNA.hh"
//#include "AdvPhysicalParameterDNA.hh"
#include "UtsusemiUnitConverter.hh"
#include "AdvDetectorManagerDNA.hh"

const UInt4 AdvNeutronManagerDNA::MAX_ITER_THETA = 10;
const UInt4 AdvNeutronManagerDNA::MAX_ITER_PHI   = 10;
const UInt4 AdvNeutronManagerDNA::MAX_ITER_NEWTON=100;

const Double AdvNeutronManagerDNA::THRESHOLD_NEWTON=1.0e-6;
const Double AdvNeutronManagerDNA::THRESHOLD_JUDGE =1.0e-8;
const Double AdvNeutronManagerDNA::THRESHOLD_ZERO  =1.0e-8;

const Double AdvNeutronManagerDNA::D_PHI_DEFAULT  =0.0001;
const Double AdvNeutronManagerDNA::D_THETA_DEFAULT=0.0001;


/**
 * A constructor.
 *
 * set default value for private variables.
 */
AdvNeutronManagerDNA::AdvNeutronManagerDNA(void){
  // SI unit
  equipmentManager=NULL;
  neutron.incEnergy.clear();
  neutron.finEnergy=0.0;
  neutron.finLambda=0.0;
  neutron.qincX.clear();
  neutron.qincY.clear();
  neutron.qincZ.clear();
  neutron.qoutX=0.0;
  neutron.qoutY=0.0;
  neutron.qoutZ=0.0;
  neutron.qfinX=0.0;
  neutron.qfinY=0.0;
  neutron.qfinZ=0.0;
  neutron.detPosX=0.0;
  neutron.detPosY=0.0;
  neutron.detPosZ=0.0;
  neutron.scaPosX=0.0;
  neutron.scaPosY=0.0;
  neutron.scaPosZ=0.0;
  neutron.tofSS.clear();
  neutron.tofSD=0.0;
  neutron.tof.clear();
  neutron.thetaBrag=0.0;
  neutron.thetaDetector=0.0;
  neutron.judge=0;
}

/**
 * A constructor
 *
 * set default value for private variables.
 * @param *equipmentMan pointer for the instance of EquipmentManager class
 */
AdvNeutronManagerDNA::AdvNeutronManagerDNA(class AdvEquipmentManagerDNA *equipmentMan){
  equipmentManager=equipmentMan;
  neutron.incEnergy.clear();
  neutron.finEnergy=0.0;
  neutron.finLambda=0.0;
  neutron.qincX.clear();
  neutron.qincY.clear();
  neutron.qincZ.clear();
  neutron.qoutX=0.0;
  neutron.qoutY=0.0;
  neutron.qoutZ=0.0;
  neutron.qfinX=0.0;
  neutron.qfinY=0.0;
  neutron.qfinZ=0.0;
  neutron.detPosX=0.0;
  neutron.detPosY=0.0;
  neutron.detPosZ=0.0;
  neutron.scaPosX=0.0;
  neutron.scaPosY=0.0;
  neutron.scaPosZ=0.0;
  neutron.tofSS.clear();
  neutron.tofSD=0.0;
  neutron.tof.clear();
  neutron.thetaBrag=0.0;
  neutron.thetaDetector=0.0;
  neutron.judge=0;
}


/**
 * A destructor.
 *
 * do nothing
 */
AdvNeutronManagerDNA::~AdvNeutronManagerDNA(void){
}

/**
 * obtain the coordinate of detected point from outer subroutine.
 * @param detPosX x-coordinate of detected point of neutron
 * @param detPosY y-coordinate of detected point of neutron
 * @param detPosZ z-coordinate of detected point of neutron
 */
Int4 AdvNeutronManagerDNA::PutDetPos(Double detPosX, Double detPosY, Double detPosZ){
  neutron.detPosX=detPosX;
  neutron.detPosY=detPosY;
  neutron.detPosZ=detPosZ;
  return 0;
}

/**
 * obtain the coordinate of the scattering center point from outer subroutine.
 * @param scaPosX x-coordinate of scattering point of neutron in the sample
 * @param scaPosY y-coordinate of scattering point of neutron in the sample
 * @param scaPosZ z-coordinate of scattering point of neutron in the sample
 */
Int4 AdvNeutronManagerDNA::PutScaPos(Double scaPosX, Double scaPosY, Double scaPosZ){
  neutron.scaPosX=scaPosX;
  neutron.scaPosY=scaPosY;
  neutron.scaPosZ=scaPosZ;
  return 0;
}

/**
 * give the information of neutron.
 * @param neutronOutput neutronInfo-type struct variable in which information of neutron is saved
*/
Int4 AdvNeutronManagerDNA::GetNeutronInfo(struct neutronInfo *neutronOutput){
  neutronOutput->incEnergy          =neutron.incEnergy;
  neutronOutput->finEnergy          =neutron.finEnergy;
  neutronOutput->finLambda           =neutron.finLambda;
  neutronOutput->qincX              =neutron.qincX;
  neutronOutput->qincY              =neutron.qincY;
  neutronOutput->qincZ              =neutron.qincZ;
  neutronOutput->qoutX              =neutron.qoutX;
  neutronOutput->qoutY              =neutron.qoutY;
  neutronOutput->qoutZ              =neutron.qoutZ;
  neutronOutput->qfinX              =neutron.qfinX;
  neutronOutput->qfinY              =neutron.qfinY;
  neutronOutput->qfinZ              =neutron.qfinZ;
  neutronOutput->detPosX                =neutron.detPosX;
  neutronOutput->detPosY                =neutron.detPosY;
  neutronOutput->detPosZ                =neutron.detPosZ;
  neutronOutput->scaPosX                =neutron.scaPosX;
  neutronOutput->scaPosY                =neutron.scaPosY;
  neutronOutput->scaPosZ                =neutron.scaPosZ;
  neutronOutput->tofSS              =neutron.tofSS;
  neutronOutput->tofSD              =neutron.tofSD;
  neutronOutput->tof                 =neutron.tof;
  neutronOutput->thetaBrag          =neutron.thetaBrag;
  neutronOutput->thetaDetector      =neutron.thetaDetector;
  neutronOutput->judge               =neutron.judge;
  return 0;
}

/**
 * set neutron data to neutronInfo variable.
 *
 * calculate the value of energy, theta, tof, etc of the neutron.
 * @param nBrag nBrag times Lambda = 2d sin (thetaBrag)
 */
//Int4 AdvNeutronManagerDNA::CalcFinEnergyThetaDetectorTofSD(Int4 nBrag){
Int4 AdvNeutronManagerDNA::SetNeutronData(Int4 nBrag){

/* calculate reflected point */
  // set detected point and scattered point
  detPos.x=neutron.detPosX;
  detPos.y=neutron.detPosY;
  detPos.z=neutron.detPosZ;
  scaPos.x=neutron.scaPosX;
  scaPos.y=neutron.scaPosY;
  scaPos.z=neutron.scaPosZ;

  if (!equipmentManager) {
    std::printf(" Equipment Manager should be specified in instance of AdvNeutronManagerDNA\n");
    exit(1);
  }

  // set equipment data used here
  L1=equipmentManager->GetL1();
  radiusUpperAnal=equipmentManager->GetUpperRadius();
  radiusLowerAnal=equipmentManager->GetLowerRadius();
  UppLtcSpc=equipmentManager->GetUppLtcSpc();
  LowLtcSpc=equipmentManager->GetLowLtcSpc();
  equipmentManager->GetCenterPosUpperMirror(&centerPosUpperAnal);
  equipmentManager->GetCenterPosLowerMirror(&centerPosLowerAnal);

  UInt4 i;
  // thetaReflectPos, phiReflectPos is relrected point.
  // theta is defined by measurement from Y axis and phi is defined by meqsurement from Z zxis in the Z-X plane.
  Double thetaReflectPos, phiReflectPos;

//#ifdef debug
//  std::printf("* information *\n");
//  std::printf("detPos :: %f, %f, %f\n", detPos.x, detPos.y, detPos.z);
//  std::printf("scaPos :: %f, %f, %f\n", scaPos.x, scaPos.y, scaPos.z);
//  std::printf("centerPosUpperAnal :: %f, %f, %f\n", centerPosUpperAnal.x, centerPosUpperAnal.y, centerPosUpperAnal.z);
//  std::printf("centerPosLowerAnal :: %f, %f, %f\n", centerPosLowerAnal.x, centerPosLowerAnal.y, centerPosLowerAnal.z);
//  std::printf("UppLtcSpc= %f,  LowLtcSpc=%f, radiusUpperAnal=%f, radiusLowerAnal=%f\n",
//          UppLtcSpc, LowLtcSpc, radiusUpperAnal, radiusLowerAnal);
//  std::printf("* information end\n");
//#endif

  // set initial value for thetaReflectPos and phiReflectPos.
  // if detPos.y > 0 thetaReflectPos should be less than pi/2.
  // if detPos.y < 0 thetaReflectPos should be larger than pi/2.
  // initial phiReflectPos is defined by the phi value of the vector connecting scattered point to detected point.
  if (detPos.y>0) {
    thetaReflectPos=PI/2-0.1*PI;
  }
  else {
    thetaReflectPos=PI/2+0.1*PI;
  }
  phiReflectPos=atan(detPos.x/detPos.z);
  if (phiReflectPos>0.0 && detPos.z < 0.0) {
    phiReflectPos+=PI;
  }
  else if ( phiReflectPos<0.0 && detPos.z < 0.0) {
    phiReflectPos+=PI;
  }
  if(phiReflectPos<0.0) phiReflectPos+=2.0*PI;

  // thetaReflectPos and phiReflectPos are defined by Newton method.
  // prePhiRefelctPos and preThetaReflectPos is reflected position determined by privious iteration of Newton method.
  // initPhiReflectPos is initial PhiReflectPos defined above.
  // diffPhiReflectPos and diffThetaReflectPos is difference of obtained value between current and previous iteration, respectively.
  // oldPos and renewPos is obtained reflected position at previous and current iteration, respectively.
  UInt4 j;
  Double prePhiReflectPos, initPhiReflectPos;
  Double preThetaReflectPos;
  Double diffPhiReflectPos, diffThetaReflectPos;
  struct coordinate oldPos, renewPos;
  initPhiReflectPos=phiReflectPos;

  Double radius; //radius for the analyzer mirror
  /* The recursive calculation by Newton method is executed below. */
  j=0;
  for (;;) {
    j++;
    // if iteration reached maximum number then exit.
    if (j>MAX_ITER_NEWTON) {
      std::printf("***caution***\n");
      std::printf("*** not converged *** \n");
      break;
    }

    // theta is defined by measurement from Y axis and phi is defined by meqsurement from Z zxis in the Z-X plane.
    // this is due to escape from numerical error

    // set the reflected position obtained by previous iteration.
    if (detPos.y>0.0) {
      radius=radiusUpperAnal;
      oldPos.x=radius*sin(thetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.x;
      oldPos.y=radius*cos(thetaReflectPos)+centerPosUpperAnal.y;
      oldPos.z=radius*sin(thetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.z;
    }
    else {
      radius=radiusLowerAnal;
      oldPos.x=radius*sin(thetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.x;
      oldPos.y=radius*cos(thetaReflectPos)+centerPosLowerAnal.y;
      oldPos.z=radius*sin(thetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.z;
    }
    prePhiReflectPos=phiReflectPos;

    /* Optimization for thetaReflectPos by Newton method is executed below. */
    i=0;
    for (;;) {
      preThetaReflectPos=thetaReflectPos;
      DetThetaRefPos(detPos, centerPosUpperAnal, centerPosLowerAnal, scaPos, radius, &thetaReflectPos, phiReflectPos);
      diffThetaReflectPos=thetaReflectPos-preThetaReflectPos;
      if (diffThetaReflectPos<0.0) {
        diffThetaReflectPos=-diffThetaReflectPos;
      }
      if (diffThetaReflectPos<THRESHOLD_NEWTON) {
        break;
      }
      i++;
      if (i>MAX_ITER_THETA) {
        break;
      }
    }

    /* Optimization for phiReflectPos by Newton method is executed below. */
    i=0;
    for (;;) {
      prePhiReflectPos=phiReflectPos;
      phiReflectPos=    initPhiReflectPos;
      DetPhiRefPos(detPos, centerPosUpperAnal, centerPosLowerAnal, scaPos, radius, thetaReflectPos, &phiReflectPos);
      diffPhiReflectPos=phiReflectPos-prePhiReflectPos;
      if (diffPhiReflectPos<0.0) {
        diffPhiReflectPos=-diffPhiReflectPos;
      }
      if (diffPhiReflectPos<THRESHOLD_NEWTON) {
        break;
      }
      i++;
      if (i>MAX_ITER_PHI) {
        break;
      }
    }

    // set the reflected position obtained by current iteration.
    if (detPos.y>0.0) {
      radius=radiusUpperAnal;
      renewPos.x=radius*sin(thetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.x;
      renewPos.y=radius*cos(thetaReflectPos)+centerPosUpperAnal.y;
      renewPos.z=radius*sin(thetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.z;
    }
    else {
      radius=radiusLowerAnal;
      renewPos.x=radius*sin(thetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.x;
      renewPos.y=radius*cos(thetaReflectPos)+centerPosLowerAnal.y;
      renewPos.z=radius*sin(thetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.z;
    }

    //std::printf("distance old renew :: %18.16f\n", ReturnDistancePoints(oldPos, renewPos));

    // if the difference between oldPos and renewPos is less than threshold then exit.
    if (ReturnDistancePoints(oldPos, renewPos)<THRESHOLD_ZERO) {
      break;
    }
  }

#ifdef debug
//  std::printf("thetaReflectPos=%f, phiReflectPos=%f\n", thetaReflectPos, phiReflectPos/PI);
#endif


// Below, influence by resolution of detector is considered.
// If unnecessary, please comment out.

// ------------------ from here -------------------------------------//

/* check */
/*
  if (detPos.y>0.0) {

    radius=radiusUpperAnal;

    double rsd=equipmentManager->GetUpperDetectorPhi(0, 0)*0.5;
    double sintheta=sin(PI/2-thetaReflectPos);
    //if (sintheta<0.0) sintheta*=-1.0;
    double costheta=cos(PI/2-thetaReflectPos);
//    double x0=0.0;
    double y0= centerPosUpperAnal.y;
    double t=(rsd-radius*costheta)/(-radius*costheta-2.0*y0*sintheta*costheta);


    double tqoutx=radius*costheta;
    double tqouty=radius*sintheta+y0;
    double tqfinx=-radius*costheta-2.0*y0*sintheta*costheta;
    double tqfiny=-radius*sintheta-2.0*y0*sintheta*sintheta+y0;
    double nx=-costheta;
    double ny=-sintheta;

    double sinphi=sin(phiReflectPos);
    double cosphi=cos(phiReflectPos);

    std::printf("qout:: %f, %f\n", tqoutx, tqouty);
    std::printf("qfin:: %f, %f\n", tqfinx, tqfiny);
    std::printf("n   :: %f, %f\n", nx, ny);
    std::printf("n+qt:: %f, %f\n", 2.0*(radius+y0*sintheta)*nx+tqoutx,
                              2.0*(radius+y0*sintheta)*ny+tqouty);

    std::printf("detlen :: %f\n",  sqrt(detPos.x*detPos.x+detPos.z*detPos.z));


    double tqx, tqy, tqz;




    std::printf("centerPosUpperAnal.y=%f, radius=%f, phi625=%f\n",
            centerPosUpperAnal.y, radiusUpperAnal, equipmentManager->GetPhi625());
    std::printf("mirror :: x=%f, y=%f\n", radius*costheta, radius*sintheta+y0);
    std::printf("sintheta=%f, sintheta=%f\n", sintheta, costheta);
    std::printf("reflect y=%f\n", radius*sintheta+y0);
    std::printf("detector x=%f\n", radius*costheta+(-radius*costheta-2.0*y0*sintheta*costheta)*t);
    std::printf("detector y=%f\n", y0+radius*sintheta+(-radius*sintheta-2.0*y0*sintheta*sintheta+y0)*t);
    std::printf("y0=%f, sintheta=%f, ()=%f, t=%f\n",
            y0, sintheta, radius*sintheta-2.0*y0*sintheta*sintheta+y0, t);
    std::printf("energy = %20.16e\n", PI*PI*HBAR/MLF_Mn*HBAR/2/UppLtcSpc/UppLtcSpc
                           /(1.0-y0*y0*costheta*costheta/(y0*y0+radius*radius+2.0*y0*radius*sintheta))*MLF_J2MEV);

    tqx=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*radius*costheta*sinphi*FM2M,
    tqy=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*(radius*sintheta+y0)*FM2M,
    tqz=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*radius*costheta*cosphi*FM2M;

    std::printf("qx=%e, qy=%e, qz=%e, qx/qz=%e\n", tqx, tqy, tqz, tqx/tqz);

    double F1=y0-radius*sintheta-2.0*y0*sintheta*sintheta;
    double F2=rsd-radius*costheta;
    double F3=1./(radius*costheta+2.0*y0*sintheta*costheta);
    double F1p=-radius*costheta-4.0*y0*sintheta*costheta;
    double F2p=radius*sintheta;
    double F3p=(radius*sintheta-2.0*y0*(costheta*costheta-sintheta*sintheta))/
               (radius*costheta+2.0*y0*sintheta*costheta)/(radius*costheta+2.0*y0*sintheta*costheta);
    double dydtheta=radius*costheta-(F1p*F2*F3+F1*F2p*F3+F1*F2*F3p);

    std::printf("dydtheta=%f\n", dydtheta);



    double dtheta1=0.002/dydtheta;
    dtheta1*=-1.0;
    std::printf("dtheta1=%f\n", dtheta1);
    std::printf("pretheta=%f, ", thetaReflectPos);
    thetaReflectPos+=dtheta1;
    std::printf(" modtheta=%f\n", thetaReflectPos);
    sintheta=sin(PI/2-thetaReflectPos);
    costheta=cos(PI/2-thetaReflectPos);
    t=(rsd-radius*costheta)/(-radius*costheta-2.0*y0*sintheta*costheta);
    tqoutx=radius*costheta;
    tqouty=radius*sintheta+y0;
    tqfinx=-radius*costheta-2.0*y0*sintheta*costheta;
    tqfiny=-radius*sintheta-2.0*y0*sintheta*sintheta+y0;
    nx=-costheta;
    ny=-sintheta;
    std::printf("qout:: %f, %f\n", tqoutx, tqouty);
    std::printf("qfin:: %f, %f\n", tqfinx, tqfiny);
    std::printf("n   :: %f, %f\n", nx, ny);
    std::printf("detector x=%f\n", radius*costheta+(-radius*costheta-2.0*y0*sintheta*costheta)*t);
    std::printf("detector y=%f\n", y0+radius*sintheta+(-radius*sintheta-2.0*y0*sintheta*sintheta+y0)*t);
    std::printf("energy = %20.16e\n", PI*PI*HBAR/MLF_Mn*HBAR/2/UppLtcSpc/UppLtcSpc
                           /(1.0-y0*y0*costheta*costheta/(y0*y0+radius*radius+2.0*y0*radius*sintheta))*MLF_J2MEV);
    tqx=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*radius*costheta*sinphi*FM2M,
    tqy=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*(radius*sintheta+y0)*FM2M,
    tqz=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*radius*costheta*cosphi*FM2M;

    std::printf("qx=%e, qy=%e, qz=%e, qx/qz=%e\n", tqx, tqy, tqz, tqx/tqz);


    thetaReflectPos-=dtheta1;
    dtheta1=-0.002/dydtheta;
    dtheta1*=-1.0;
    std::printf("dtheta1=%f\n", dtheta1);
    std::printf("pretheta=%f, ", thetaReflectPos);
    thetaReflectPos+=dtheta1;
    std::printf(" modtheta=%f\n", thetaReflectPos);
    sintheta=sin(PI/2-thetaReflectPos);
    costheta=cos(PI/2-thetaReflectPos);
    t=(rsd-radius*costheta)/(-radius*costheta-2.0*y0*sintheta*costheta);
    tqoutx=radius*costheta;
    tqouty=radius*sintheta+y0;
    tqfinx=-radius*costheta-2.0*y0*sintheta*costheta;
    tqfiny=-radius*sintheta-2.0*y0*sintheta*sintheta+y0;
    nx=-costheta;
    ny=-sintheta;
    std::printf("qout:: %f, %f\n", tqoutx, tqouty);
    std::printf("qfin:: %f, %f\n", tqfinx, tqfiny);
    std::printf("n   :: %f, %f\n", nx, ny);
    std::printf("detector x=%f\n", radius*costheta+(-radius*costheta-2.0*y0*sintheta*costheta)*t);
    std::printf("detector y=%f\n", y0+radius*sintheta+(-radius*sintheta-2.0*y0*sintheta*sintheta+y0)*t);
    std::printf("energy = %18.16f\n", PI*PI*HBAR/MLF_Mn*HBAR/2/UppLtcSpc/UppLtcSpc
                           /(1.0-y0*y0*costheta*costheta/(y0*y0+radius*radius+2.0*y0*radius*sintheta))*MLF_J2MEV);

    tqx=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*radius*costheta*sinphi*FM2M,
    tqy=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*(radius*sintheta+y0)*FM2M,
    tqz=PI/UppLtcSpc*sqrt(1./(radius*radius+2.0*y0*radius*sintheta+y0*y0*sintheta*sintheta))*radius*costheta*cosphi*FM2M;

    std::printf("qx=%e, qy=%e, qz=%e, qx/qz=%e\n", tqx, tqy, tqz, tqx/tqz);

  }
*/
/*check end*/

// ------------------ to here -------------------------------------//

//  fflush(stdout);

//  std::printf("\n *** check value ***\n");
  // std::vector q0 = ReflectPos - scaPos
  //        q  : reflected neutron at ReflectPos
  //        n :: normal std::vector at ReflectPos

  /* check validity of reflected point */
  // qfinX (qfinY, qfinZ) is x- (y-, z-) component of unit std::vector of detected-neutron wave std::vector.
  // qoutX (qoutY, qoutZ) is x- (y-, z-) component of unit std::vector of scatterd-neutron wave std::vector.
  // nx (ny, nz) is x- (y-, z-) component of unit std::vector of normal std::vector at reflected point.
  // ReflectPos is a reflected position.
  Double qfinX, qfinY, qfinZ, qoutX, qoutY, qoutZ;
  Double nx, ny, nz;
  struct coordinate ReflectPos;

  // set values for ReflectPos.
  if (detPos.y>0.0) {
    radius=radiusUpperAnal;
    ReflectPos.x=radius*sin(thetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.x;
    ReflectPos.y=radius*cos(thetaReflectPos)+centerPosUpperAnal.y;
    ReflectPos.z=radius*sin(thetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.z;
  } else {
    radius=radiusLowerAnal;
    ReflectPos.x=radius*sin(thetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.x;
    ReflectPos.y=radius*cos(thetaReflectPos)+centerPosLowerAnal.y;
    ReflectPos.z=radius*sin(thetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.z;
  }

#ifdef debug
//  std::printf("ReflectPos :: %f, %f, %f\n", ReflectPos.x, ReflectPos.y, ReflectPos.z);
#endif


  /* check validity of angle  for reflected point */
  // In this routine, thetaReflectPosNeXus is theta measured from Z axis.
  // Reflected point should be located at the range of analyzer mirror.
  //
  // thetaReflectPosNeXus is theta of reflected point.
  double thetaReflectPosNeXus=atan(ReflectPos.y/sqrt(ReflectPos.x*ReflectPos.x+ReflectPos.z*ReflectPos.z));
#ifdef debug
//  std::printf("theta_Reflect = %f\n", thetaReflectPosNeXus/PI*180.0);
#endif
  if(detPos.y> 0.0){
    if (thetaReflectPosNeXus < equipmentManager->GetMinThetaUpperMirror() ||
        equipmentManager->GetMaxThetaUpperMirror() < thetaReflectPosNeXus) {
#ifdef debug
//      std::printf("*** neutron reflecting point was out of bounds of the upper analyzer mirror ***\n");
//      std::printf("    detPos.x=%f, detPos.y=%f, detPos.z=%f\n", detPos.x, detPos.y, detPos.z);
//      std::printf("    MinTheta=%f, theta_Reflect = %f, MaxTheta=%f\n",
//              equipmentManager->GetMinThetaUpperMirror(), thetaReflectPosNeXus,
//              equipmentManager->GetMaxThetaUpperMirror());
#endif
      return 1;
    } else {
      // nothing
    }
  } else {
    if (thetaReflectPosNeXus < -equipmentManager->GetMinThetaLowerMirror() ||
        equipmentManager->GetMaxThetaLowerMirror() < thetaReflectPosNeXus) {
#ifdef debug
//      std::printf("*** neutron reflecting point was out of bounds of the lower analyzer mirror ***\n");
//      std::printf("    detPos.x=%f, detPos.y=%f, detPos.z=%f\n", detPos.x, detPos.y, detPos.z);
//      std::printf("    MinTheta=%f, theta_Reflect = %f, MaxTheta=%f\n",
//              -equipmentManager->GetMinThetaLowerMirror(), thetaReflectPosNeXus,
//              equipmentManager->GetMaxThetaLowerMirror());
#endif
      return 1;
    }
  }


  // lengthFligth is a neutron length of flight from sample to detector.
  Double lengthFlight;
  lengthFlight=ReturnDistancePoints(detPos, ReflectPos)+ReturnDistancePoints(scaPos, ReflectPos);

#ifdef debug
//  std::printf("detPos.x=%f, detPos.y=%f, detPos.z=%f\n", detPos.x, detPos.y, detPos.z);
//  std::printf("ReflectPos.x=%f, ReflectPos.y=%f, ReflectPos.z=%f, lengthFlight=%f\n", ReflectPos.x, ReflectPos.y, ReflectPos.z, lengthFlight);
#endif

  // qout is unit std::vector of scattered neutron wave std::vector.
  qoutX=ReflectPos.x-scaPos.x;
  qoutY=ReflectPos.y-scaPos.y;
  qoutZ=ReflectPos.z-scaPos.z;
  Double lengthQ0=sqrt(qoutX*qoutX+qoutY*qoutY+qoutZ*qoutZ);
  qoutX/=lengthQ0;
  qoutY/=lengthQ0;
  qoutZ/=lengthQ0;

  // LtcSpc is distance between atomic surface of mirror.
  // (nx, ny, nz) is the unit std::vector of normalized std::vector at reflected point.
  Double LtcSpc;
  if (detPos.y>0.0) {
    nx=centerPosUpperAnal.x-ReflectPos.x;
    ny=centerPosUpperAnal.y-ReflectPos.y;
    nz=centerPosUpperAnal.z-ReflectPos.z;
    LtcSpc=UppLtcSpc;
  }
  else {
    nx=centerPosLowerAnal.x-ReflectPos.x;
    ny=centerPosLowerAnal.y-ReflectPos.y;
    nz=centerPosLowerAnal.z-ReflectPos.z;
    LtcSpc=LowLtcSpc;
  }
  Double lengthN=sqrt(nx*nx+ny*ny+nz*nz);
  nx/=lengthN;
  ny/=lengthN;
  nz/=lengthN;

  // qdotn is an absolute value of inner product q.n.
  Double qdotn;
  qdotn=qoutX*nx+qoutY*ny+qoutZ*nz;
  if (qdotn<0.0) {
    qdotn*=-1.0;
  }

#ifdef debug
//  std::printf("qoutX=%f, qoutY=%f, qoutZ=%f\n", qoutX, qoutY, qoutZ);
//  std::printf("qdotn=%f\n", qdotn);
#endif

  // qfin is the unit std::vector of detected neutron wave std::vector.
  qfinX=qoutX+2.0*qdotn*nx;
  qfinY=qoutY+2.0*qdotn*ny;
  qfinZ=qoutZ+2.0*qdotn*nz;

//  Double lengthQ=sqrt(qfinX*qfinX+qfinY*qfinY+qfinZ*qfinZ);
//  std::printf("lengthQ should be 1.0 :: lengthQ=%f\n", lengthQ);


  /* obtain detected point by use of qout, qfin and ReflectPos. */
  // obtained detected point should be coincide with given detected point.
  // variable "differnce" is difference value between obtained and given detected point.
  // detPosX, detPosY, detPosZ :: obtained detected point
  Double t;
  t=qfinX*(detPos.x-ReflectPos.x)+qfinY*(detPos.y-ReflectPos.y)+qfinZ*(detPos.z-ReflectPos.z);

  Double detPosX, detPosY, detPosZ;
  detPosX=ReflectPos.x+t*qfinX;
  detPosY=ReflectPos.y+t*qfinY;
  detPosZ=ReflectPos.z+t*qfinZ;

  Double difference;
  difference=sqrt( (detPos.x-detPosX)*(detPos.x-detPosX)
                  + (detPos.y-detPosY)*(detPos.y-detPosY)
                  + (detPos.z-detPosZ)*(detPos.z-detPosZ) );

#ifdef debug
//  std::printf("xd=%f (mm), yd=%f (mm), zd=%f (mm)\n", detPos.x*M2MM, detPos.y*M2MM, detPos.z*M2MM);
//  std::printf("xr=%f (mm), yr=%f (mm), zr=%f (mm)\n", detPosX*M2MM, detPosY*M2MM, detPosZ*M2MM);
//  std::printf("diff=%f (mm)\n", difference*M2MM);
#endif

  if (difference < THRESHOLD_JUDGE) {
    neutron.judge=1;
  } else {
    std::printf(" *** Newton method was not optimized the trace of neutron ***\n");
    return 1;
  }

/* added */
#ifdef debug
//  std::printf(" phi625 =%f\n", equipmentManager->GetPhi625()); fflush(stdout);
//  std::printf(" qxqz=%f, qy=%f\n", sqrt(qoutX*qoutX+qoutZ*qoutZ), qoutY); fflush(stdout);
#endif

  /* check the validity of flight path of neutron in the DNA equipment */
  // checkheight :: height at the entrance of the sample room
  // checkheight2 :: height in front of the detector
  double checkheight=equipmentManager->GetPhi625()/2.0/sqrt(qoutX*qoutX+qoutZ*qoutZ)*qoutY;
#ifdef debug
//  std::printf("height at 625 = %f\n", checkheight);
#endif
  double checkheight2=detPosY-(equipmentManager->GetPhi625()-equipmentManager->GetUpperDetectorPhi(0, 0))/2.0/sqrt(qfinX*qfinX+qfinZ*qfinZ)*qfinY;
#ifdef debug
//  std::printf("height at 625 part2 = %f\n", checkheight2);
#endif
  if( checkheight < -equipmentManager->GetW92() ||  equipmentManager->GetW120() < checkheight ){
//    std::printf(" *** neutron was scattered at exit of sample room ***\n"); std::printf("     w92=%f, height=%f, w120=%f\n", -equipmentManager->GetW92(),
//              checkheight, equipmentManager->GetW120());
    return 1;
  }

  if( checkheight2 < equipmentManager->GetLowerDetectorWindowLower() ||
      (equipmentManager->GetLowerDetectorWindowUpper() < checkheight2 && checkheight2 < equipmentManager->GetUpperDetectorWindowLower()) ||
      equipmentManager->GetUpperDetectorWindowUpper() < checkheight2 )
  {
//    std::printf(" *** neutron was scattered at entrance of detector room ***\n");
//    std::printf("     lower=%f, height=%f, heigher=%f\n",
//              equipmentManager->GetLowerDetectorWindowLower(),
//              checkheight2,
//              equipmentManager->GetUpperDetectorWindowUpper());
    return 1;
  }

  // check of validity of flight path of neutron end.
  neutron.judge=1; // valid neutron


  /* information of neutron is set below */
  // Lambda :: wave length of detected neutron
  Double Lambda;
  Lambda=ObtainLamda(nBrag, LtcSpc, qdotn);

  // finEnergy :: energy of detected neutron
  // velocity :: velocity of detected neutron
  Double finEnergy, velocity;
  finEnergy=2.0*PI*PI*(HBAR/Lambda)*(HBAR/Lambda)/MLF_Mn;
  velocity=sqrt(2.0*finEnergy/MLF_Mn);

#ifdef debug
//  std::printf("Lambda=%f (angstrom), |q|=%f (1/angstrom), energy=%f (meV), velocity=%f (mm/s), lengthFlight=%f (m),  tof=%f (micor_s)\n",
//          Lambda*M2ANGSTROM, 2.0*PI/(Lambda*M2ANGSTROM), finEnergy*MLF_J2MEV, velocity*M2MM, lengthFlight, lengthFlight/velocity*SEC2MICROSEC);
#endif

  //thetaDetector :: incident angle to detector
  Double thetaDetector;
  thetaDetector=asin(qfinY/sqrt(qfinX*qfinX+qfinY*qfinY+qfinZ*qfinZ));

  if (thetaDetector<0.0) {
    thetaDetector=-thetaDetector;
  }

#ifdef debug
//  std::printf("thetaDetector=%f\n", thetaDetector);

//  std::printf("%d-th iteratoin are needed for converge\n",j);
#endif

  /* set neutron data to neutron_info */
  neutron.finEnergy=finEnergy;
  neutron.finLambda=Lambda;
  neutron.qoutX=2.0*PI/Lambda*qoutX;
  neutron.qoutY=2.0*PI/Lambda*qoutY;
  neutron.qoutZ=2.0*PI/Lambda*qoutZ;
  neutron.qfinX=2.0*PI/Lambda*qfinX;
  neutron.qfinY=2.0*PI/Lambda*qfinY;
  neutron.qfinZ=2.0*PI/Lambda*qfinZ;
  neutron.tofSD=lengthFlight/velocity;
  neutron.thetaBrag=asin(qdotn);
  neutron.thetaDetector=thetaDetector;

  return 0;
}

/**
 * calculate wavelength of neutron.
 * @param nBragg integer
 * @param LtcSpc distance between atomic planes
 * @param qdotn inner product between wave std::vector of neutron and normal std::vector at reflecting point
 * @return wave length of reflected neutron
 */
Double AdvNeutronManagerDNA::ObtainLamda(int nBrag, Double LtcSpc, Double qdotn){
  Double sinTheta;
  Double Lambda;

  sinTheta=qdotn;
  Lambda=2.0*LtcSpc*sinTheta/nBrag;
  return Lambda;
}

/**
 * calculate phiReflectPos which minimize the length of flight of neutron in terms of phi.
 * @param detPos coordinate of detecting point
 * @param centerPosUpperAnal center of upper analyzer mirror
 * @param centerPosLowerAnal center of lower analyzer mirror
 * @param scaPos coordinate of scattering point
 * @param radius radius of analyzer mirror
 * @param thetaReflectPos polar coordinate of reflecting point
 * @param phiReflectPos polar coordinate of reflecting point
 */
Int4 AdvNeutronManagerDNA::DetPhiRefPos(struct coordinate detPos, struct coordinate centerPosUpperAnal, struct coordinate centerPosLowerAnal,
            struct coordinate scaPos, Double radius, Double thetaReflectPos, Double* phiReflectPos){

  Double dPhiReflectPos;
  Double length1, length2;
  struct coordinate ReflectPosFoward, ReflectPosBackward, ReflectPos;
  Double dfdx1, dfdx2;
  Double length;

  dPhiReflectPos=D_PHI_DEFAULT;

  for (;;) {
/*
    if(rd.y>0.0){
      ReflectPos.z=radius*cos(thetaReflectPos)+centerPosUpperAnal.z;
      ReflectPos.x=radius*sin(thetaReflectPos)*cos(*phiReflectPos)+centerPosUpperAnal.x;
      ReflectPos.y=radius*sin(thetaReflectPos)*sin(*phiReflectPos)+centerPosUpperAnal.y;
    } else {
      ReflectPos.x=radius*sin(thetaReflectPos)*cos(*phiReflectPos)+centerPosLowerAnal.x;
      ReflectPos.y=radius*sin(thetaReflectPos)*sin(*phiReflectPos)+centerPosLowerAnal.y;
      ReflectPos.z=radius*cos(thetaReflectPos)+centerPosLowerAnal.z;
    }
*/

    if (detPos.y>0.0) {
//   std::printf("rd.y is grater than 0\n");
      ReflectPos.x=radius*sin(thetaReflectPos)*sin(*phiReflectPos)+centerPosUpperAnal.x;
      ReflectPos.y=radius*cos(thetaReflectPos)+centerPosUpperAnal.y;
      ReflectPos.z=radius*sin(thetaReflectPos)*cos(*phiReflectPos)+centerPosUpperAnal.z;
    }
    else {
//    std::printf("rd.y is less than 0\n");
      ReflectPos.x=radius*sin(thetaReflectPos)*sin(*phiReflectPos)+centerPosLowerAnal.x;
      ReflectPos.y=radius*cos(thetaReflectPos)+centerPosLowerAnal.y;
      ReflectPos.z=radius*sin(thetaReflectPos)*cos(*phiReflectPos)+centerPosLowerAnal.z;
    }

    length=ReturnDistancePoints(detPos, ReflectPos)+ReturnDistancePoints(scaPos, ReflectPos);

//    std::printf("phiReflectPos=%f, dPhiReflectPos=%f\n", *phiReflectPos, dPhiReflectPos);
//    std::printf("ReflectPos.x=%f, y=%f, z=%f\n", ReflectPos.x, ReflectPos.y, ReflectPos.z);
  //1st derivative

/*
    if(rd.y > 0.0){
      ReflectPosFoward.x=radiusAnal*sin(thetaReflectPos)*cos(*phiReflectPos-dPhiReflectPos)+centerPosUpperAnal.x;
      ReflectPosFoward.y=radiusAnal*sin(thetaReflectPos)*sin(*phiReflectPos-dPhiReflectPos)+centerPosUpperAnal.y;
      ReflectPosFoward.z=radiusAnal*cos(thetaReflectPos)+centerPosUpperAnal.z;
    } else {
      ReflectPosFoward.x=radiusAnal*sin(thetaReflectPos)*cos(*phiReflectPos-dPhiReflectPos)+centerPosLowerAnal.x;
      ReflectPosFoward.y=radiusAnal*sin(thetaReflectPos)*sin(*phiReflectPos-dPhiReflectPos)+centerPosLowerAnal.y;
      ReflectPosFoward.z=radiusAnal*cos(thetaReflectPos)+centerPosLowerAnal.z;
    }
*/


    if (detPos.y>0.0) {
//   std::printf("rd.y is grater than 0\n");
      ReflectPosFoward.x=radius*sin(thetaReflectPos)*sin(*phiReflectPos-dPhiReflectPos)+centerPosUpperAnal.x;
      ReflectPosFoward.y=radius*cos(thetaReflectPos)+centerPosUpperAnal.y;
      ReflectPosFoward.z=radius*sin(thetaReflectPos)*cos(*phiReflectPos-dPhiReflectPos)+centerPosUpperAnal.z;
    }
    else {
//    std::printf("rd.y is less than 0\n");
      ReflectPosFoward.x=radius*sin(thetaReflectPos)*sin(*phiReflectPos-dPhiReflectPos)+centerPosLowerAnal.x;
      ReflectPosFoward.y=radius*cos(thetaReflectPos)+centerPosLowerAnal.y;
      ReflectPosFoward.z=radius*sin(thetaReflectPos)*cos(*phiReflectPos-dPhiReflectPos)+centerPosLowerAnal.z;
    }


    length1=ReturnDistancePoints(detPos, ReflectPosFoward)+ReturnDistancePoints(scaPos, ReflectPosFoward);
    dfdx1=(length1-length)/dPhiReflectPos;

//    std::printf("length1=%f, length=%f, dPhiReflectPos=%f\n", length1, length, dPhiReflectPos);
//
//    std::printf("*phiReflectPos=%f, dPhi=%f, thetaReflectPos=%f\n", *phiReflectPos, dPhiReflectPos, thetaReflectPos);
//    std::printf("ReflectPosFoward.x=%f, y=%f, z=%f\n", ReflectPosFoward.x, ReflectPosFoward.y, ReflectPosFoward.z);

/*
    if(rd.y > 0.0){
      ReflectPosBackward.x=radiusAnal*sin(thetaReflectPos)*cos(*phiReflectPos+dPhiReflectPos)+centerPosUpperAnal.x;
      ReflectPosBackward.y=radiusAnal*sin(thetaReflectPos)*sin(*phiReflectPos+dPhiReflectPos)+centerPosUpperAnal.y;
      ReflectPosBackward.z=radiusAnal*cos(thetaReflectPos)+centerPosUpperAnal.z;
    } else {
      ReflectPosBackward.x=radiusAnal*sin(thetaReflectPos)*cos(*phiReflectPos+dPhiReflectPos)+centerPosLowerAnal.x;
      ReflectPosBackward.y=radiusAnal*sin(thetaReflectPos)*sin(*phiReflectPos+dPhiReflectPos)+centerPosLowerAnal.y;
      ReflectPosBackward.z=radiusAnal*cos(thetaReflectPos)+centerPosLowerAnal.z;
    }
*/

    if (detPos.y>0.0) {
//   std::printf("rd.y is grater than 0\n");
      ReflectPosBackward.x=radius*sin(thetaReflectPos)*sin(*phiReflectPos+dPhiReflectPos)+centerPosUpperAnal.x;
      ReflectPosBackward.y=radius*cos(thetaReflectPos)+centerPosUpperAnal.y;
      ReflectPosBackward.z=radius*sin(thetaReflectPos)*cos(*phiReflectPos+dPhiReflectPos)+centerPosUpperAnal.z;
    }
    else {
//    std::printf("rd.y is less than 0\n");
      ReflectPosBackward.x=radius*sin(thetaReflectPos)*sin(*phiReflectPos+dPhiReflectPos)+centerPosLowerAnal.x;
      ReflectPosBackward.y=radius*cos(thetaReflectPos)+centerPosLowerAnal.y;
      ReflectPosBackward.z=radius*sin(thetaReflectPos)*cos(*phiReflectPos+dPhiReflectPos)+centerPosLowerAnal.z;
    }


    length2=ReturnDistancePoints(detPos, ReflectPosBackward)+ReturnDistancePoints(scaPos, ReflectPosBackward);
    dfdx2=(length-length2)/dPhiReflectPos;

//    std::printf("length1=%f, length=%f, dPhiReflectPos=%f\n", length1, length, dPhiReflectPos);

//    if (-THRESHOLD_NEWTON < dfdx1 && dfdx1 < THRESHOLD_NEWTON){
//      if (-THRESHOLD_NEWTON < dfdx1 && dfdx1 < THRESHOLD_NEWTON){



//    std::printf("ReflectPosBackward.x=%f, y=%f, z=%f\n", ReflectPosBackward.x, ReflectPosBackward.y, ReflectPosBackward.z);

    Double dfdx0;
    dfdx0=(dfdx1+dfdx2)*0.5;

  //2nd derivative
    Double d2fdx2;
    d2fdx2=(dfdx2-dfdx1)/dPhiReflectPos;
//    std::printf("dfdx1=%f, dfdx2=%f, dfdx0=%f\n", dfdx1, dfdx2, dfdx0);
//    std::printf("d2fdx2=%f\n", d2fdx2);

    if (d2fdx2>-THRESHOLD_NEWTON && d2fdx2<THRESHOLD_NEWTON) {
//      std::printf("** renew dPhiReflectPos :: %f\n", dPhiReflectPos);
      dPhiReflectPos=2.0*dPhiReflectPos;
      continue;
    }

//    std::printf("dfdx1=%f, dfdx2=%f, dfdx0=%f, d2fdx2=%f\n", dfdx1, dfdx2, dfdx0, d2fdx2);

    *phiReflectPos=*phiReflectPos-dfdx0/d2fdx2;
    if (*phiReflectPos<0.0) {
      *phiReflectPos+=2.0*PI;
    }
    if (*phiReflectPos>2.0*PI) {
      *phiReflectPos-=2.0*PI;
    }

//    std::printf("length=%f, length1=%f, length2=%f\n", length, length1, length2);
    break;

  }
  return 0;
}

/**
 * calculate thetaReflectPos which minimize the length of flight of neutron in teReflectPoss of thetaReflectPos.
 * @param detPos coordinate of detecting point
 * @param centerPosUpperAnal center of upper analyzer mirror
 * @param centerPosLowerAnal center of lower analyzer mirror
 * @param scaPos coordinate of scattering point
 * @param radiusAnal radius of analyzer mirror
 * @param thetaReflectPos polar coordinate of reflecting point
 * @param phiReflectPos polar coordinate of reflecting point
 */
Int4 AdvNeutronManagerDNA::DetThetaRefPos(struct coordinate detPos, struct coordinate centerPosUpperAnal, struct coordinate centerPosLowerAnal,
              struct coordinate scaPos, Double radius, Double* thetaReflectPos, Double phiReflectPos){

  Double dThetaReflectPos;
  Double length1, length2;
  struct coordinate ReflectPosFoward, ReflectPosBackward, ReflectPos;
  Double dfdx1, dfdx2;
  Double length;

  dThetaReflectPos=D_THETA_DEFAULT;

  for (;;) {
/*
    if( rd.y > 0.0) {
      ReflectPos.x=radiusAnal*sin(*thetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.x;
      ReflectPos.y=radiusAnal*sin(*thetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.y;
      ReflectPos.z=radiusAnal*cos(*thetaReflectPos)+centerPosUpperAnal.z;
    }else{
      ReflectPos.x=radiusAnal*sin(*thetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.x;
      ReflectPos.y=radiusAnal*sin(*thetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.y;
      ReflectPos.z=radiusAnal*cos(*thetaReflectPos)+centerPosLowerAnal.z;
    }
*/

    if (detPos.y>0.0) {
//   std::printf("rd.y is grater than 0\n");
      ReflectPos.x=radius*sin(*thetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.x;
      ReflectPos.y=radius*cos(*thetaReflectPos)+centerPosUpperAnal.y;
      ReflectPos.z=radius*sin(*thetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.z;
    }
    else {
//    std::printf("rd.y is less than 0\n");
      ReflectPos.x=radius*sin(*thetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.x;
      ReflectPos.y=radius*cos(*thetaReflectPos)+centerPosLowerAnal.y;
      ReflectPos.z=radius*sin(*thetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.z;
    }

    length=ReturnDistancePoints(detPos, ReflectPos)+ReturnDistancePoints(scaPos, ReflectPos);

    //1st derivative

/*
    if( rd.y > 0.0) {
      ReflectPosFoward.x=radiusAnal*sin(*thetaReflectPos-dThetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.x;
      ReflectPosFoward.y=radiusAnal*sin(*thetaReflectPos-dThetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.y;
      ReflectPosFoward.z=radiusAnal*cos(*thetaReflectPos-dThetaReflectPos)+centerPosUpperAnal.z;
    } else {
      ReflectPosFoward.x=radiusAnal*sin(*thetaReflectPos-dThetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.x;
      ReflectPosFoward.y=radiusAnal*sin(*thetaReflectPos-dThetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.y;
      ReflectPosFoward.z=radiusAnal*cos(*thetaReflectPos-dThetaReflectPos)+centerPosLowerAnal.z;
    }
*/


    if (detPos.y>0.0) {
//   std::printf("rd.y is grater than 0\n");
      ReflectPosFoward.x=radius*sin(*thetaReflectPos-dThetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.x;
      ReflectPosFoward.y=radius*cos(*thetaReflectPos-dThetaReflectPos)+centerPosUpperAnal.y;
      ReflectPosFoward.z=radius*sin(*thetaReflectPos-dThetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.z;
    }
    else {
//    std::printf("rd.y is less than 0\n");
      ReflectPosFoward.x=radius*sin(*thetaReflectPos-dThetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.x;
      ReflectPosFoward.y=radius*cos(*thetaReflectPos-dThetaReflectPos)+centerPosLowerAnal.y;
      ReflectPosFoward.z=radius*sin(*thetaReflectPos-dThetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.z;
    }


    length1=ReturnDistancePoints(detPos, ReflectPosFoward)+ReturnDistancePoints(scaPos, ReflectPosFoward);
    dfdx1=(length1-length)/dThetaReflectPos;

//    std::printf("ReflectPosFoward.x=%f, y=%f, z=%f\n", ReflectPosFoward.x, ReflectPosFoward.y, ReflectPosFoward.z);

/*
    if( rd.y > 0.0) {
      ReflectPosBackward.x=radiusAnal*sin(*thetaReflectPos+dThetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.x;
      ReflectPosBackward.y=radiusAnal*sin(*thetaReflectPos+dThetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.y;
      ReflectPosBackward.z=radiusAnal*cos(*thetaReflectPos+dThetaReflectPos)+centerPosUpperAnal.z;
    } else {
      ReflectPosBackward.x=radiusAnal*sin(*thetaReflectPos+dThetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.x;
      ReflectPosBackward.y=radiusAnal*sin(*thetaReflectPos+dThetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.y;
      ReflectPosBackward.z=radiusAnal*cos(*thetaReflectPos+dThetaReflectPos)+centerPosLowerAnal.z;
    }
*/

    if (detPos.y>0.0) {
//   std::printf("rd.y is grater than 0\n");
      ReflectPosBackward.x=radius*sin(*thetaReflectPos+dThetaReflectPos)*sin(phiReflectPos)+centerPosUpperAnal.x;
      ReflectPosBackward.y=radius*cos(*thetaReflectPos+dThetaReflectPos)+centerPosUpperAnal.y;
      ReflectPosBackward.z=radius*sin(*thetaReflectPos+dThetaReflectPos)*cos(phiReflectPos)+centerPosUpperAnal.z;
    }
    else {
//    std::printf("rd.y is less than 0\n");
      ReflectPosBackward.x=radius*sin(*thetaReflectPos+dThetaReflectPos)*sin(phiReflectPos)+centerPosLowerAnal.x;
      ReflectPosBackward.y=radius*cos(*thetaReflectPos+dThetaReflectPos)+centerPosLowerAnal.y;
      ReflectPosBackward.z=radius*sin(*thetaReflectPos+dThetaReflectPos)*cos(phiReflectPos)+centerPosLowerAnal.z;
    }

    length2=ReturnDistancePoints(detPos, ReflectPosBackward)+ReturnDistancePoints(scaPos, ReflectPosBackward);
    dfdx2=(length-length2)/dThetaReflectPos;

//    std::printf("ReflectPosBackward.x=%f, y=%f, z=%f\n", ReflectPosBackward.x, ReflectPosBackward.y, ReflectPosBackward.z);

    Double dfdx0;
    dfdx0=(dfdx1+dfdx2)*0.5;

  //2nd derivative
    Double d2fdx2;
    d2fdx2=(dfdx2-dfdx1)/dThetaReflectPos;
//    std::printf("dfdx1=%f, dfdx2=%f, dfdx0=%f\n", dfdx1, dfdx2, dfdx0);
//    std::printf("d2fdx2=%f\n", d2fdx2);

    if (d2fdx2>-THRESHOLD_NEWTON && d2fdx2<THRESHOLD_NEWTON) {
//      std::printf("** renew dThetaReflectPos :: %f\n", dThetaReflectPos);
      dThetaReflectPos=2.0*dThetaReflectPos;
      continue;
    }

    Double value;
    value=dfdx0/d2fdx2;
//    if(value>0.5) value=0.1;
//    if(value<-0.5) value=-0.1;
    *thetaReflectPos=*thetaReflectPos-dfdx0/d2fdx2;
//    std::printf("thetaReflectPos=%f\n", thetaReflectPos);
    if (*thetaReflectPos<0.0) {
      *thetaReflectPos=-*thetaReflectPos;
    }
    if (*thetaReflectPos>PI) {
      *thetaReflectPos=2.0*PI-*thetaReflectPos;
    }
//    std::printf("thetaReflectPos=%f, length=%f, length1=%f, length2=%f\n", *thetaReflectPos, length, length1, length2);
    break;
  }
  return 0;
}

/**
 * calculate distance between two points
 * @param r1 coordinate of point 1
 * @param r2 coordinate of point 2
 */
Double AdvNeutronManagerDNA::ReturnDistancePoints(struct coordinate r1, struct coordinate r2){
  Double length;
  length= sqrt( (r1.x-r2.x)*(r1.x-r2.x)+(r1.y-r2.y)*(r1.y-r2.y)+ (r1.z-r2.z)*(r1.z-r2.z) );
  return length;
}

/**
 * calculate incident energies for neutrons
 *
 * @param[in] startTime start value of TOF
 * @param[in] endTime end value of TOF
 * @param[in] intervalTime interval value of TOF for calculation
 */
Int4 AdvNeutronManagerDNA:: CalcIncEnergies(Double startTime, Double endTime, Double intervalTime){
  // SI unit
  Double time, velocity, energy;
  Int4 iEnd=(Int4) ((endTime-startTime)/intervalTime+0.1)+1;

//  std::printf("startTime=%f, endTime=%f, interval=%f\n", startTime, endTime, intervalTime);

  for (Int4 i=0; i<iEnd; i++) {
    time=startTime+intervalTime*i;
    if (neutron.tofSD>time) {
      continue;
    }
    velocity=L1/(time-neutron.tofSD);
    energy=0.5*MLF_Mn*velocity*velocity; //(J);
/*
    if (energy < neutron.finEnergy) {
      break;
    }
*/
    neutron.tof.push_back(time);
    neutron.tofSS.push_back(time-neutron.tofSD);
    neutron.incEnergy.push_back(energy);
  }
  return 0;
}

/**
 * calculate TOF
 *
 * @param minEnergy minimum energy for neutron
 * @param maxEnergy maxmum energy for neutron
 * @param intervalEnergy interval energy for calculation
 */
Int4 AdvNeutronManagerDNA:: CalcTof(Double minEnergy, Double maxEnergy, Double intervalEnergy){
  //  SI unit
  Double time, velocity, energy;
  Int4 iEnd=(Int4) ((maxEnergy-minEnergy)/intervalEnergy+0.1)+1;

  for (Int4 i=0; i<iEnd; i++) {
    energy=minEnergy+intervalEnergy*i+neutron.finEnergy;
    velocity=sqrt(2.0*energy/MLF_Mn);
    time=L1/velocity;
    neutron.tofSS.push_back(time);
    neutron.tof.push_back(time+neutron.tofSD);
    neutron.incEnergy.push_back(energy);
  }
  return 0;
}

/**
 * return effciency of detector
 *
 * @retval efficiency of detector
 */
Double AdvNeutronManagerDNA:: ReturnEfficiencyDetector(Double epsilon, Double epsilonRatio){
  Double sigmaDtecAbs;
  Double sigmaDtecWallAbs, sigmaDtecWallScat;

  AdvDetectorManagerDNA detector;
  detector.SetIntegThresholdValue(epsilon);
  detector.SetIntegThresholdRatio(epsilonRatio);

  detector.GetSigmas(neutron.finEnergy, &sigmaDtecAbs, &sigmaDtecWallAbs, &sigmaDtecWallScat);


//  std::printf("sigmaDtecAbs=%f, sigmaDtecWallAbs=%f, sigmaDtecWallScat=%f\n",
//          sigmaDtecAbs, sigmaDtecWallAbs, sigmaDtecWallScat);

//  Double efficiency_detector=detector.CalcEfficiencyDetector(neutron.thetaDetector,
//                                             &detPos, sigmaDtecAbs, sigmaDtecWallScat, sigmaDtecWallAbs);

  Double efficiency_detector=detector.CalcEfficiencyDetector(neutron.thetaDetector,
                                             sigmaDtecAbs, sigmaDtecWallScat, sigmaDtecWallAbs);


/*
  std::printf("energy=%e, sig1=%e, sig2=%e, sig3=%e, theta=%e, ef=%e\n",
          neutron.finEnergy, sigmaDtecAbs, sigmaDtecWallAbs, sigmaDtecWallScat,
          neutron.thetaDetector, efficiency_detector);
  exit(1);
*/

  return efficiency_detector;
}
