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

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


AdvDetectorManagerDNA:: AdvDetectorManagerDNA(void){
  if (!(isReady())) {
    UtsusemiError("AdvDetectorManagerDNA >> Error Initializing (Maybe not found atomic data file).");
    return;
  }
        //std::string filepath = getenv("HOME");
  std::string filepath = UtsusemiEnvGetUserDir();
  std::string filename = "detector_data.dat";
        //filepath += "/ana/setup/";
  filepath += "/ana/DNA/setup/";
  filepath += filename;

//  filename="/home/dnaadmin/00Install/work.DNA/correction/detector_data.dat";
  std::cout << "detector_data_filepath = " <<filepath <<std::endl;


//AdvDetectorManagerDNA:: AdvDetectorManagerDNA(std::string& nistDataBaseFile, std::string& detectorDataFile) : ScatAbsoBase(nistDataBaseFile) {
  //filename=detectorDataFile;
  wallInfo.initialize();
  detectorInfo.initialize();

  SetInfoData(filepath, &wallInfo, &detectorInfo);
  wallInfo.totalDensity=wallInfo.weightPerVolume*MLF_KG2G/wallInfo.effectiveAtomicWeight*MLF_NA;
  detectorInfo.totalDensity=detectorInfo.gasPressure*MLF_ATM2PA/kB/detectorInfo.temperature; // SI unit

/*
  prUint4f("detector_info.total_density=%e\n", detector_info.total_density);
  prUint4f("effective atomic weight for wall = %f\n", wall_info.effective_atomic_weight);
  prUint4f("effective atomic weight for body = %f\n", detector_info.effective_atomic_weight);
  prUint4f("wall :: atomic weight = %f\n", wall_info.effective_atomic_weight);
  prUint4f("wall :: weight_per_volume = %f\n", wall_info.weight_per_volume);
  prUint4f("cof :: %f\n", 1.e+03*MLF_NA);
  prUint4f("density of wall = %e\n", wall_info.total_density);

  fflush(stdout);

// test test test
  std::printf("detector_info\n");
  std::printf("form-type=%d\n", detector_info.form);
  std::printf("rl=%f, rs=%f, height=%f\n", detector_info.rl, detector_info.rs, detector_info.height);
  for(int i=0; i<detector_info.atomname.size();i++){
    std::printf("%d-th atom name :: %s, density ::%f\n", i, detector_info.atomname[i].c_str(), detector_info.atomdensity[i]);
  }
  std::printf("ratio_T=%f, temperature=%f, gas_pressure=%f\n", detector_info.ratio_T, detector_info.temperature, detector_info.gas_pressure);
  std::printf("weight_per_volume=%f, total_density=%f\n", detector_info.weight_per_volume, detector_info.total_density);

  std::printf("wall_info\n");
  std::printf("form-type=%d\n", wall_info.form);
  std::printf("wall rl=%f, rs=%f, height=%f\n", wall_info.rl, wall_info.rs, wall_info.height);
  for(int i=0; i<wall_info.atomname.size();i++){
    std::printf("%d-th atom name :: %s, density ::%f\n", i, wall_info.atomname[i].c_str(), wall_info.atomdensity[i]);
  }
  std::printf("ratio_T=%f, temperature=%f, gas_pressure=%f\n", wall_info.ratio_T, wall_info.temperature, wall_info.gas_pressure);
  std::printf("weight_per_volume=%f, total_density=%f\n", wall_info.weight_per_volume, wall_info.total_density);

  fflush(stdout);
*/

  epsilon=1.0e-05;
  epsilonRatio=1.0e-04;

}

AdvDetectorManagerDNA:: AdvDetectorManagerDNA(std::string filepath){
  if (!(isReady())) {
    UtsusemiError("AdvDetectorManagerDNA >> Error Initializing (Maybe not found atomic data file).");
    return;
  }
  wallInfo.initialize();
  detectorInfo.initialize();

  std::cout << "detector_data_filepath = " <<filepath <<std::endl;

  SetInfoData(filepath, &wallInfo, &detectorInfo);
  wallInfo.totalDensity=wallInfo.weightPerVolume*MLF_KG2G/wallInfo.effectiveAtomicWeight*MLF_NA;
  detectorInfo.totalDensity=detectorInfo.gasPressure*MLF_ATM2PA/kB/detectorInfo.temperature; // SI unit


  epsilon=1.0e-05;
  epsilonRatio=1.0e-04;

}

AdvDetectorManagerDNA:: ~AdvDetectorManagerDNA(void){
}

void AdvDetectorManagerDNA:: GetSigmas(Double energy, Double* sigmaDA, Double* sigmaWA, Double* sigmaWS){
  GetSigmaFromVelocityRule(&wallInfo, &detectorInfo, energy, &sigmaDetectorA, &sigmaWallA, &sigmaWallS);
  *sigmaDA=sigmaDetectorA;
  *sigmaWA=sigmaWallA;
  *sigmaWS=sigmaWallS;
}

Double AdvDetectorManagerDNA :: GetSigmaDA(Double energyNeutron){
  Double energy=energyNeutron*MLF_MEV2J;
  Double velocity=sqrt(2.0*energy/MLF_Mn);
  Double sigmaDA=0.0;

//  std::printf("detectorInfo.atomname.size()=%d\n", detectorInfo.atomname.size());
  for (UInt4 i=0; i<detectorInfo.atomname.size(); i++){
//    std::printf("i=%d\n");fflush(stdout);
//    std::printf("atomDensityRatio=%e\n", detectorInfo.atomDensityRatio[i]);fflush(stdout);
//    std::printf("atomname=%s\n", detectorInfo.atomname[i]);fflush(stdout);
//    std::printf("velocity=%e\n",velocity);fflush(stdout);
//    std::printf("getAtomSigma=%d\n", GetAtomSigmaFromVelocityRule(detectorInfo.atomname[i], 'a', velocity)); fflush(stdout);
    sigmaDA+=detectorInfo.atomDensityRatio[i]*GetAtomSigmaFromVelocityRule(detectorInfo.atomname[i], 'a', velocity);
  }
//  std::printf("sigmaDA=%d\n", sigmaDA);
  return sigmaDA;
}

Double AdvDetectorManagerDNA :: GetSigmaWA(Double energyNeutron){
  Double energy=energyNeutron*MLF_MEV2J;
  Double velocity=sqrt(2.0*energy/MLF_Mn);
  Double sigmaWA=0.0;
  for (UInt4 i=0; i<wallInfo.atomname.size(); i++){
    sigmaWA+=wallInfo.atomDensityRatio[i]*GetAtomSigmaFromVelocityRule(wallInfo.atomname[i], 'a', velocity);

  }
  return sigmaWA;
}

