#include "UtsusemiNeunetEventDecoderDNA.hh"
//////////////////////////////////////////////////////////

const Double UtsusemiNeunetEventDecoderDNA::MASS_NEUTRON    = 1.674928e-27;
const Double UtsusemiNeunetEventDecoderDNA::HBAR            = 1.054571596e-34;
const Double UtsusemiNeunetEventDecoderDNA::THRESHOLD_NEWTON=1.0e-8;
const Double UtsusemiNeunetEventDecoderDNA::THRESHOLD_JUDGE = 1.0e-08;
const Double UtsusemiNeunetEventDecoderDNA::THRESHOLD_ZERO  =1.0e-8;
const Double UtsusemiNeunetEventDecoderDNA::D_PHI_DEFAULT   = 0.0001;
const Double UtsusemiNeunetEventDecoderDNA::D_THETA_DEFAULT = 0.0001;

UtsusemiNeunetEventDecoderDNA::
UtsusemiNeunetEventDecoderDNA():
UtsusemiNeunetEventDecoderBase(){
    _tof_pat_id =0;

    _parserDetInfo = new BoostXmlParser();  /**< XML parser  */
    _parserWirInfo = new BoostXmlParser();  /**< XML parser  */
    _parserChopInfo = new BoostXmlParser(); /**< XML parser  */
    _parserDetInfo->Clear();
    _parserWirInfo->Clear();
    _parserChopInfo->Clear();

    _st = new StringTools();
    _wiring_file   = "";
    _detector_file = "";

    radiusUpperAnal = 2.3;
    radiusLowerAnal = 2.3;
    centerPosUpperAnalx = 0.0;
    centerPosUpperAnaly = 0.102;
    centerPosUpperAnalz = 0.0;
    centerPosLowerAnalx = 0.0;
    centerPosLowerAnaly = -0.102;
    centerPosLowerAnalz = 0.0;
    scaPosx = 0.0;
    scaPosy = 0.0;
    scaPosz = 0.0;
    dthetaDetDeg = 3.0;

    l1           = 42.00;
    lMonitor     = 39.188;
    lChopper     = 10.00;
    lbandChopper =  7.50;

    useFastChopper = false;
}
//////////////////////////////////////////////////////////
UtsusemiNeunetEventDecoderDNA::
~UtsusemiNeunetEventDecoderDNA(){
delete _parserDetInfo;
delete _parserWirInfo;
delete _parserChopInfo;
delete _st;
}
//////////////////////////////////////////////////////////
Int4 UtsusemiNeunetEventDecoderDNA::SetParametersFromFiles( std::string wiring_file, std::string detector_file )
    {
    Int4 ret = UtsusemiNeunetEventDecoderBase::SetParametersFromFiles( wiring_file, detector_file );
    _parserDetInfo->Load(detector_file);
    _parserWirInfo->Load(wiring_file);

    radiusUpperAnal     = GetParamFromXmlFile("detectorInfo/instrumentInfo/","radiusUpperAnal"    ,_parserDetInfo);
    radiusLowerAnal     = GetParamFromXmlFile("detectorInfo/instrumentInfo/","radiusLowerAnal"    ,_parserDetInfo);
    centerPosUpperAnalx = GetParamFromXmlFile("detectorInfo/instrumentInfo/","centerPosUpperAnalx",_parserDetInfo);
    centerPosUpperAnaly = GetParamFromXmlFile("detectorInfo/instrumentInfo/","centerPosUpperAnaly",_parserDetInfo);
    centerPosUpperAnalz = GetParamFromXmlFile("detectorInfo/instrumentInfo/","centerPosUpperAnalz",_parserDetInfo);
    centerPosLowerAnalx = GetParamFromXmlFile("detectorInfo/instrumentInfo/","centerPosLowerAnalx",_parserDetInfo);
    centerPosLowerAnaly = GetParamFromXmlFile("detectorInfo/instrumentInfo/","centerPosLowerAnaly",_parserDetInfo);
    centerPosLowerAnalz = GetParamFromXmlFile("detectorInfo/instrumentInfo/","centerPosLowerAnalz",_parserDetInfo);
    scaPosx      = GetParamFromXmlFile("detectorInfo/instrumentInfo/","scaPosy"     ,_parserDetInfo);
    scaPosy      = GetParamFromXmlFile("detectorInfo/instrumentInfo/","scaPosy"     ,_parserDetInfo);
    scaPosz      = GetParamFromXmlFile("detectorInfo/instrumentInfo/","scaPosz"     ,_parserDetInfo);
    dthetaDetDeg = GetParamFromXmlFile("detectorInfo/instrumentInfo/","dthetaDetDeg",_parserDetInfo);

    //l1           = GetParamFromXmlFile("detectorInfo/instrumentInfo/","L1",_parserDetInfo)/1000.0;
    lMonitor     = GetParamFromXmlFile("detectorInfo/instrumentInfo/","LMonitor",_parserDetInfo)/1000.0;
    lbandChopper = GetParamFromXmlFile("detectorInfo/instrumentInfo/","LBandChopper",_parserDetInfo)/1000.0;
    lChopper     = GetParamFromXmlFile("detectorInfo/instrumentInfo/","LChopper",_parserDetInfo)/1000.0;

    return 0;
    }
//////////////////////////////////////////////////////////
Int4 UtsusemiNeunetEventDecoderDNA::SetChopperParametersFromFiles(  std::string chopper_file )
    {
    useFastChopper = true;
    std::cout << "useFastChopper:" << useFastChopper <<std::endl;
    return 0;
    }
//////////////////////////////////////////////////////////
Double UtsusemiNeunetEventDecoderDNA::GetParamFromXmlFile(std::string basepath,std::string tag,BoostXmlParser *parser)
    {
    Double val;
    std::string mess = " tag is not found / is invalid";
    if (parser->hasPath(basepath+tag))
        {
        std::string s_val = parser->PutContent(basepath+tag);
        if (s_val!="")
            {
            val = stools->StringToDouble(s_val);
            //std::cout << "  " << tag << ":" << val << std::endl;
            return val;
            }
        else
            {
            std::cout << tag+mess <<std::endl;
            }
        }
    else
        {
        std::cout << tag+mess <<std::endl;
        }
    return 0.0;
    }