Double AdvDetectorManagerDNA :: GetSigmaWS(Double energyNeutron){
  Double energy=energyNeutron*MLF_MEV2J;
  Double velocity=sqrt(2.0*energy/MLF_Mn);
  Double sigmaWS=0.0;
  for (UInt4 i=0; i<wallInfo.atomname.size(); i++){
    sigmaWS+=wallInfo.atomDensityRatio[i]*GetAtomSigmaFromVelocityRule(wallInfo.atomname[i], 's', velocity);
  }
  return sigmaWS;
}

Double AdvDetectorManagerDNA:: GetEfficiency(Double eneNeutron, Double thetaDetector){
  Double sigmaDA, sigmaWA, sigmaWS;
  Double energy=eneNeutron*MLF_MEV2J;
//  Double theta=thetaDetector*MLF_DEGREE2RADIAN;
  GetSigmas(energy, &sigmaDA, &sigmaWA, &sigmaWS);
//  struct coordinate detPos;
//  detPos.x=detPos.y=detPos.z=0.0;
  return CalcEfficiencyDetector(thetaDetector, sigmaDA, sigmaWS, sigmaWA);
}

void AdvDetectorManagerDNA:: MakeTable(Double inputMinEnergy, Double inputMaxEnergy, UInt4 devnum, Double inputThetaDetector, ElementContainer& ec){
//void AdvDetectorManagerDNA:: MakeTable(Double inputMinEnergy, Double inputMaxEnergy, UInt4 devnum, Double inputThetaDetector){
  Double minEnergy;
  Double maxEnergy;
  Double thetaDetector;
  if (inputMinEnergy <= inputMaxEnergy){
    minEnergy=inputMinEnergy*MLF_MEV2J;
    maxEnergy=inputMaxEnergy*MLF_MEV2J;
  } else {
    minEnergy=inputMaxEnergy*MLF_MEV2J;
    maxEnergy=inputMinEnergy*MLF_MEV2J;
  }
  thetaDetector=inputThetaDetector*MLF_DEGREE2RADIAN;

  Double lambdaMax=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/minEnergy);
  Double lambdaMin=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/maxEnergy);

  Double lambda0=lambdaMax;

  Double ratio=0.1; // in the case of 4-th order Tayler expansion and error is less than 1e-05
  Double deltaLambda;
  Double energy0;
  Double i0, i1, i2, i3, i4;

  std::vector <Double> lambdaList;
  std::vector <Double> i0List;
  std::vector <Double> i1List;
  std::vector <Double> i2List;
  std::vector <Double> i3List;
  std::vector <Double> i4List;

  FILE* fp=fopen("testintegdata.dat", "w");

 std::fprintf(fp, "%12s %12s %12s %12s %12s %12s %12s\n", "energy [meV]", "lamda0", "i0", "i1", "i2", "i3", "i4");
  while (lambda0>lambdaMin){
    deltaLambda=ratio*lambda0;
    lambda0/=(1.0+ratio);
    energy0=2.0*PI*PI*HBAR*HBAR/MLF_Mn/lambda0/lambda0;
    GetCorrectionTableLambda(energy0, inputThetaDetector, &i0, &i1, &i2, &i3, &i4);
   std::fprintf(fp, "%12.6e %12.6e  %12.6e  %12.6e  %12.6e  %12.6e  %12e\n", energy0*MLF_J2MEV, lambda0, i0, i1, i2, i3, i4);
    //fstd::printf(fp, "%e %e  %e  %e  %e  %e  %e\n", energy0*MLF_J2MEV, lambda0, i0, i1, i2, i3, i4);
    lambdaList.push_back(lambda0);
    i0List.push_back(i0);
    i1List.push_back(i1);
    i2List.push_back(i2);
    i3List.push_back(i3);
    i4List.push_back(i4);
    lambda0-=deltaLambda;
  }
  fclose(fp);

  fp=fopen("testCoeffResultData.dat", "w");
 std::fprintf(fp, "%s %s %s\n", "energy", "Theta", "efficincy");

  Double dE=(maxEnergy-minEnergy)/devnum;

  std::vector<Double> energyBin = *(new std::vector<Double>(devnum+1));
  for(UInt4 i=0; i<=devnum; i++) {
      energyBin.at(i) = minEnergy+i*dE;
  }
  std::vector<Double> efficiency = *(new std::vector<Double>(devnum));
  std::vector<Double> dummy      = *(new std::vector<Double>(devnum, 0.0));

  Double lambda;
  Double f;
  //int i, j;
  int place;
  for(UInt4 i=0; i<devnum; i++){
    Double energy=minEnergy+i*dE;
    lambda=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/energy);
    place=-1;
    for(UInt4 j=0; j<lambdaList.size(); j++){
      if(lambda>=lambdaList[j]){
        place=j;
        break;
      }
    }
    if(place==-1){
      place=lambdaList.size()-1;
    }
    if(place>0){
      if(lambdaList[place-1]-lambda<lambda-lambdaList[place]) {
        place-=1;
      }
    }
    lambda0=lambdaList[place];
    energy0=2.0*PI*PI*HBAR*HBAR/MLF_Mn/lambda0/lambda0;
    energy*=MLF_J2MEV;
    energy0*=MLF_J2MEV;
    f=GetCorrectEff4(energy0, inputThetaDetector, energy-energy0,
                     i0List[place], i1List[place], i2List[place], i3List[place], i4List[place]);
   std::fprintf(fp, "%f %f %f\n", energy, inputThetaDetector, f);
    efficiency.at(i) = f;
  }
  fclose(fp);

  ec.AddToHeader("theta", inputThetaDetector);
  ec.Add("energy", energyBin, "meV");
  ec.Add("efficiency", efficiency);
  ec.Add("dummy", dummy);
  ec.SetKeys("energy", "efficiency", "dummy");
}

PyObject*  AdvDetectorManagerDNA:: GetCorrectIntensityFromPython(PyObject *inputPyEnergyList, PyObject *inputPyIntensityList, Double inputThetaDetector){

//  std::printf("GetCorerctionIntensity pre \n"); fflush(stdout);

  std::vector< Double > inputEnergyList = __gCppToPython.ListToDoubleVector( inputPyEnergyList );
  std::vector< Double > inputIntensityList = __gCppToPython.ListToDoubleVector( inputPyIntensityList );

  std::vector< Double > correctIntensityList;

/*
  std::printf("write inputEnergy List\n");
  std::printf(" num of list = %d\n", inputEnergyList.size());
  for(int i=0; i<inputEnergyList.size(); i++){
    std::printf("%d :: value = %f\n", inputEnergyList[i]);
  }

  std::printf("write inputIntensity List\n");
  std::printf(" num of list = %d\n", inputIntensityList.size());
  for(int i=0; i<inputIntensityList.size(); i++){
    std::printf("%d :: value = %f\n", inputIntensityList[i]);
  }
*/

  fflush(stdout);

  correctIntensityList = GetCorrectIntensity(inputEnergyList, inputIntensityList, inputThetaDetector);


  PyObject *returnCorrectIntensityList=__gCppToPython.VectorDoubleToList(correctIntensityList);


  return returnCorrectIntensityList;
}