//////////////////////////////////////////////////////////
void UtsusemiNeunetEventDecoderDNA::
Clear()
    {
    _pixelEfVect.clear();
    _pixelL1Vect.clear();
    _pixelL2Vect.clear();
    _pixelL3Vect.clear();
    _pixelPolarAngleVect.clear();
    _pixelAzimAngleVect.clear();
    _pixelThetaDetectorVect.clear();
    _pixelDThetaDetectorVect.clear();
    _pixelDOmega.clear();
    _pixelTofMax.clear();
    _pixelTofMin.clear();
    _pixelNumOfFrame.clear();
    _pixelT0Detector.clear();
    }
//////////////////////////////////////////////////////////

std::vector<Double> UtsusemiNeunetEventDecoderDNA::
PutHistBin( UInt4 outerPixelId ){
    std::vector<Double> ret;
    ret.clear();

    if (_wirInfo->TofBinInfoList[outerPixelId]==NULL) return ret;
    std::vector<Double>* tofBinInfo = _wirInfo->TofBinInfoList[outerPixelId];

    _tof_pat_id = (UInt4)(tofBinInfo->at(0));
    if (_wirInfo->TofBinPtnInfo[ _tof_pat_id ]==NULL) return ret;

    Int4 tofBinType = _wirInfo->TofBinPtnInfo[ _tof_pat_id ]->type;

    if (tofBinType==27 || tofBinType==28)
        {
        ret=PutHistBinHW(outerPixelId);
        return ret;
        }
    else
        {
        ret=UtsusemiNeunetEventDecoderBase::PutHistBin( outerPixelId );
        return ret;
        }
    }
//////////////////////////////////////////////////////////
std::vector<Double> UtsusemiNeunetEventDecoderDNA::
PutHistBinHW( UInt4 outerPixelId ){
    std::vector<Double> ret;
    ret.clear();

    if (outerPixelId==0)
        {
        std::cout << "UtsusemiNeunetEventDecoderDNA >> PutHistBinHW" << std::endl;
        Clear();
        }

    //Load PixelPosition Parameter From DetectorInfo.xml

    Double pixelSize = GetPixelSize();

    Double OffsetY   = 120.0 + 37.5;
    Double tof_offset_moderator;
    std::vector<Double> pos  = GetPixelPosition(outerPixelId,-OffsetY, 0);
    std::vector<Double> posH = GetPixelPosition(outerPixelId,-OffsetY, pixelSize);
    std::vector<Double> posL = GetPixelPosition(outerPixelId,-OffsetY,-pixelSize);

    std::vector<Double>* pattern = _wirInfo->TofBinPtnInfo[ _tof_pat_id ]->PatternVect;

    Double hw_start, hw_end, hw_delta, Lambda_center, delta_Lambda;
    Double t0_offset_from_wf, LaticeSpace, L1;

    Int4 tofBinType = _wirInfo->TofBinPtnInfo[ _tof_pat_id ]->type;
    std::vector<Double> params=pattern[0];

    if (tofBinType==27)
        {
        hw_start          = params[0];
        hw_end            = params[1];
        hw_delta          = params[2];

        Lambda_center     = params[3]*1e-10;
        delta_Lambda      = params[4]*1e-10;
        t0_offset_from_wf = params[5];
        LaticeSpace       = params[6]*1e-10;
        L1                = params[7]*1e-3; //#[20141208 TY Add mm -> m];
        }
    else if (tofBinType==28)
        {
        Lambda_center     = params[0]*1e-10;
        delta_Lambda      = params[1]*1e-10;
        t0_offset_from_wf = params[2];
        LaticeSpace       = params[3]*1e-10;
        L1                = params[4]*1e-3; //#[20141208 TY Add mm -> m];
        }

    Double L2, L3, Ef, polarAngle, thetaDetector, azimAngle,tmp;
    std::vector<Double> scatPos,sposHVect, sposLVect;
    CalcPhiAnalyzer(pos,  LaticeSpace, L2,  L3,  Ef,  polarAngle, thetaDetector, azimAngle, scatPos  );
    CalcPhiAnalyzer(posH, LaticeSpace, tmp, tmp, tmp, tmp,        tmp,           tmp,       sposHVect);
    CalcPhiAnalyzer(posL, LaticeSpace, tmp, tmp, tmp, tmp,        tmp,           tmp,       sposLVect);
/*
if (outerPixelId==24070 || outerPixelId==5830)
{
std::cout <<"##   ID     ##" <<outerPixelId<<std::endl;
std::cout <<"##   POS    ##" <<pos[0]<<"\t"<<pos[1]<<"\t"<<pos[2]<<std::endl;
std::cout <<"##  L2L3Ef  ##" <<L2<<"\t"<<L3<<"\t"<<Ef<<std::endl;
}
*/
    Double dtheta      = PutDeltaIncidentAngleAtMirrorDNA( pos, sposHVect, sposLVect);
    Double t0_detector = 2286.2869 * ( (L2+L3)/sqrt(Ef) );

    Double dOmega = PutPsdPixelSolidAngleDNA(pos[1], sposHVect, sposLVect);

    Double Lambda_min = Lambda_center - delta_Lambda*0.5;
    Double Lambda_max = Lambda_center + delta_Lambda*0.5;

    Double Emin   = 2.0*M_PI*M_PI*(HBAR/Lambda_max)*(HBAR/Lambda_max)/MLF_Mn*0.624*1e22; //[meV]
    Double Emax   = 2.0*M_PI*M_PI*(HBAR/Lambda_min)*(HBAR/Lambda_min)/MLF_Mn*0.624*1e22; //[meV]

    Double LSC    = 42.00;

    Double tofmin;
    Double tofmax;
    if (useFastChopper){
        tofmin = 2286.2869 * LSC / sqrt(Emax) + 2286.2869 * (L2+L3) / sqrt(Ef); //[usec]
        tofmax = 2286.2869 * LSC / sqrt(Emin) + 2286.2869 * (L2+L3) / sqrt(Ef); //[usec]
        //tofmin = 2286.2869 * (LSC-lChopper) / sqrt(Emax) + 2286.2869 * (L2+L3) / sqrt(Ef); //[usec]
        //tofmax = 2286.2869 * (LSC-lChopper) / sqrt(Emin) + 2286.2869 * (L2+L3) / sqrt(Ef); //[usec]
        }
    else{
        tofmin = 2286.2869 * LSC / sqrt(Emax) + 2286.2869 * (L2+L3) / sqrt(Ef); //[usec]
        tofmax = 2286.2869 * LSC / sqrt(Emin) + 2286.2869 * (L2+L3) / sqrt(Ef); //[usec]
        }

    UInt4 numOfFrame=0;
    while(tofmax>numOfFrame*40000.0)
        {
        numOfFrame+=1;
        }

    std::vector<Double> HW_bin;
    if (tofBinType==27)
        {
        HW_bin=GetArithmeticSequenceVect(hw_start,hw_end,hw_delta);
        }
    else if (tofBinType==28)
        {
        HW_bin=GetUserDefinedVect();
        }

    Double tof_offset_file;
    if (_pixelTOFOffsetFileVect.size()==0)
        {
        tof_offset_file=0;
        }
    else
        {
        tof_offset_file=_pixelTOFOffsetFileVect[outerPixelId];
        }

    for (UInt4 j=0; j<HW_bin.size(); j++)
        {
        //tof_offset_moderator = 92.233*exp(-0.11353*(Ef + HW_bin[j])) + 63.018*(pow((Ef + HW_bin[j]),(-0.45686))); //original
        //tof_offset_moderator = 92.047*exp(-0.11387*(Ef + HW_bin[j])) + 63.124*(pow((Ef + HW_bin[j]),(-0.45727))); //after_itt
        tof_offset_moderator =0;
        Double t0_sample;
        if (useFastChopper)
            {
            //t0_sample = 2286.2869 * (L1-lChopper) / sqrt(Ef + HW_bin[j]) - t0_offset_from_wf - tof_offset_moderator;
            t0_sample = 2286.2869 * L1 / sqrt(Ef + HW_bin[j]) - t0_offset_from_wf - tof_offset_moderator;
            }
        else
            {
            t0_sample = 2286.2869 * L1 / sqrt(Ef + HW_bin[j]) - t0_offset_from_wf - tof_offset_moderator;
            }
        ret.push_back( t0_sample + t0_detector - tof_offset_file);
        }

    if (outerPixelId==5870)
        {
        //for (UInt4 xv=0; xv<ret.size(); xv++)
        //    {
        //    std::cout <<"Hw="<<HW_bin[xv]<<", ret["<<xv<<"]="<<ret[xv]<<std::endl;
        //    }
        std::cout << std::endl;
        //std::cout << "UtsusemiNeunetEventDecoderDNA >> pos      : " << pos[0] <<","<<pos[1]<<","<<pos[2]<<std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> pixelId  : " << outerPixelId << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> Ef       : " << Ef << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> L1       : " << L1 << std::endl;
        std::cout << " (if used high speed chopper, L1 -= Lchopper)"<< std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> L2       : " << L2 << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> L3       : " << L3 << std::endl;

        std::cout << "UtsusemiNeunetEventDecoderDNA >> pa       : " << polarAngle << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> ta       : " << thetaDetector << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> aa       : " << azimAngle << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> sp1       : " << scatPos[0] << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> sp2       : " << scatPos[1] << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> sp3       : " << scatPos[2] << std::endl;

        std::cout << "UtsusemiNeunetEventDecoderDNA >> tofmin   : " << tofmin << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> tofmax   : " << tofmax << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> num fr   : " << numOfFrame << std::endl;
        if(tofBinType==27)
            {
            std::cout << "UtsusemiNeunetEventDecoderDNA >> hw_start : " << hw_start << std::endl;
            std::cout << "UtsusemiNeunetEventDecoderDNA >> hw_end   : " << hw_end << std::endl;
            std::cout << "UtsusemiNeunetEventDecoderDNA >> hw_delta : " << hw_delta << std::endl;
            }

        std::cout << "UtsusemiNeunetEventDecoderDNA >> Lambda_center : " << Lambda_center *1e10<< std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> delta_Lambda  : " << delta_Lambda *1e10<< std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> t0_offset_wf  : " << t0_offset_from_wf << std::endl;

        std::cout << "UtsusemiNeunetEventDecoderDNA >> LaticeSpace   : " << LaticeSpace << std::endl;
        std::cout << "UtsusemiNeunetEventDecoderDNA >> t0_detector   : " << t0_detector << std::endl;
        }

    _pixelEfVect.push_back(Ef);
    _pixelL1Vect.push_back(L1);
    _pixelL2Vect.push_back(L2);
    _pixelL3Vect.push_back(L3);
    _pixelPolarAngleVect.push_back(polarAngle);
    _pixelAzimAngleVect.push_back(azimAngle);
    _pixelThetaDetectorVect.push_back(thetaDetector);
    _pixelDThetaDetectorVect.push_back(dtheta);
    _pixelDOmega.push_back(dOmega);
    _pixelTofMin.push_back(tofmin);
    _pixelTofMax.push_back(tofmax);
    _pixelNumOfFrame.push_back(numOfFrame);
    _pixelT0Detector.push_back(t0_detector);

    return ret;
    }
//////////////////////////////////////////////////////////
Double UtsusemiNeunetEventDecoderDNA::
GetPixelSize(){
    std::vector<Double> pv0=PutPixelPosition(0);
    std::vector<Double> pv1=PutPixelPosition(1);
    Double pixelSize = sqrt((pv0[0]-pv1[0])*(pv0[0]-pv1[0])+(pv0[1]-pv1[1])*(pv0[1]-pv1[1])+(pv0[2]-pv1[2])*(pv0[2]-pv1[2]));

    return pixelSize;
    }