std::vector<Double>  AdvDetectorManagerDNA:: GetCorrectIntensity(std::vector<Double> inputEnergyList, std::vector<Double> inputIntensityList, Double inputThetaDetector){

//  std::printf("GetCorerctionIntensity\n"); fflush(stdout);

  //int i, j;
  std::vector<Double> energyList;

//  std::printf("GetCorerctionIntensity0-0-1\n"); fflush(stdout);

/*
  for(i=0; i<inputEnergyList.size()-1; i++){
    if(i<10)
    std::printf("inputEnergy[%d]=%e, initensity=%e\n", i, (Double) inputEnergyList[i], inputIntensityList[i]); fflush(stdout);
  }
*/

  for(UInt4 i=0; i<inputEnergyList.size()-1; i++){
//    std::printf("%d:: GetCorerctionIntensity0-0-1-before\n", i); fflush(stdout);

//    energyList[i]=0.5*(inputEnergyList[i]+inputEnergyList[i+1]);
    energyList.push_back(0.5*(inputEnergyList[i]+inputEnergyList[i+1]));


//    std::printf("GetCorerctionIntensity0-0-1-end\n"); fflush(stdout);

  }

//  std::printf("GetCorerctionIntensity0-1\n"); fflush(stdout);

  Double minEnergy;
  Double maxEnergy;
  UInt4  numEne;

  minEnergy=1.e+31;
  maxEnergy=-1.e+31;
  numEne=energyList.size();

//  std::printf("GetCorerctionIntensity0-2\n"); fflush(stdout);


  for(UInt4 i=0; i<numEne; i++){
    if (minEnergy>energyList[i]) {
      minEnergy=energyList[i];
    }
    if (maxEnergy<energyList[i]) {
      maxEnergy=energyList[i];
    }
  }
  minEnergy=minEnergy*MLF_MEV2J;
  maxEnergy=maxEnergy*MLF_MEV2J;

//  std::printf("GetCorerctionIntensity0-3\n"); fflush(stdout);

  Double thetaDetector;
  thetaDetector=inputThetaDetector*MLF_DEGREE2RADIAN;

  Double lambdaMax=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/minEnergy);
  Double lambdaMin=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/maxEnergy);

  Double lambda0=lambdaMax;

//  Double ratio=0.1; // in the case of 4-th order Tayler expansion and error is less than 1e-05
  Double ratio=0.1;
  Double deltaLambda;
  Double energy0;
  Double i0, i1, i2, i3, i4;

  std::vector <Double> lambdaList;
  std::vector <Double> i0List;
  std::vector <Double> i1List;
  std::vector <Double> i2List;
  std::vector <Double> i3List;
  std::vector <Double> i4List;

//  std::printf("GetCorerctionIntensity0-4\n"); fflush(stdout);


  FILE* fp=fopen("testintegdata.dat", "w");  //write for debug. not necessary.

//  std::printf("GetCorerctionIntensity1\n"); fflush(stdout);


  while (lambda0>lambdaMin){
    deltaLambda=ratio*lambda0;
    lambda0/=(1.0+ratio);
    energy0=2.0*PI*PI*HBAR*HBAR/MLF_Mn/lambda0/lambda0;
    GetCorrectionTableLambda(energy0, inputThetaDetector, &i0, &i1, &i2, &i3, &i4);
   std::fprintf(fp, "%e %e  %e  %e  %e  %e  %e\n", energy0*MLF_J2MEV, lambda0, i0, i1, i2, i3, i4);
    lambdaList.push_back(lambda0);
    i0List.push_back(i0);
    i1List.push_back(i1);
    i2List.push_back(i2);
    i3List.push_back(i3);
    i4List.push_back(i4);
    lambda0-=deltaLambda;
  }
  fclose(fp);

  std::vector<Double> CorrectIntensityList;
  Double correctIntensity;

  fp=fopen("testCoeffResultData.dat", "w"); // write for debug, not necessary

//  std::printf("GetCorerctionIntensity2\n"); fflush(stdout);

  Double lambda;
  Double f;
  int place;
  for(UInt4 i=0; i<numEne; i++){
    Double energy=energyList[i]*MLF_MEV2J;
    lambda=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/energy);
    place=-1;
    for(UInt4 j=0; j<lambdaList.size(); j++){
      if(lambda>=lambdaList[j]){
        place=j;
        break;
      }
    }
    if(place==-1){
      place=lambdaList.size()-1;
    }
    if(place>0){
      if(lambdaList[place-1]-lambda<lambda-lambdaList[place]) {
        place-=1;
      }
    }
    lambda0=lambdaList[place];
    energy0=2.0*PI*PI*HBAR*HBAR/MLF_Mn/lambda0/lambda0;
    energy*=MLF_J2MEV;
    energy0*=MLF_J2MEV;
    f=GetCorrectEff4(energy0, inputThetaDetector, energy-energy0,
                     i0List[place], i1List[place], i2List[place], i3List[place], i4List[place]);
   std::fprintf(fp, "%e %e %e\n", energy, inputThetaDetector, f);

    correctIntensity=inputIntensityList[i]/f;
    CorrectIntensityList.push_back(correctIntensity);

  }
  fclose(fp);

//  std::printf("GetCorerctionIntensity3\n"); fflush(stdout);

  return CorrectIntensityList;

}