//////////////////////////////////////////////////////////
std::vector<Double> UtsusemiNeunetEventDecoderDNA::
GetPixelPosition(Double outerPixelId,Double offset,Double pixelSize){

    std::vector<Double> pv = PutPixelPosition(outerPixelId);
    std::vector<Double> pos(3);
    pos[0]=pv[0]*0.001;
    if (pv[1]>0)
        {
        pos[1]=(pv[1]+pixelSize*0.50 +offset)*0.001;
        }
    else
        {
        pos[1]=(pv[1]-pixelSize*0.50 -offset)*0.001;
        }
    pos[2]=pv[2]*0.001;

    return pos;
    }
//////////////////////////////////////////////////////////
std::vector<Double> UtsusemiNeunetEventDecoderDNA::
PutXaxis(){

    Int4 tofBinType = _wirInfo->TofBinPtnInfo[ _tof_pat_id ]->type;
    if (tofBinType==27)
        {
        std::vector<Double>* pattern = _wirInfo->TofBinPtnInfo[ _tof_pat_id ]->PatternVect;
        std::vector<Double> params=pattern[0];
        Double hw_start = params[0];
        Double hw_end   = params[1];
        Double hw_delta = params[2];

        std::vector<Double> hw_bin;
        hw_bin.clear();
        hw_bin=GetArithmeticSequenceVect(hw_start,hw_end,hw_delta);

        return hw_bin;
        }
    else if (tofBinType==28)
        {
        std::vector<Double> hw_bin;
        hw_bin.clear();
        hw_bin=GetUserDefinedVect();

        return hw_bin;
        }
    else
        {
            //return _tofBinConv->PutXaxis();
            return UtsusemiNeunetEventDecoderBase::PutXaxis();
        }

    }
//////////////////////////////////////////////////////////
Double UtsusemiNeunetEventDecoderDNA::
PutDeltaIncidentAngleAtMirrorDNA(std::vector<Double> posVect,std::vector<Double> sposHvect, std::vector<Double> sposLvect)
    {
    Double posi0 = posVect[0];
    Double posi1 = posVect[1];
    Double posi2 = posVect[2];
    Double sposiH0 = sposHvect[0];
    Double sposiH1 = sposHvect[1];
    Double sposiH2 = sposHvect[2];
    Double sposiL0 = sposLvect[0];
    Double sposiL1 = sposLvect[1];
    Double sposiL2 = sposLvect[2];

    Double thetaDetectorH = asin((sposiH1-posi1)/sqrt((sposiH0-posi0)*(sposiH0-posi0)+(sposiH1-posi1)*(sposiH1-posi1)+(sposiH2-posi2)*(sposiH2-posi2)));
    Double thetaDetectorL = asin((sposiL1-posi1)/sqrt((sposiL0-posi0)*(sposiL0-posi0)+(sposiL1-posi1)*(sposiL1-posi1)+(sposiL2-posi2)*(sposiL2-posi2)));

    Double dthetaDetector = thetaDetectorH - thetaDetectorL;
    return dthetaDetector;
    }
//////////////////////////////////////////////////////////

Double UtsusemiNeunetEventDecoderDNA::
PutPsdPixelSolidAngleDNA(Double pos1,std::vector<Double> sposHvect, std::vector<Double> sposLvect)
    {

// constant
    //Double radiusUpperAnal = 2.3;
    //Double radiusLowerAnal = 2.3;
    //Double centerPosUpperAnalx = 0.0;
    //Double centerPosUpperAnaly = 0.102;
    //Double centerPosUpperAnalz = 0.0;
    //Double centerPosLowerAnalx = 0.0;
    //Double centerPosLowerAnaly = -0.102;
    //Double centerPosLowerAnalz = 0.0;
    //Double scaPosx = 0.0;
    //Double scaPosy = 0.0;
    Double dthetaDet = dthetaDetDeg*M_PI/180;

// --constant

    Double deltaOmega;

    Double sposiH0 = sposHvect[0];
    Double sposiH1 = sposHvect[1];
    Double sposiH2 = sposHvect[2];
    Double sposiL0 = sposLvect[0];
    Double sposiL1 = sposLvect[1];
    Double sposiL2 = sposLvect[2];

    if(pos1>=0)
        {
        Double LCentorMirrorH = sqrt(pow((sposiH0-centerPosUpperAnalx),2)+pow((sposiH2-centerPosUpperAnalz),2));
        Double LCentorMirrorL = sqrt(pow((sposiL0-centerPosUpperAnalx),2)+pow((sposiL2-centerPosUpperAnalz),2));
        Double angleBetaH = atan((sposiH1-centerPosUpperAnaly)/LCentorMirrorH);
        Double angleBetaL = atan((sposiL1-centerPosUpperAnaly)/LCentorMirrorL);
        Double angleBetaM = (angleBetaH + angleBetaL)*0.5;
        Double deltaArea = pow(radiusUpperAnal,2)*abs(sin(angleBetaL)-sin(angleBetaH))*dthetaDet;
        Double sposiMx = radiusUpperAnal*cos(angleBetaM) + sqrt(pow(centerPosUpperAnalx,2)+pow(centerPosUpperAnalz,2));
        Double sposiMy = radiusUpperAnal*sin(angleBetaM) + centerPosUpperAnaly;
        Double radiusDet2 =pow((sposiMx - scaPosx),2)+pow((sposiMy - scaPosx),2);
        Double angleAlphaM = atan(abs((sposiMy-scaPosy)/(sposiMx-scaPosx)));

        deltaOmega = cos(abs(angleAlphaM-angleBetaM))*deltaArea/radiusDet2;
        }
    else
        {
        Double LCentorMirrorH = sqrt(pow((sposiH0-centerPosLowerAnalx),2)+pow((sposiH2-centerPosLowerAnalz),2));
        Double LCentorMirrorL = sqrt(pow((sposiL0-centerPosLowerAnalx),2)+pow((sposiL2-centerPosLowerAnalz),2));
        Double angleBetaH = atan((sposiH1-centerPosLowerAnaly)/LCentorMirrorH);
        Double angleBetaL = atan((sposiL1-centerPosLowerAnaly)/LCentorMirrorL);
        Double angleBetaM = (angleBetaH + angleBetaL)*0.5;
        Double deltaArea = pow(radiusLowerAnal,2)*abs(sin(angleBetaL)-sin(angleBetaH))*dthetaDet;
        Double sposiMx = radiusLowerAnal*cos(angleBetaM) + sqrt(pow(centerPosLowerAnalx,2)+pow(centerPosLowerAnalz,2));
        Double sposiMy = radiusLowerAnal*sin(angleBetaM) + centerPosLowerAnaly;
        Double radiusDet2 =pow((sposiMx - scaPosx),2)+pow((sposiMy - scaPosx),2);
        Double angleAlphaM = atan(abs((sposiMy-scaPosy)/(sposiMx-scaPosx)));

        deltaOmega = cos(abs(angleAlphaM-angleBetaM))*deltaArea/radiusDet2;
        }
    return deltaOmega;

    // solid angle calculation -end
    /////////////////////////////////////////////
    }


//////////////////////////////////////////////////////////

std::vector<Double> UtsusemiNeunetEventDecoderDNA::
GetArithmeticSequenceVect(Double start, Double end, Double delta)
    {
    std::vector<Double> vect;
    vect.clear();

    if (start>end)
        {
        std::swap(start,end);
        }
    Double x = start - Double(delta)/2.0;
    while( x < end )
        {
        vect.push_back( x );
        x += delta;
        }
    vect.push_back( x );
    reverse(vect.begin(),vect.end());
    return vect;
    }

//////////////////////////////////////////////////////////

std::vector<Double> UtsusemiNeunetEventDecoderDNA::
GetUserDefinedVect()
    {
    std::vector<Double> vect;
    vect.clear();

    std::vector<Double>* pattern = _wirInfo->TofBinPtnInfo[ _tof_pat_id ]->PatternVect;
    std::vector<Double>  params = pattern[0];

    //Double Lambda_center     = params[0]*1e-10;
    //Double delta_Lambda      = params[1]*1e-10;
    //Double t0_offset_from_wf = params[2];
    //Double LaticeSpace       = params[3]*1e-10;
    //Double L1                = params[4];

    UInt4 vectSize = params.size();
    if (vectSize>5)
        {
        for (UInt4 i=5;i<vectSize;i++)
            {
            vect.push_back(params[i]);
            }
        //sort(vect.begin(),vect.end());
        //sort(vect.begin(),vect.end(),greater<Double>());
        reverse(vect.begin(),vect.end());
        }

    return vect;
    }