void AdvDetectorManagerDNA:: MakeTableTheta(Double inputMinTheta, Double inputMaxTheta, UInt4 devnum, Double inputEnergy, ElementContainer& ec){
//void AdvDetectorManagerDNA:: MakeTableTheta(Double inputMinTheta, Double inputMaxTheta, UInt4 devnum, Double inputEnergy){
  Double minTheta;
  Double maxTheta;
  Double energy;

//  std::printf("begin\n"); fflush(stdout);

  if (inputMinTheta <= inputMaxTheta){
    minTheta=inputMinTheta*MLF_DEGREE2RADIAN;
    maxTheta=inputMaxTheta*MLF_DEGREE2RADIAN;
  } else {
    minTheta=inputMaxTheta*MLF_DEGREE2RADIAN;
    maxTheta=inputMinTheta*MLF_DEGREE2RADIAN;
  }
  energy=inputEnergy*MLF_MEV2J;

//  std::printf("energy=%e\n", energy); fflush(stdout);

//  Double lambdaMax=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/minEnergy);
//  Double lambdaMin=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/maxEnergy);

//  Double lambda0=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/energy);

  Double ratio=0.1; // in the case of 4-th order Tayler expansion and error is less than 1e-05

  Double deltaTheta;
  Double theta0=maxTheta;
  Double i0, i1, i2, i3, i4;

  std::vector <Double> thetaList;
  std::vector <Double> i0List;
  std::vector <Double> i1List;
  std::vector <Double> i2List;
  std::vector <Double> i3List;
  std::vector <Double> i4List;

  FILE* fp=fopen("testthetaintegdata.dat", "w");

//  std::printf("begin while\n"); fflush(stdout);


  while (theta0>minTheta){
    deltaTheta=ratio;
//    deltaTheta=ratio*cos(theta0);
    //theta0/=(1.0+ratio);
    theta0-=ratio;
    //energy0=2.0*PI*PI*HBAR*HBAR/MLF_Mn/lambda0/lambda0;
    Double thetaDetector=theta0*MLF_RADIAN2DEGREE;

//    std::printf("before GetCorrectionLamdba\n"); fflush(stdout);

    GetCorrectionTableTheta(energy, thetaDetector, &i0, &i1, &i2, &i3, &i4);

//    std::printf("end GetCorrectionLamda\n"); fflush(stdout);

   std::fprintf(fp, "%e  %e  %e  %e  %e  %e\n", thetaDetector, i0, i1, i2, i3, i4);
    thetaList.push_back(theta0);
    i0List.push_back(i0);
    i1List.push_back(i1);
    i2List.push_back(i2);
    i3List.push_back(i3);
    i4List.push_back(i4);
    theta0-=deltaTheta;
  }
  fclose(fp);

  fp=fopen("testThetaCoeffResultData.dat", "w");

  Double dTheta=(minTheta-maxTheta)/devnum;

  std::vector<Double> angle = *(new std::vector<Double>(devnum+1));
  for(UInt4 i=0; i<devnum; i++){
      angle.at(i) = maxTheta+i*dTheta;
  }
  std::vector<Double> efficiency = *(new std::vector<Double>(devnum));
  std::vector<Double> dummy      = *(new std::vector<Double>(devnum, 0.0));
//  Double theta;
  Double f;
  //int i, j;
  int place;
  for(UInt4 i=0; i<devnum; i++){
    Double theta=maxTheta+i*dTheta;
    //lambda=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/energy);
    place=-1;
    for(UInt4 j=0; j<thetaList.size(); j++){
      if(theta>=thetaList[j]){
        place=j;
        break;
      }
    }
    if(place==-1){
      place=thetaList.size()-1;
    }
    if(place>0){
      if(thetaList[place-1]-theta<theta-thetaList[place]) {
        place-=1;
      }
    }
    theta0=thetaList[place];
//    energy0=2.0*PI*PI*HBAR*HBAR/MLF_Mn/lambda0/lambda0;
//    energy*=MLF_J2MEV;
//    energy0*=MLF_J2MEV;

    Double inputThetaDetector=theta0*MLF_RADIAN2DEGREE;

//    std::printf("%d-th data :: theta0=%f, theta=%f\n", place, theta0*MLF_RADIAN2DEGREE, theta*MLF_RADIAN2DEGREE);
    f=GetCorrectThetaEff4(energy, inputThetaDetector, (theta-theta0)*MLF_RADIAN2DEGREE,
                     i0List[place], i1List[place], i2List[place], i3List[place], i4List[place]);
    double ftest=GetCorrectThetaEff2(energy, inputThetaDetector, (theta-theta0)*MLF_RADIAN2DEGREE,
                     i0List[place], i1List[place], i2List[place], i3List[place], i4List[place]);

   std::fprintf(fp, "%f %f %12.10f %12.10f\n", inputEnergy, theta*MLF_RADIAN2DEGREE, f, ftest);
    efficiency.at(i)=f;
  }
  fclose(fp);

  ec.AddToHeader("energy", inputEnergy);
  ec.Add("theta", angle, "degree");
  ec.Add("efficiency", efficiency);
  ec.Add("dummy", dummy);
  ec.SetKeys("theta", "efficiency", "dummy");
}

void AdvDetectorManagerDNA:: GetCorrectionTableLambda(Double eneNeutron, Double thetaDetector,
                                             Double* i0, Double* i1, Double* i2, Double*i3, Double* i4){
  Double sigmaDA, sigmaWA, sigmaWS;
  Double energy=eneNeutron;
//  Double theta=thetaDetector*MLF_DEGREE2RADIAN;
  GetSigmas(eneNeutron, &sigmaDA, &sigmaWA, &sigmaWS);

  energy=eneNeutron;
  Double lambda0=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/energy);

//  struct coordinate detPos;
//  detPos.x=detPos.y=detPos.z=0.0;
  UInt4 coefNum;
  coefNum=0;
  *i0=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=1;
  *i1=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=2;
  *i2=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=3;
  *i3=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=4;
  *i4=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);

}


void AdvDetectorManagerDNA:: GetCorrectionTableTheta(Double eneNeutron, Double thetaDetector,
                                             Double* i0, Double* i1, Double* i2, Double*i3, Double* i4){
  Double sigmaDA, sigmaWA, sigmaWS;
  Double energy=eneNeutron;
//  Double theta=thetaDetector*MLF_DEGREE2RADIAN;
  GetSigmas(eneNeutron, &sigmaDA, &sigmaWA, &sigmaWS);

  Double lambda0=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/energy);
//  struct coordinate detPos;
//  detPos.x=detPos.y=detPos.z=0.0;
  UInt4 coefNum;
  coefNum=0;
  *i0=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=5;
  *i1=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=6;
  *i2=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=7;
  *i3=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=8;
  *i4=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);

}







Double AdvDetectorManagerDNA:: GetEfficiencyTable(Double eneNeutron, Double thetaDetector){
  Double sigmaDA, sigmaWA, sigmaWS;
  Double energy=eneNeutron*MLF_MEV2J;
//  Double theta=thetaDetector*MLF_DEGREE2RADIAN;
  GetSigmas(energy, &sigmaDA, &sigmaWA, &sigmaWS);

  Double lambda0=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/energy);

//  struct coordinate detPos;
//  detPos.x=detPos.y=detPos.z=0.0;
  UInt4 coefNum;
  coefNum=0;
  Double i0=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=1;
  Double i1=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=2;
  Double i2=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=3;
  Double i3=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);
  coefNum=4;
  Double i4=CalcCoefEfficiencyDetector(coefNum, thetaDetector, sigmaDA, sigmaWS, sigmaWA, lambda0);


  std::printf("lambda0=%e, coef0=%f, coef1=%f, coef2=%f, coef3=%f, coef4=%f\n", lambda0, i0, i1, i2, i3, i4);

  return 0.0;
}

Double AdvDetectorManagerDNA:: GetCorrectEff2(Double eneNeutron, Double thetaDetector, Double deltaEne,
                     Double hosei0, Double hosei1, Double hosei2,
                     Double hosei3, Double hosei4){
  Double ramda0=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/(eneNeutron*MLF_MEV2J));
  Double tmpramda=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/((eneNeutron+deltaEne)*MLF_MEV2J));
  Double deltaRamda=tmpramda-ramda0;