//////////////////////////////////////////////////////////
UInt4 UtsusemiNeunetEventDecoderDNA::
DecodeEventData( UInt4 daqId, UInt4 modNo, const UChar *data, UInt4 *pixel_id, double *tof, std::vector<Double>* Clock, UInt4 ThNum ){
    UInt4 ret = 0;

    // if given event is neutron event;
    if (*data == _HeaderNeutronEvent)
        {
        if (_prevT0Event[_EventSize*ThNum+0]!=0x00)
            {
            UInt4 moduleNo = (UInt4)(*(_prevT0Event+(_EventSize*ThNum)+2));
            UInt4 det_num = (UInt4)( (*(data+4))&0x7 );


            //if (_wirInfo->PixelInfoStore->at(daqId)->at(moduleNo)->size()<=(2*det_num+1))
            if (_wirInfo->PixelInfoStore->at(daqId)->at(moduleNo)->size()==4)
            {//For Monitori Detector
            return UtsusemiNeunetEventDecoderBase::
                DecodeEventData( daqId, moduleNo, data, pixel_id, tof, Clock, ThNum );
            }
            //-----------------------------------------------------------
            // decode neutron event of NeuNET --start
            UInt4 k = (UInt4)( *(data+6) )/16;
            UInt4 ph_l = (UInt4)( *(data+5) ) * 16 +  k ;
            UInt4 ph_r = (UInt4)( *(data+7) ) + 256 * ( (UInt4( *(data+6) ) )-(k*16) );
            UInt4 tof_clock = (UInt4)( *(data+1) << 16 ) + (UInt4)( *(data+2) << 8 ) + (UInt4)( *(data+3) );
            *tof = tof_clock/40.0; // [micro-sec] tof [0 ~ 400000]
            // decode neutron event of NeuNET --end
            //-----------------------------------------------------------

            std::vector<Int4> *pixel_info1 = NULL;
            std::vector<Int4> *pixel_info2 = NULL;
            // load pixel_info (pixel_id) -- start
            try
                {
                pixel_info1 = _wirInfo->PixelInfoStore->at(daqId)->at(moduleNo)->at(2*det_num);
                pixel_info2 = _wirInfo->PixelInfoStore->at(daqId)->at(moduleNo)->at(2*det_num+1);
                }
            catch(...)
                {
                return ret;
                }
            Int4 det_id1 = (*pixel_info1)[1];
            Int4 det_id2 = (*pixel_info2)[1];
            if (det_id1>=0 && det_id2>0)
                {
                std::vector<Double>* abc1 = _wirInfo->PsdParamsList->at( det_id1 );
                std::vector<Double>* abc2 = _wirInfo->PsdParamsList->at( det_id2 );
                if (abc1!=NULL && abc2!=NULL)
                    {
                    if ( ((ph_l+ph_r)>=(UInt4)((*abc1)[3])) && ((ph_l+ph_r)<=(UInt4)((*abc1)[4])) && ((ph_l+ph_r)>=(UInt4)((*abc2)[3])) && ((ph_l+ph_r)<=(UInt4)((*abc2)[4])) )
                        {

                        Int4 pixel_posi1 = Int4( (*abc1)[0] * (Double)ph_l / ( (Double)ph_r + (*abc1)[1]*(Double)ph_l ) - (*abc1)[2] ); // L1 in ver.02
                        Int4 pixel_posi2 = Int4( (*abc2)[0] * (Double)ph_r / ( (Double)ph_l + (*abc2)[1]*(Double)ph_r ) - (*abc2)[2] ); // L1 in ver.02

                        if (pixel_posi1>=0 && pixel_posi2>=0)
                            {
                            std::vector<Double> *bininfo1 = _wirInfo->PsdBinInfoList[det_id1];
                            std::vector<Double> *bininfo2 = _wirInfo->PsdBinInfoList[det_id2];
                            Int4 pixel;
                            if (pixel_posi1<pixel_posi2)
                                {
                                pixel = (Int4)( (pixel_posi1 - (*bininfo1)[2]) / (*bininfo1)[1] );
                                if ((pixel>=0) && (pixel<=((*pixel_info1)[3]-1)))
                                    {
                                    *pixel_id = (*pixel_info1)[2] + pixel;
                                    if ((*pixel_id)<=_wirInfo->MaxPixelId) ret = _isNeutronEvent;
                                    }
                                }
                            else
                                {
                                pixel = (Int4)( (pixel_posi2 - (*bininfo2)[2]) / (*bininfo2)[1] );
                                if ((pixel>=0) && (pixel<=((*pixel_info2)[3]-1)))
                                    {
                                    *pixel_id = (*pixel_info2)[2] + pixel;
                                    if ((*pixel_id)<=_wirInfo->MaxPixelId) ret = _isNeutronEvent;
                                    }
                                }
                            }
                        }
                    }
                }

            //load pixel_info (pixel_id) -- end
            //-----------------------------------------------------------
            // frame treatment --start
                // minus clock means this frame must be ignored.

            Int4 tofBinType = _wirInfo->TofBinPtnInfo[ _tof_pat_id ]->type;
            if (tofBinType==28 || tofBinType==27)
                {
                UInt4 numOfFrame = _pixelNumOfFrame[*pixel_id];
                Double tofMax = _pixelTofMax[*pixel_id];
                Double tofMin = _pixelTofMin[*pixel_id];
                // Clock->at(0) ~     0 // [micro-sec]
                // Clock->at(1) ~ 40000 // [micro-sec]
                // Clock->at(2) ~ 80000 // [micro-sec]

                if (numOfFrame==0)
                    {
                    *tof = 0;
                    }
                else if ( numOfFrame>1 )
                    {
                    if (( tofMin <= *tof )&&( *tof <= tofMax )) return ret; // std::fixed by YI (210416)
                    if ( *tof + (40000.0*(numOfFrame-1)) < tofMax )
                        {
                        if (Clock->at( numOfFrame -1 )<0) return ret;
                        *tof += Clock->at( numOfFrame -1 );
                        }
                    else
                        {
                        if (Clock->at( numOfFrame -2 )<0) return ret;
                        *tof += Clock->at( numOfFrame -2 );
                        }

                    if (*tof < tofMin)
                        {
                        *tof = 0;
                        }
                    else if (*tof < tofMax)
                        {
                        }
                    else
                        {
                        *tof = 0;
                        }
                    }
                }
            else
                {
                    if (this->_isSetFrameBoundary){
                        UInt4 fno = _wirDict->FrameBoundaryInfoList[(*pixel_id)]->first;
                        Double boundary = _wirDict->FrameBoundaryInfoList[(*pixel_id)]->second;
                        // if no clocks for TOF shifting, return -1 to ignore this frame.
                        if ( *tof < boundary){
                            if (Clock->at( fno -1 )<0) return -1;
                            *tof += Clock->at( fno -1 );
                        }else{
                            if (Clock->at( fno -2 )<0) return -1;
                            *tof += Clock->at( fno -2 );
                        }
                    }
                    /*
                    if ( (_wirInfo->FrameBoundaryInfo.first)>1 ){
                        if ( *tof < (_wirInfo->FrameBoundaryInfo.second) ){
                            if (Clock->at( _wirInfo->FrameBoundaryInfo.first -1 )<0) return ret;
                            *tof += Clock->at( _wirInfo->FrameBoundaryInfo.first -1 );
                        }else{
                            if (Clock->at( _wirInfo->FrameBoundaryInfo.first -2 )<0) return ret;
                            *tof += Clock->at( _wirInfo->FrameBoundaryInfo.first -2 );
                        }
                    }
                    */
                    /*
                UInt4 numOfFrame = _wirInfo->useFrameNo;
                Double tofFrameBoundary = _wirInfo->tofFrameBoundary;
                if ( numOfFrame>1 )
                    {
                    if ( *tof < tofFrameBoundary )
                        {
                        if (Clock->at( numOfFrame -1 )<0) return ret;
                        *tof += Clock->at( numOfFrame -1 );
                        }
                    else
                        {
                        if (Clock->at( numOfFrame -2 )<0) return ret;
                        *tof += Clock->at( numOfFrame -2 );
                        }
                    }
                    */
                }
            // frame treatment --end
            //-----------------------------------------------------------
            }
        }
    // T0 event
    else if (*data == _HeaderT0Event)
        {
        for (UInt4 i=0;i<_EventSize;i++) (*(_prevT0Event+(_EventSize*ThNum)+i))=(*(data+i));
        ret = _isT0Event;
        }
    // Header clock event
    else if (*data == _HeaderClockEvent)
        {
        ret = _isClockEvent;
        }

    return ret;

    }

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

void UtsusemiNeunetEventDecoderDNA::CalcPhiAnalyzer(std::vector<Double> posVect,Double LaticeSpace,Double &L2,Double &L3,Double &Ef,Double &polarAngle,Double &thetaDetector,Double &azimAngle,std::vector<Double> &scatPos)
    {
    std::vector<Double> ret=_CalcPhiAnalyzer( posVect, LaticeSpace);

    L2=ret[0];
    L3=ret[1];
    Ef=ret[2];
    polarAngle=ret[3];
    thetaDetector=ret[4];
    azimAngle=ret[5];

    scatPos.resize(3);
    scatPos[0]=ret[6];
    scatPos[1]=ret[7];
    scatPos[2]=ret[8];
    }