//  std::printf("ramda0=%e, d_ramda=%e, ratio=%f\n", ramda0, deltaRamda, deltaRamda/ramda0);

  Double modTheta0=thetaDetector*MLF_DEGREE2RADIAN;
  Double fTheta0=1.0/cos(modTheta0);
  //Double sinTheta0=sin(modTheta0);
  //Double cosTheta0=cos(modTheta0);
  //Double fp1Theta0=sinTheta0/(cosTheta0*cosTheta0);
  //Double fp2Theta0=(1.0+sinTheta0*sinTheta0)/(cosTheta0*cosTheta0*cosTheta0);

  //Double gRamda=(ramda0+deltaRamda)/ramda0;
  Double gpRamda=1.0/ramda0;

  Double i0=hosei0;
  Double i1=hosei1*fTheta0*gpRamda;
  Double i2=hosei2*fTheta0*fTheta0*gpRamda*gpRamda;
  //Double i3=hosei3*fTheta0*fTheta0*fTheta0*gpRamda*gpRamda*gpRamda;
  //Double i4=hosei4*fTheta0*fTheta0*fTheta0*fTheta0*gpRamda*gpRamda*gpRamda*gpRamda;

//  return i0+i1*deltaRamda+i2*deltaRamda*deltaRamda+i3*deltaRamda*deltaRamda*deltaRamda+i4*deltaRamda*deltaRamda*deltaRamda*deltaRamda;

  return i0+i1*deltaRamda+i2*deltaRamda*deltaRamda;

}

Double AdvDetectorManagerDNA:: GetCorrectEff4(Double eneNeutron, Double thetaDetector, Double deltaEne,
                     Double hosei0, Double hosei1, Double hosei2,
                     Double hosei3, Double hosei4){
  Double ramda0=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/(eneNeutron*MLF_MEV2J));
  Double tmpramda=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/((eneNeutron+deltaEne)*MLF_MEV2J));
  Double deltaRamda=tmpramda-ramda0;

//  std::printf("ramda0=%e, d_ramda=%e, ratio=%f\n", ramda0, deltaRamda, deltaRamda/ramda0);

  Double modTheta0=thetaDetector*MLF_DEGREE2RADIAN;
  Double fTheta0=1.0/cos(modTheta0);
  //Double sinTheta0=sin(modTheta0);
  //Double cosTheta0=cos(modTheta0);
  //Double fp1Theta0=sinTheta0/(cosTheta0*cosTheta0);
  //Double fp2Theta0=(1.0+sinTheta0*sinTheta0)/(cosTheta0*cosTheta0*cosTheta0);

  //Double gRamda=(ramda0+deltaRamda)/ramda0;
  Double gpRamda=1.0/ramda0;

  Double i0=hosei0;
  Double i1=hosei1*fTheta0*gpRamda;
  Double i2=hosei2*fTheta0*fTheta0*gpRamda*gpRamda;
  Double i3=hosei3*fTheta0*fTheta0*fTheta0*gpRamda*gpRamda*gpRamda;
  Double i4=hosei4*fTheta0*fTheta0*fTheta0*fTheta0*gpRamda*gpRamda*gpRamda*gpRamda;

  return i0+i1*deltaRamda+i2*deltaRamda*deltaRamda+i3*deltaRamda*deltaRamda*deltaRamda+i4*deltaRamda*deltaRamda*deltaRamda*deltaRamda;

//  return i0+i1*deltaRamda+i2*deltaRamda*deltaRamda;

}

Double AdvDetectorManagerDNA:: GetCorrectThetaEff2(Double eneNeutron, Double thetaDetector, Double deltaTheta,
                     Double hosei0, Double hosei1, Double hosei2,
                     Double hosei3, Double hosei4){
//  Double ramda0=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/(eneNeutron*MLF_MEV2J));
//  Double tmpramda=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/((eneNeutron+deltaEne)*MLF_MEV2J));
//  Double deltaRamda=tmpramda-ramda0;

//  std::printf("ramda0=%e, d_ramda=%e, ratio=%f\n", ramda0, deltaRamda, deltaRamda/ramda0);

  //Double modTheta0=thetaDetector*MLF_DEGREE2RADIAN;
  //Double fTheta0=1.0/cos(modTheta0);
  //Double sinTheta0=sin(modTheta0);
  //Double cosTheta0=cos(modTheta0);
  //Double fp1Theta0=sinTheta0/(cosTheta0*cosTheta0);
  //Double fp2Theta0=(1.0+sinTheta0*sinTheta0)/(cosTheta0*cosTheta0*cosTheta0);

//  Double gRamda=(ramda0+deltaRamda)/ramda0;
//  Double gpRamda=1.0/ramda0;
  Double modDeltaTheta=deltaTheta*MLF_DEGREE2RADIAN;

  Double i0=hosei0;
  Double i1=hosei1*modDeltaTheta;
  Double i2=hosei2*modDeltaTheta*modDeltaTheta;
//  Double i3=hosei3*modDeltaTheta*modDeltaTheta*modDeltaTheta;
//  Double i4=hosei4*modDeltaTheta*modDeltaTheta*modDeltaTheta*modDeltaTheta;

  return i0+i1+i2;

//  return i0+i1*deltaRamda+i2*deltaRamda*deltaRamda;

}


Double AdvDetectorManagerDNA:: GetCorrectThetaEff4(Double eneNeutron, Double thetaDetector, Double deltaTheta,
                     Double hosei0, Double hosei1, Double hosei2,
                     Double hosei3, Double hosei4){
//  Double ramda0=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/(eneNeutron*MLF_MEV2J));
//  Double tmpramda=sqrt(2.0*PI*PI*HBAR*HBAR/MLF_Mn/((eneNeutron+deltaEne)*MLF_MEV2J));
//  Double deltaRamda=tmpramda-ramda0;

//  std::printf("ramda0=%e, d_ramda=%e, ratio=%f\n", ramda0, deltaRamda, deltaRamda/ramda0);

  //Double modTheta0=thetaDetector*MLF_DEGREE2RADIAN;
  //Double fTheta0=1.0/cos(modTheta0);
  //Double sinTheta0=sin(modTheta0);
  //Double cosTheta0=cos(modTheta0);
  //Double fp1Theta0=sinTheta0/(cosTheta0*cosTheta0);
  //Double fp2Theta0=(1.0+sinTheta0*sinTheta0)/(cosTheta0*cosTheta0*cosTheta0);

//  Double gRamda=(ramda0+deltaRamda)/ramda0;
//  Double gpRamda=1.0/ramda0;
  Double modDeltaTheta=deltaTheta*MLF_DEGREE2RADIAN;

  Double i0=hosei0;
  Double i1=hosei1*modDeltaTheta;
  Double i2=hosei2*modDeltaTheta*modDeltaTheta;
  Double i3=hosei3*modDeltaTheta*modDeltaTheta*modDeltaTheta;
  Double i4=hosei4*modDeltaTheta*modDeltaTheta*modDeltaTheta*modDeltaTheta;

  return i0+i1+i2+i3+i4;
//  return i0+i1+i2+i3;


//  return i0+i1*deltaRamda+i2*deltaRamda*deltaRamda;

}






/*
Double AdvDetectorManagerDNA:: return_atom_sigma_from_file(char* atom_name, char state, Double energy){
  obtain_atom_sigma_from_file(atom_name, state, energy);
  return sigma;
}
*/


/*
Double AdvDetectorManagerDNA:: return_atom_sigma_from_velocity_rule(Double energy){
  char atomname[16];
  char state;
  Double velocity=sqrt(2.0*energy*1.0e-03*eV/mn);

  // detector
  for(int i=0 ; i<body_info.atomname.size(); i++){
    obtain_atom_sigma_from_velocity_rule(detector_body_info, state, velocity);
  return sigma;
}
*/

/*

Double AdvDetectorManagerDNA:: return_integral_efficiency_detector(Double theta, struct coordinate *detPos,
                                                               Double sigma_d_a, Double sigma_w_s, Double sigma_w_a){
  return CalcEfficiencyDetector(theta, detPos, sigma_d_a, sigma_w_s, sigma_w_a);
}
*/


Double AdvDetectorManagerDNA:: CalcEfficiencyDetector(Double thetaDetector,
//                                                  struct coordinate *detPos,
                                                  Double sigmaDA, Double sigmaWS, Double sigmaWA){
  Double theta=thetaDetector*MLF_DEGREE2RADIAN;
  Double n3He=detectorInfo.totalDensity;
  Double nwall=wallInfo.totalDensity;
  Double T=wallInfo.ratioT;
  Double radiusDetector=detectorInfo.rl;
  Double radiusWall=wallInfo.rl;

#if debug
  std::printf("T=%f\n",T);
  std::printf("n3He=%e, nwall=%e\n", n3He, nwall);
  std::printf("radiusDetector=%f, radiusWall=%f\n", radiusDetector, radiusWall);
  std::printf("cos theta =%f\n", cos(theta));
  std::printf("sigmaDA=%e, sigmaWS=%e, sigmaWA=%e\n", sigmaDA, sigmaWS, sigmaWA);
#endif
  // integral was done by use of Guauss-Legendre (m=6) method
  UInt4 max=10000;
  UInt4 nDiv;
  Double dx;
  Double x1=0.0;
  Double xi;

  UInt4 m=6;
  Double x[m],y[m/2], xk[m], Hk[m], f[m];
  xk[0]=-0.9324695142;
  xk[1]=-0.6612093865;
  xk[2]=-0.2386191861;
  xk[3]=-xk[2];
  xk[4]=-xk[1];
  xk[5]=-xk[0];
  Hk[0]=0.1713244924;
  Hk[1]=0.3607615730;
  Hk[2]=0.4679139346;
  Hk[3]=Hk[2];
  Hk[4]=Hk[1];
  Hk[5]=Hk[0];
  Double s1, s;
  s1=s=0.0;
  Double diff;

  nDiv=4;
  for (UInt4 i=0; i<max; i++) {
    nDiv*=2;
    dx=1.0/nDiv;
    for (UInt4 j=0; j<m/2; j++) {
      y[j]=0.0;
    }
    for (UInt4 j=0; j<nDiv; j++){
      xi=x1+((j+1)-0.5)*dx;
      for (UInt4 k=0; k<m; k++) {
        x[k]=xi+xk[k]*dx/2;
      }
      for (UInt4 k=0; k<m; k++) {
        f[k]=ReturnAbsorptionByDetector(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T);
      }
      for (UInt4 k=0; k<m/2; k++) {
        y[k]+=f[k]+f[m-k-1];
      }
    }
    for (UInt4 j=0; j<m/2; j++) {
      y[j]*=Hk[j];
    }
    Double sum=0.0;
    for (UInt4 j=0; j<m/2; j++) {
      sum+=y[j];
    }
    s=0.5*dx*sum;
    diff=s-s1;
    if (diff<0.0) {
      diff=-diff;
    }
#if debug
    std::printf("%d s=%e\n", i, s); fflush(stdout);
#endif
    if (diff < epsilon || diff/s1 < epsilonRatio ){
      break;
    }
    s1=s;
  }
  return s;
};



Double AdvDetectorManagerDNA:: CalcCoefEfficiencyDetector(UInt4 num, Double thetaDetector,
//                                                  struct coordinate *detPos,
                                                  Double sigmaDA, Double sigmaWS, Double sigmaWA, Double lambda0){
  Double theta=thetaDetector*MLF_DEGREE2RADIAN;
  Double n3He=detectorInfo.totalDensity;
  Double nwall=wallInfo.totalDensity;
  Double T=wallInfo.ratioT;
  Double radiusDetector=detectorInfo.rl;
  Double radiusWall=wallInfo.rl;

#if debug
  std::printf("T=%f\n",T);
  std::printf("n3He=%e, nwall=%e\n", n3He, nwall);
  std::printf("radiusDetector=%f, radiusWall=%f\n", radiusDetector, radiusWall);
  std::printf("cos theta =%f\n", cos(theta));
  std::printf("sigmaDA=%e, sigmaWS=%e, sigmaWA=%e\n", sigmaDA, sigmaWS, sigmaWA);
#endif
  // integral was done by use of Guauss-Legendre (m=6) method
  UInt4 max=10000;
  UInt4 nDiv;
  Double dx;
  Double x1=0.0;
  Double xi;

  UInt4 m=6;
  Double x[m],y[m/2], xk[m], Hk[m], f[m];
  xk[0]=-0.9324695142;
  xk[1]=-0.6612093865;
  xk[2]=-0.2386191861;
  xk[3]=-xk[2];
  xk[4]=-xk[1];
  xk[5]=-xk[0];
  Hk[0]=0.1713244924;
  Hk[1]=0.3607615730;
  Hk[2]=0.4679139346;
  Hk[3]=Hk[2];
  Hk[4]=Hk[1];
  Hk[5]=Hk[0];
  Double s1, s;
  s1=s=0.0;
  Double diff;

  nDiv=4;
  for (UInt4 i=0; i<max; i++) {
    nDiv*=2;
    dx=1.0/nDiv;
    for (UInt4 j=0; j<m/2; j++) {
      y[j]=0.0;
    }
    for (UInt4 j=0; j<nDiv; j++){
      xi=x1+((j+1)-0.5)*dx;
      for (UInt4 k=0; k<m; k++) {
        x[k]=xi+xk[k]*dx/2;
      }
      for (UInt4 k=0; k<m; k++) {

        switch (num) {
          case 0:
            f[k]=ReturnAbsorptionByDetector(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T);
            break;
          case 1:
            f[k]=ReturnAbsorptionByDetector1(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T);
            break;
          case 2:
            f[k]=ReturnAbsorptionByDetector2(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T);
            break;
          case 3:
            f[k]=ReturnAbsorptionByDetector3(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T);
            break;
          case 4:
            f[k]=ReturnAbsorptionByDetector4(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T);
            break;
          case 5:
            f[k]=ReturnAbsorptionByDetector5(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T, lambda0);
            break;
          case 6:
            f[k]=ReturnAbsorptionByDetector6(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T, lambda0);
            break;
          case 7:
            f[k]=ReturnAbsorptionByDetector7(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T, lambda0);
            break;
          case 8:
            f[k]=ReturnAbsorptionByDetector8(x[k], theta, sigmaDA, sigmaWS, sigmaWA, radiusDetector, radiusWall, n3He, nwall, T, lambda0);
            break;


          default:
            break;
        }

      }
      for (UInt4 k=0; k<m/2; k++) {
        y[k]+=f[k]+f[m-k-1];
      }
    }
    for (UInt4 j=0; j<m/2; j++) {
      y[j]*=Hk[j];
    }
    Double sum=0.0;
    for (UInt4 j=0; j<m/2; j++) {
      sum+=y[j];
    }
    s=0.5*dx*sum;
    diff=s-s1;
    if (diff<0.0) {
      diff=-diff;
    }
#if debug
    std::printf("%d s=%e\n", i, s); fflush(stdout);
#endif
    if (diff < epsilon || diff/s1 < epsilonRatio ){
      break;
    }
    s1=s;
  }
  return s;
};

Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;
  fx=(1.0-exp(-n3He*sigmaDA*tx))*exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);