//////////////////////////////////////////////////////////
std::vector<double> UtsusemiNeunetEventDecoderDNA::_CalcPhiAnalyzer(std::vector<Double> posVect, double LaticeSpace)
    {
    Double L2,L3,L2L3;

    std::vector<double> result_param;

    // Double L1= 42.0; /**< Length between moderator and sample */
    Double radiusUpperAnal = 2.3; /**< radius of the upper analyzer mirror */
    Double radiusLowerAnal = 2.3; /**< radius of the lower analyzer mirror */
    struct _coordinate detPos; /**< position of detected  point */
    struct _coordinate scaPos; /**< position of scattered point */
    struct _coordinate centerPosUpperAnal; /**< center position of the sphere of the upper analyzer mirror */
    struct _coordinate centerPosLowerAnal; /**< cneter position of the sphere of the lower analyzer mirror*/
    struct _coordinate zero,unitVect,qfin,qout;
    Double UppLtcSpc = LaticeSpace; /**< distance between atomic surface of the upper analyzer mirror */
    Double LowLtcSpc = LaticeSpace;//1.638e-10; /**< distance between atomic surface of the lower analyzer mirror */

    detPos.x = posVect[0];
    detPos.y = posVect[1];
    detPos.z = posVect[2];
    scaPos.x = scaPosx;
    scaPos.y = scaPosy;
    scaPos.z = scaPosz;
    centerPosUpperAnal.x = centerPosUpperAnalx;
    centerPosUpperAnal.y = centerPosUpperAnaly;
    centerPosUpperAnal.z = centerPosUpperAnalz;
    centerPosLowerAnal.x = centerPosLowerAnalx;
    centerPosLowerAnal.y = centerPosLowerAnaly;
    centerPosLowerAnal.z = centerPosLowerAnalz;

    zero.x=0.0;
    zero.y=0.0;
    zero.z=0.0;

    // 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.
    Double thetaReflectPos, phiReflectPos;
    if (detPos.y>0) thetaReflectPos=M_PI/2-0.1*M_PI;
    else thetaReflectPos=M_PI/2+0.1*M_PI;

    phiReflectPos=atan(detPos.x/detPos.z);
    if (phiReflectPos>0.0 && detPos.z < 0.0) phiReflectPos+=M_PI;
    else if ( phiReflectPos<0.0 && detPos.z < 0.0) phiReflectPos+=M_PI;

    if(phiReflectPos<0.0) phiReflectPos+=2.0*M_PI;

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

    UInt4 i,j;
    Double prePhiReflectPos, initPhiReflectPos;
    Double preThetaReflectPos;
    Double diffPhiReflectPos, diffThetaReflectPos;

    initPhiReflectPos=phiReflectPos;

    Double radius; //radius for the analyzer mirror
    radius=radiusLowerAnal;
    /* 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 axis in the Z-X plane.
        // this is due to escape from numerical error

        // set the reflected position obtained by previous iteration.
        struct _coordinate oldPos = _SphericalCoordinate(detPos.y, radiusUpperAnal, radiusLowerAnal, thetaReflectPos, phiReflectPos, centerPosUpperAnal, centerPosLowerAnal);
        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.
        struct _coordinate renewPos = _SphericalCoordinate(detPos.y, radiusUpperAnal, radiusLowerAnal, thetaReflectPos, phiReflectPos, centerPosUpperAnal, centerPosLowerAnal);

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

        }

    /* check validity of reflected point */
    // qfin.x (qfin.y, qfin.z) is x- (y-, z-) component of unit std::vector of detected-neutron wave std::vector.
    // qout.x (qout.y, qout.z) is x- (y-, z-) component of unit std::vector of scatterd-neutron wave std::vector.
    // unitVect.x (unitVect.y, unitVect.z) is x- (y-, z-) component of unit std::vector of normal std::vector at reflected point.
    // ReflectPos is a reflected position.

    struct _coordinate ReflectPos = _SphericalCoordinate(detPos.y, radiusUpperAnal, radiusLowerAnal, thetaReflectPos, phiReflectPos, centerPosUpperAnal, centerPosLowerAnal);

    /* 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));

    // lengthFligth is a neutron length of flight from sample to detector.
    L3 = _ReturnDistancePoints(detPos, ReflectPos);
    L2 = _ReturnDistancePoints(scaPos, ReflectPos);
    L2L3 = L2+L3;

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

    Double PolarAngle = acos(qout.z/sqrt(qout.x*qout.x+qout.y*qout.y+qout.z*qout.z));
    Double AzimAngle  = acos(qout.x/sqrt(qout.x*qout.x+qout.y*qout.y));
    if (qout.y<0)  AzimAngle = -AzimAngle;

    qout.x /= lengthQ0;
    qout.y /= lengthQ0;
    qout.z /= lengthQ0;

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

    unitVect.x /= lengthN;
    unitVect.y /= lengthN;
    unitVect.z /= lengthN;

    // qdotn is an absolute value of inner product q.n.
    Double qdotn;
    qdotn=qout.x*unitVect.x+qout.y*unitVect.y+qout.z*unitVect.z;
    if (qdotn<0.0) qdotn = -qdotn;

    // qfin is the unit std::vector of detected neutron wave std::vector.
    qfin.x = qout.x + 2.0*qdotn*unitVect.x;
    qfin.y = qout.y + 2.0*qdotn*unitVect.y;
    qfin.z = qout.z + 2.0*qdotn*unitVect.z;

    /* 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=0.625/2.0/sqrt(qout.x*qout.x+qout.z*qout.z)*qout.y;

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

    // finEnergy :: energy of detected neutron
    Double finEnergy     = 2.0*M_PI*M_PI*(HBAR/Lambda)*(HBAR/Lambda)/MLF_Mn;
    Double finEnergy_meV = finEnergy*0.624*1e22;
    //thetaDetector :: incident angle to detector
    Double thetaDetector = asin(qfin.y/sqrt(qfin.x*qfin.x+qfin.y*qfin.y+qfin.z*qfin.z));

    if (thetaDetector<0.0) thetaDetector = -thetaDetector;

    result_param.push_back(L2);
    result_param.push_back(L3);
    result_param.push_back(finEnergy_meV);
    result_param.push_back(PolarAngle);
    result_param.push_back(thetaDetector);
    result_param.push_back(AzimAngle);
    result_param.push_back(ReflectPos.x);
    result_param.push_back(ReflectPos.y);
    result_param.push_back(ReflectPos.z);

    return result_param;
    }

///////////////////// Rutines (theta) //////////////////////
/**
 * calculate thetaReflectPos which minimize the length of flight of neutron in terms of theta.
 * @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 UtsusemiNeunetEventDecoderDNA::_DetThetaRefPos(struct _coordinate detPos, struct _coordinate centerPosUpperAnal, struct _coordinate centerPosLowerAnal,
              struct _coordinate scaPos, Double radius, Double* thetaReflectPos, Double phiReflectPos){

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

    dThetaReflectPos=D_THETA_DEFAULT;

    for (;;) {
        ReflectPos         =  _SphericalCoordinate(detPos.y, radius, radius, *thetaReflectPos, phiReflectPos, centerPosUpperAnal, centerPosLowerAnal);
        length             = _ReturnDistancePoints(detPos, ReflectPos)+_ReturnDistancePoints(scaPos, ReflectPos);

        // 1st derivative
        ReflectPosFoward   = _SphericalCoordinate(detPos.y, radius, radius, *thetaReflectPos-dThetaReflectPos, phiReflectPos, centerPosUpperAnal, centerPosLowerAnal);
        length1            = _ReturnDistancePoints(detPos, ReflectPosFoward)+_ReturnDistancePoints(scaPos, ReflectPosFoward);
        dfdx1              = (length1-length)/dThetaReflectPos;

        ReflectPosBackward = _SphericalCoordinate(detPos.y, radius, radius, *thetaReflectPos+dThetaReflectPos, phiReflectPos, centerPosUpperAnal, centerPosLowerAnal);
        length2            = _ReturnDistancePoints(detPos, ReflectPosBackward)+_ReturnDistancePoints(scaPos, ReflectPosBackward);
        dfdx2              = (length-length2)/dThetaReflectPos;

        Double dfdx0       = (dfdx1+dfdx2)*0.5;

        // 2nd derivative
        Double d2fdx2      = (dfdx2-dfdx1)/dThetaReflectPos;

        if (d2fdx2>-THRESHOLD_NEWTON && d2fdx2<THRESHOLD_NEWTON) {
            dThetaReflectPos    = 2.0*dThetaReflectPos;
            continue;
            }

        *thetaReflectPos    = *thetaReflectPos-dfdx0/d2fdx2;

        if (*thetaReflectPos<0.0) *thetaReflectPos=-*thetaReflectPos;

        if (*thetaReflectPos>M_PI) *thetaReflectPos=2.0*M_PI-*thetaReflectPos;

        break;
        }

    return 0;
    }

///////////////////// Rutines (theta) //////////////////////
/**
 * 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 UtsusemiNeunetEventDecoderDNA::_DetPhiRefPos(struct _coordinate detPos, struct _coordinate centerPosUpperAnal, struct _coordinate centerPosLowerAnal,
            struct _coordinate scaPos, Double radius, Double thetaReflectPos, Double* phiReflectPos){

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

    dPhiReflectPos=D_PHI_DEFAULT;

    for (;;) {
        ReflectPos         = _SphericalCoordinate(detPos.y, radius, radius, thetaReflectPos, *phiReflectPos, centerPosUpperAnal, centerPosLowerAnal);
        length             = _ReturnDistancePoints(detPos, ReflectPos)+_ReturnDistancePoints(scaPos, ReflectPos);

        // 1st derivative
        ReflectPosFoward   = _SphericalCoordinate(detPos.y, radius, radius, thetaReflectPos, *phiReflectPos-dPhiReflectPos, centerPosUpperAnal, centerPosLowerAnal);
        length1            = _ReturnDistancePoints(detPos, ReflectPosFoward)+_ReturnDistancePoints(scaPos, ReflectPosFoward);
        dfdx1              = (length1-length)/dPhiReflectPos;

        ReflectPosBackward = _SphericalCoordinate(detPos.y, radius, radius, thetaReflectPos, *phiReflectPos+dPhiReflectPos, centerPosUpperAnal, centerPosLowerAnal);
        length2            = _ReturnDistancePoints(detPos, ReflectPosBackward)+_ReturnDistancePoints(scaPos, ReflectPosBackward);
        dfdx2              = (length-length2)/dPhiReflectPos;

        Double dfdx0       = (dfdx1+dfdx2)*0.5;

        // 2nd derivative
        Double d2fdx2      = (dfdx2-dfdx1)/dPhiReflectPos;

        if (d2fdx2>-THRESHOLD_NEWTON && d2fdx2<THRESHOLD_NEWTON) {
            dPhiReflectPos=2.0*dPhiReflectPos;
            continue;
            }

        *phiReflectPos=*phiReflectPos-dfdx0/d2fdx2;

        if (*phiReflectPos<0.0) *phiReflectPos+=2.0*M_PI;

        if (*phiReflectPos>2.0*M_PI) *phiReflectPos-=2.0*M_PI;

        break;
    }
    return 0;
    }
//////////////////////////////////////////////////////////
/**
 * calculate distance between two points
 * @param r1 _coordinate of point 1
 * @param r2 _coordinate of point 2
 */
Double UtsusemiNeunetEventDecoderDNA::_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 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 UtsusemiNeunetEventDecoderDNA::_ObtainLambda(int nBrag, Double LtcSpc, Double qdotn)
    {
    Double sinTheta;
    Double Lambda;

    sinTheta=qdotn;
    Lambda=2.0*LtcSpc*sinTheta/nBrag;
    return Lambda;
    }
//////////////////////////////////////////////////////////
struct _coordinate UtsusemiNeunetEventDecoderDNA::_SphericalCoordinate(Double yposition, Double radius_up, Double radius_down, Double theta, Double phi, struct _coordinate r2, struct _coordinate r3)
    {
    struct _coordinate r1;
    if (yposition>0.0) {
       r1.x = radius_up*sin(theta)*sin(phi)+r2.x;
       r1.y = radius_up*cos(theta)         +r2.y;
       r1.z = radius_up*sin(theta)*cos(phi)+r2.z;
    }
    else {
       r1.x = radius_down*sin(theta)*sin(phi)+r3.x;
       r1.y = radius_down*cos(theta)         +r3.y;
       r1.z = radius_down*sin(theta)*cos(phi)+r3.z;
    }
    return r1;
    }