/*end*/

  return fx;
};

Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector1(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;

  Double alphax=-n3He*sigmaDA*tx*cos(theta);
  Double betax=-nwall*txWall*cos(theta);
  Double epsilonx=betax*sigmaWA;
  Double eta1=exp(-n3He*sigmaDA*tx);
  Double eta2=exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);

  fx=eta2*epsilonx-eta1*eta2*(epsilonx+alphax);
/*end*/

  return fx;
};


Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector2(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;

  Double alphax=-n3He*sigmaDA*tx*cos(theta);
  Double betax=-nwall*txWall*cos(theta);
  Double epsilonx=betax*sigmaWA;
  Double eta1=exp(-n3He*sigmaDA*tx);
  Double eta2=exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);

  fx=0.5*(eta2*epsilonx*epsilonx-eta1*eta2*(epsilonx+alphax)*(epsilonx+alphax));
/*end*/

  return fx;
};

Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector3(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;

  Double alphax=-n3He*sigmaDA*tx*cos(theta);
  Double betax=-nwall*txWall*cos(theta);
  Double epsilonx=betax*sigmaWA;
  Double eta1=exp(-n3He*sigmaDA*tx);
  Double eta2=exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);

  fx=1.0/6.0*(eta2*epsilonx*epsilonx*epsilon-eta1*eta2*(epsilonx+alphax)*(epsilonx+alphax)*(epsilon+alphax));
/*end*/

  return fx;
};


Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector4(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;

  Double alphax=-n3He*sigmaDA*tx*cos(theta);
  Double betax=-nwall*txWall*cos(theta);
  Double epsilonx=betax*sigmaWA;
  Double eta1=exp(-n3He*sigmaDA*tx);
  Double eta2=exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);

  fx=1.0/24.0*(eta2*epsilonx*epsilonx*epsilon*epsilon
               -eta1*eta2*(epsilonx+alphax)*(epsilonx+alphax)*(epsilon+alphax)*(epsilon+alphax));
/*end*/

  return fx;
};

Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector5(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T, Double lambda0){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;

  Double alphax=-n3He*sigmaDA*tx*cos(theta);
  Double betax=-nwall*txWall*cos(theta);
  Double epsilonx=betax*sigmaWA;
  Double gp=1.0; // /lambda0;
  Double gammax=betax*(1.0-T)*sigmaWS;
  Double omegax=gammax+epsilonx*1.0;
  Double eta1=exp(-n3He*sigmaDA*tx);
  Double eta2=exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);

  Double cosTheta=cos(theta);
  Double sinTheta=sin(theta);
  //Double fTheta=1.0/cosTheta;
  Double fp1=sinTheta/(cosTheta*cosTheta);
  //Double fp2=(1.0+sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta);
  //Double fp3=2.0*sinTheta/(cosTheta*cosTheta)+3.0*(sinTheta+sinTheta*sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta*cosTheta);
  //Double fp4=(5.0+11.0*sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta)+12.0*sinTheta*sinTheta*(1.0+sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta*cosTheta*cosTheta);


  fx=eta2*omegax*fp1-eta1*eta2*fp1*(alphax*gp+omegax);
/*end*/

  return fx;
};


Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector6(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T, Double lambda0){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;

  Double alphax=-n3He*sigmaDA*tx*cos(theta);
  Double betax=-nwall*txWall*cos(theta);
  Double epsilonx=betax*sigmaWA;
  Double gp=1.0; ///lambda0;
  Double gammax=betax*(1.0-T)*sigmaWS;
  Double omegax=gammax+epsilonx*1.0;
  Double eta1=exp(-n3He*sigmaDA*tx);
  Double eta2=exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);

  Double cosTheta=cos(theta);
  Double sinTheta=sin(theta);
  //Double fTheta=1.0/cosTheta;
  Double fp1=sinTheta/(cosTheta*cosTheta);
  Double fp2=(1.0+sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta);
  //Double fp3=2.0*sinTheta/(cosTheta*cosTheta)+3.0*(sinTheta+sinTheta*sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta*cosTheta);
  //Double fp4=(5.0+11.0*sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta)+12.0*sinTheta*sinTheta*(1.0+sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta*cosTheta*cosTheta);

  Double alphagomega=alphax*gp+omegax;


  fx=0.5*eta2*(omegax*omegax*fp1*fp1+omegax*fp2)-0.5*eta1*eta2*(alphagomega*alphagomega*fp1*fp1+alphagomega*fp2);
/*end*/

  return fx;
};


Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector7(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T, Double lambda0){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;

  Double alphax=-n3He*sigmaDA*tx*cos(theta);
  Double betax=-nwall*txWall*cos(theta);
  Double epsilonx=betax*sigmaWA;
  Double gp=1.0; // /lambda0;
  Double gammax=betax*(1.0-T)*sigmaWS;
  Double omegax=gammax+epsilonx*1.0;
  Double eta1=exp(-n3He*sigmaDA*tx);
  Double eta2=exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);

  Double cosTheta=cos(theta);
  Double sinTheta=sin(theta);
  //Double fTheta=1.0/cosTheta;
  Double fp1=sinTheta/(cosTheta*cosTheta);
  Double fp2=(1.0+sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta);
  Double fp3=2.0*sinTheta/(cosTheta*cosTheta)+3.0*(sinTheta+sinTheta*sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta*cosTheta);
  //Double fp4=(5.0+11.0*sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta)+12.0*sinTheta*sinTheta*(1.0+sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta*cosTheta*cosTheta);

  Double alphagomega=alphax*gp+omegax;

  Double fx1, fx2;

  Double omega3=omegax*omegax*omegax;
  Double omega2=omegax*omegax;
  Double alphagomega3=alphagomega*alphagomega*alphagomega;
  Double alphagomega2=alphagomega*alphagomega;

  fx1=1.0/6*eta2*(omega3*fp1*fp1*fp1+3.0*omega2*fp1*fp2+omegax*fp3);
  fx2=1.0/6*eta1*eta2*(alphagomega3*fp1*fp1*fp1+3.0*alphagomega2*fp1*fp2+alphagomega*fp3);

  fx=fx1-fx2;
/*end*/

  return fx;
};


Double AdvDetectorManagerDNA:: ReturnAbsorptionByDetector8(Double x, Double theta,
                                                        Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                        Double radiusDetector, Double radiusWall, Double n3He, Double nwall, Double T, Double lambda0){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
  txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;

  Double alphax=-n3He*sigmaDA*tx*cos(theta);
  Double betax=-nwall*txWall*cos(theta);
  Double epsilonx=betax*sigmaWA;
  Double gp=1.0; // /lambda0;
  Double gammax=betax*(1.0-T)*sigmaWS;
  Double omegax=gammax+epsilonx*1.0;
  Double eta1=exp(-n3He*sigmaDA*tx);
  Double eta2=exp(-nwall*(sigmaWA+T*sigmaWS)*txWall);

  Double cosTheta=cos(theta);
  Double sinTheta=sin(theta);
  //Double fTheta=1.0/cosTheta;
  Double fp1=sinTheta/(cosTheta*cosTheta);
  Double fp2=(1.0+sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta);
  Double fp3=2.0*sinTheta/(cosTheta*cosTheta)+3.0*(sinTheta+sinTheta*sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta*cosTheta);
  Double fp4=(5.0+11.0*sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta)+12.0*sinTheta*sinTheta*(1.0+sinTheta*sinTheta)/(cosTheta*cosTheta*cosTheta*cosTheta*cosTheta);
//  Double fp4=(3.0*sinTheta*sinTheta+5.0+8.0*sinTheta*sinTheta*cosTheta*cosTheta*(sinTheta*sinTheta+5.0))/cosTheta/cosTheta/cosTheta;

  Double alphagomega=alphax*gp+omegax;

  Double fx1, fx2;

  Double omega3=omegax*omegax*omegax;
  Double omega2=omegax*omegax;
  Double omega4=omega2*omega2;
  Double alphagomega3=alphagomega*alphagomega*alphagomega;
  Double alphagomega2=alphagomega*alphagomega;
  Double alphagomega4=alphagomega2*alphagomega2;

  fx1=1.0/24*eta2*(omega4*fp1*fp1*fp1*fp1+6.0*omega3*fp1*fp1*fp2+3.0*omega2*fp2*fp2+4.0*omega2*fp1*fp3+omegax*fp4);
  fx2=1.0/24*eta1*eta2*(alphagomega4*fp1*fp1*fp1*fp1+6.0*alphagomega3*fp1*fp1*fp2+4.0*alphagomega2*fp1*fp3+3.0*alphagomega2*fp2*fp2+alphagomega*fp4);

  fx=fx1-fx2;
/*end*/

  return fx;
};


/*
Double AdvDetectorManagerDNA:: obtain_atom_sigma_from_file(char* atom_name, char state, Double energy){
  Double energy_i;
  Double sigma_i;
  int length_keyword=16;
  Double x1, x2, y1, y2;
  x1=x2=y1=y2=0.0;
  sigma=0.0;

  char sc_type[length_keyword];;

  std::sprintf(sc_type, "%s_%c", atom_name, state);

  FILE* fp;
  char database_name[256];

  std::sprintf(database_name, "%s/%s_%s.dat", database_dir, name, atom_name);

  fp=fopen(database_name, "r");

  char *p;
  int  length_buffer=256;
  char buffer[256];
  char keyword[length_keyword];
  int i;

  Double a, b, y0;

  int num_species_scattering;

  while(fgets(buffer, length_buffer, fp)!=NULL){
    p=std::strtok(buffer, ":");
    strncpy(keyword, p, length_keyword);
    if(strcmp(keyword, sc_type)==0){
      while ( fgets(buffer, length_buffer, fp)!=NULL){
        p=std::strtok(buffer, ",");
        energy_i=atof(p);
        while ( (p=std::strtok(NULL, ",")) !=NULL ) sigma_i=atof(p);
        if(energy<=energy_i){
          x2=energy_i;
          y2=sigma_i;
          break;
        }
        x1=energy_i;
        y1=sigma_i;
      }
//      std::printf("x1=%f, y1=%f, x2=%f, y2=%f\n", x1, y1, x2, y2);
      a=(y2-y1)/(x2-x1);
      b=y1-a*x1;
      y0=a*energy+b;
//      std::printf("a=%f, b=%f, y0=%f\n", a, b, y0);
      sigma=exp(y0);
      break;
    }
  }

  return sigma;
}
*/


/*
Double AdvDetectorManagerDNA:: obtain_atom_sigma_from_velocity_rule(char* atom_name, char state, Double velocity){
// velocity is given in unit of [m/s]
  sigma=0.0;
  char xs_type[16];
  std::sprintf(xs_type, "%s_%c", atom_name, state);
  num_data=1;
  xs_data=new Double* [num_data];
  for(int i=0; i<num_data; i++) xs_data[i]=new Double [2];

  set_sigma_data_NIST(atom_name, xs_type);
  sigma=xs_data[0][1]*xs_data[0][0]/velocity;

  delete_xs_data_object();

  return sigma;

}
*/

/*
Double AdvDetectorManagerDNA:: obtain_complex_sigma_from_file(int num_atom, Double ratio[],
                                                char* atom_name[],
                                                char state[], Double energy){
  Double sum=0.0;
  for(int i=0; i<num_atom; i++) sum+=ratio[i];
  for(int i=0; i<num_atom; i++) ratio[i]/sum;

//  Double sigma;
  for(int i=0; i<num_atom; i++){
    sigma+=ratio[i]*obtain_atom_sigma_from_file(atom_name[i], state[i], energy);
  }

  return sigma;
}
*/

