#include <iostream>
#include <cmath>
#include "Header.hh"
//#include "AdvPhysicalParameterDNA.hh"
#include "UtsusemiUnitConverter.hh"
#include "AdvNeutronMonitorDNA.hh"

AdvNeutronMonitorDNA:: AdvNeutronMonitorDNA(void){
  if (!(isReady())) {
    UtsusemiError("AdvNeutronMonitorDNA >> Error Initializing (Maybe not found atomic data file).");
    return;
  }
        //std::string filepath = getenv("HOME");
        std::string filepath = UtsusemiEnvGetUserDir();
        std::string filename = "monitor_data.dat";
        //filepath += "/ana/setup/";
        filepath += "/ana/DNA/setup/";
        filepath += filename;
       //filename="/home/dnaadmin/00Install/work.DNA/correction/monitor_data.dat";

       filename = filepath;

  wallInfo.initialize();
  monitorInfo.initialize();
  std::cout <<"filepath = "<<filename<<std::endl;
  SetInfoData(filename, &wallInfo, &monitorInfo);
  wallInfo.totalDensity=wallInfo.weightPerVolume*MLF_KG2G/wallInfo.effectiveAtomicWeight*MLF_NA;
  monitorInfo.totalDensity=monitorInfo.gasPressure*MLF_ATM2PA/kB/monitorInfo.temperature; // SI unit

  this->monitorCount=NULL;


  //LengthFromSource=NAN;
  LengthFromSource=39.188;
  //time=null;
  //energy=null;

}

AdvNeutronMonitorDNA:: AdvNeutronMonitorDNA(std::string filepath){
  if (!(isReady())) {
    UtsusemiError("AdvNeutronMonitorDNA >> Error Initializing (Maybe not found atomic data file).");
    return;
  }
       filename = filepath;

  wallInfo.initialize();
  monitorInfo.initialize();
  std::cout <<"filepath = "<<filename<<std::endl;
  SetInfoData(filename, &wallInfo, &monitorInfo);
  wallInfo.totalDensity=wallInfo.weightPerVolume*MLF_KG2G/wallInfo.effectiveAtomicWeight*MLF_NA;
  monitorInfo.totalDensity=monitorInfo.gasPressure*MLF_ATM2PA/kB/monitorInfo.temperature; // SI unit

  this->monitorCount=NULL;


  //LengthFromSource=NAN;
  LengthFromSource=39.188;
  //time=null;
  //energy=null;
}



AdvNeutronMonitorDNA:: ~AdvNeutronMonitorDNA(void){
}

void AdvNeutronMonitorDNA::TranslateFromTToE(void){
  UInt4 i;

/* Judege of LengthFromSource */
/*

*/

//  LengthFromSource=42.0;

  Double velocity;

  for(i=0; i<time.size(); i++){
    velocity=LengthFromSource/time[i];
    energy.push_back(0.5*MLF_Mn*velocity*velocity);
//    std::printf("velocity(m/s) = %f, energy (eV) = %f, MASS_N=%f\n",
//            velocity, 0.5*MLF_Mn*velocity*velocity*MLF_J2MEV, MLF_Mn);
  }

//  exit(1);

}

void AdvNeutronMonitorDNA::vectorReverse(std::vector<Double>& v) {
    for (UInt4 i=0, j=v.size()-1; j-i > 1; ++i, --j) {
        std::swap<Double>(v[i], v[j]);
    }
}


ElementContainer& AdvNeutronMonitorDNA::TranslateFromTToE(ElementContainer& src) {
    std::vector<Double> tof = src.PutX();
    std::vector<Double> val = src.PutY();
    std::vector<Double> err = src.PutE();

    std::vector<Double> energy = *(new std::vector<Double>(tof.size()));
    Double velocity;
    for (UInt4 i=0; i<tof.size(); ++i) {
        velocity=LengthFromSource/tof.at(i);
        energy.at(i)=(0.5*MLF_Mn*velocity*velocity);
    }
    UInt4 imax = (val.size() % 2 == 0) ? val.size()/2 : (val.size()-1)/2;
    Double tmp1, tmp2;
    for (UInt4 i=0; i<imax; ++i) {
        tmp1                    = val.at(i);
        val.at(i)               = val.at(val.size()-1 -i);
        val.at(val.size()-1 -i) = tmp1;

        tmp2                    = err.at(i);
        err.at(i)               = err.at(err.size()-1 -i);
        err.at(err.size()-1 -i) = tmp2;
    }

    ElementContainer *dest = new ElementContainer(*(src.PutHeaderPointer()));
    dest->Add("energy",      energy, src.PutUnit(src.PutXKey()));
    dest->Add(src.PutYKey(), val,    src.PutUnit(src.PutYKey()));
    dest->Add(src.PutEKey(), err,    src.PutUnit(src.PutEKey()));
    dest->SetKeys("energy", src.PutYKey(), src.PutEKey());

    return *dest;

}

void AdvNeutronMonitorDNA::SetLengthFromSource(Double length){
  LengthFromSource=length;
}

Double AdvNeutronMonitorDNA::GetMonitorEfficiency(double energy){
//  sigmaNitroAbs=GetAtomSigmaFromVelocityRule("0Ni", 'a', energy);
  double velocity=sqrt(2.0*energy/MLF_Mn);
  sigmaNitroAbs=GetAtomSigmaFromVelocityRule("0N", 'a', velocity);
//  std::printf("sigmaNitorAbso=%e\n", sigmaNitroAbs);
//  std::printf("totalDensity=%e\n", monitorInfo.totalDensity);
//  std::printf("width=%e\n",monitorInfo.width);
//  std::printf("shouleder=%e\n", monitorInfo.totalDensity*sigmaNitroAbs*monitorInfo.width);
//  std::printf("eff=%e\n",1.0-exp(-monitorInfo.totalDensity*sigmaNitroAbs*monitorInfo.width));
  return 1.0-exp(-monitorInfo.totalDensity*sigmaNitroAbs*monitorInfo.width);
}

Double AdvNeutronMonitorDNA::GetWallEfficiency(double energy){
//  sigmaNitroAbs=GetAtomSigmaFromVelocityRule("0Ni", 'a', energy);
//  double velocity=sqrt(2.0*energy/MLF_Mn);
  Double sigmaAWall=ReturnSigmaFromVelocityRule(&wallInfo, energy, 'a');
  Double sigmaSWall=ReturnSigmaFromVelocityRule(&wallInfo, energy, 's');
  Double sigmaEffAWall=(1.0-wallInfo.ratioT)*sigmaSWall+sigmaAWall;
  return exp(-wallInfo.totalDensity*sigmaEffAWall*wallInfo.width);
}


void AdvNeutronMonitorDNA::SetIntensityAtSource(){
/* this code temporary gives a neutron intensity data */
  int i;
  //double dt=1.e-4;
  //double base=1.0e-3;
  int num=100;
  for(i=0; i<num; i++){
    double velocity=1700.0+i*10.0;

  //  time.push_back(base+dt*i);
    time.push_back(LengthFromSource/velocity);
    observedAtMonitor.push_back(exp(-1.e-2*((i-num/2))*((i-num/2))));
    observedAtMonitorErr.push_back(sqrt(exp(-1.e-2*((i-num/2))*((i-num/2)))));

  }
}

void AdvNeutronMonitorDNA::SetIntensityAtSource(ElementContainer& monitorCount) {

    this->monitorCount = &monitorCount;
    std::string xkey = monitorCount.PutXKey();
    std::string ykey = monitorCount.PutYKey();
    UInt4 xsize = monitorCount.PutSize(xkey);
    UInt4 ysize = monitorCount.PutSize(ykey);
//    std::cerr << "Fine: AdvNeutronMonitorDNA::SetIntensityAtSource(ElementContainer&): " << __FILE__ << ":" << __LINE__ ;
//    std::cerr << "key=(" << xkey << ", " << ykey << "), size=(" << xsize << ", " << ysize << ")" << std::endl;
    if ( xsize == ysize) {
        time = monitorCount.PutX();
    } else if ( xsize == ysize +1) {
        time = *(new std::vector<Double>(ysize));
        std::vector<Double> x=monitorCount.PutX();
        for (UInt4 i=0; i<ysize; ++i) {
            time.at(i) = (x.at(i) + x.at(i+1))/2.0;
//            std::cerr << "Fine: AdvNeutronMonitorDNA::SetIntensityAtSource(ElementContainer&): " << __FILE__ << ":" << __LINE__ ;
//            std::cerr << "i=" << i << std::endl;
        }
    }
    observedAtMonitor = monitorCount.PutY();
    observedAtMonitorErr = monitorCount.PutE();
}

void AdvNeutronMonitorDNA::GetIntensityAtSample(){
  SetIntensityAtSource();
  TranslateFromTToE();
//  std::printf("intensity size =%lu\n", observedAtMonitor.size());
  for(UInt4 i=0; i<observedAtMonitor.size(); i++){
    std::printf("i=%d\n",i);
    monitorEfficiency=GetMonitorEfficiency(energy[i]);
    wallEfficiency=GetWallEfficiency(energy[i]);
    Double sigmaWallAbs=ReturnSigmaFromVelocityRule(&wallInfo, energy[i], 'a');
    Double sigmaWallScat=ReturnSigmaFromVelocityRule(&wallInfo, energy[i], 's');
    sigmaWallEffAbs=(1.0-wallInfo.ratioT)*sigmaWallScat+sigmaWallAbs;
    Double sigmaMonitorTotal=ReturnSigmaFromVelocityRule(&monitorInfo, energy[i], 't');
    Double sigmaWallTotal=ReturnSigmaFromVelocityRule(&wallInfo, energy[i], 't');
    intensityAtSample.push_back(
                                observedAtMonitor[i]/monitorEfficiency
                                *exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)
                                *exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)
                               );
    intensityAtSampleErr.push_back(
                                observedAtMonitorErr[i]/monitorEfficiency
                                *exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)
                                *exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)
                               );

    intensityAtMonitor.push_back(
                                observedAtMonitor[i]/monitorEfficiency/wallEfficiency
                               );
    intensityAtMonitorErr.push_back(
                                observedAtMonitorErr[i]/monitorEfficiency/wallEfficiency
                               );

//    std::printf("monitor efficiency\n");
//    std::printf("wall efficiency\n");
//    std::printf("sigmaWallAbs\n");
//    std::printf("sigmaWallScat\n");
//    std::printf("sigmaWallEffAbs\n");
//    std::printf("sigmaMonitorTotal\n");
//    std::printf("sigmaWallTotal\n");
//    std::printf("observedAtMonitor=%e, efficiencty=%e, sigmon=%e, sigwal=%e\n",
//            observedAtMonitor[i], monitorEfficiency, sigmaMonitorTotal, sigmaWallTotal);
//    std::printf("intensityAtSample\n");
//    exit(1);
  }

  /* temporary */
  /*
  FILE* fp=fopen("I0Edata.dat","w");
 std::fprintf(fp, "time(micro sec),  energy(meV),  , intensityAtMonitor, observedAtMonitor,  intensityAtSample,  ratio\n");
  for(UInt4 i=0; i<observedAtMonitor.size(); i++){
   std::fprintf(fp, "%e   %e   %e   %e   %e   %e\n", time[i]*SEC2MICROSEC, energy[i]*MLF_J2MEV, intensityAtMonitor[i], observedAtMonitor[i], intensityAtSample[i], intensityAtSample[i]/intensityAtMonitor[i]);
  }
  fflush(fp);
  fclose(fp);
  */
  std::string fileName("I0E.dat");
  this->outputResult(fileName);

}

void AdvNeutronMonitorDNA::GetIntensityAtSample(ElementContainer& monitorCount, ElementContainerArray& result) {
    SetIntensityAtSource(monitorCount);
//    TranslateFromTToE();

//    std::printf("intensity size =%lu\n", observedAtMonitor.size());
    energy = monitorCount.PutX();

    for (UInt4 i=0; i<observedAtMonitor.size(); ++i) {
//      std::printf("i=%d\n",i);
        Double e;
        if (energy.size() == observedAtMonitor.size()) {
//            e = energy.at(i);
            e = energy.at(i)*MLF_MEV2J; // 20120724 add *MLF_MEV2J
        } else {
//            e = (energy.at(i) + energy.at(i))/2.0;
            e = (energy.at(i) + energy.at(i))/2.0*MLF_MEV2J; // 20120724 add *MLF_MEV2J
        }
        monitorEfficiency=GetMonitorEfficiency(e);
        wallEfficiency=GetWallEfficiency(e);
        Double sigmaWallAbs =ReturnSigmaFromVelocityRule(&wallInfo, e, 'a');
        Double sigmaWallScat=ReturnSigmaFromVelocityRule(&wallInfo, e, 's');
        sigmaWallEffAbs=(1.0-wallInfo.ratioT)*sigmaWallScat+sigmaWallAbs;
        Double sigmaMonitorTotal=ReturnSigmaFromVelocityRule(&monitorInfo, e, 't');
        Double sigmaWallTotal=ReturnSigmaFromVelocityRule(&wallInfo, e, 't');

        if((energy[i] >0)&&(observedAtMonitor[i]!=0)){
            intensityAtSample.push_back(
                                observedAtMonitor[i]/monitorEfficiency
                                *exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)
                                *exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)
                               );

            intensityAtSampleErr.push_back(
                                observedAtMonitorErr[i]/monitorEfficiency
                                *exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)
                                *exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)
                               );
            intensityAtMonitor.push_back(observedAtMonitor[i]/monitorEfficiency/wallEfficiency);
            intensityAtMonitorErr.push_back(observedAtMonitorErr[i]/monitorEfficiency/wallEfficiency);
        }else{
            intensityAtSample.push_back(0);
            intensityAtSampleErr.push_back(0);
            intensityAtMonitor.push_back(0);
            intensityAtMonitorErr.push_back(0);
        }
    }

    std::string fileName("I0E.dat");
//  this->outputResult(fileName);
    this->toContainer(result);
    //ElementContainerArray eca=this->getCorrection();

}

void AdvNeutronMonitorDNA::GetIntensityAtSample(ElementContainer& monitorCount, ElementContainer& result) {

    SetIntensityAtSource(monitorCount);

  //  TranslateFromTToE();

//    std::printf("intensity size =%lu\n", observedAtMonitor.size());
    energy = monitorCount.PutX();

    for (UInt4 i=0; i<observedAtMonitor.size(); ++i) {
 //     std::printf("i=%d\n",i);
        Double e;
        if (energy.size() == observedAtMonitor.size()) {
//            e = energy.at(i);
            e = energy.at(i)*MLF_MEV2J; // 20120724 add *MLF_MEV2J
        } else {
//            e = (energy.at(i) + energy.at(i))/2.0;
            e = (energy.at(i) + energy.at(i))/2.0*MLF_MEV2J; // 20120724 add *MLF_MEV2J
        }
        monitorEfficiency=GetMonitorEfficiency(e);
        wallEfficiency=GetWallEfficiency(e);
        Double sigmaWallAbs =ReturnSigmaFromVelocityRule(&wallInfo, e, 'a');
        Double sigmaWallScat=ReturnSigmaFromVelocityRule(&wallInfo, e, 's');
        sigmaWallEffAbs=(1.0-wallInfo.ratioT)*sigmaWallScat+sigmaWallAbs;
        Double sigmaMonitorTotal=ReturnSigmaFromVelocityRule(&monitorInfo, e, 't');
        Double sigmaWallTotal=ReturnSigmaFromVelocityRule(&wallInfo, e, 't');

        if((energy[i] >0)&&(observedAtMonitor[i]!=0)){
            intensityAtSample.push_back(
                                observedAtMonitor[i]/monitorEfficiency
                                *exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)
                                *exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)
                               );
            intensityAtSampleErr.push_back(
                                observedAtMonitorErr[i]/monitorEfficiency
                                *exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)
                                *exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)
                               );
            intensityAtMonitor.push_back(observedAtMonitor[i]/monitorEfficiency/wallEfficiency);
            intensityAtMonitorErr.push_back(observedAtMonitorErr[i]/monitorEfficiency/wallEfficiency);
        }else{
            intensityAtSample.push_back(0);
            intensityAtSampleErr.push_back(0);
            intensityAtMonitor.push_back(0);
            intensityAtMonitorErr.push_back(0);
        }

    }

    std::string fileName("I0E.dat");
//    this->outputResult(fileName);
    this->toContainer(result);

    //ElementContainerArray eca=this->getCorrection();

}


void AdvNeutronMonitorDNA::GetProfileUseMonAtSample(ElementContainer& monitorCount, ElementContainer& result) {

    SetIntensityAtSource(monitorCount);

  //  TranslateFromTToE();

//    std::printf("intensity size =%lu\n", observedAtMonitor.size());
    energy = monitorCount.PutX();

    for (UInt4 i=0; i<observedAtMonitor.size(); ++i) {
 //     std::printf("i=%d\n",i);
        Double e;
        if (energy.size() == observedAtMonitor.size()) {
//            e = energy.at(i);
            e = energy.at(i)*MLF_MEV2J; // 20120724 add *MLF_MEV2J
        } else {
//            e = (energy.at(i) + energy.at(i))/2.0;
            e = (energy.at(i) + energy.at(i))/2.0*MLF_MEV2J; // 20120724 add *MLF_MEV2J
        }
        monitorEfficiency=GetMonitorEfficiency(e);
        wallEfficiency=GetWallEfficiency(e);
        Double sigmaWallAbs =ReturnSigmaFromVelocityRule(&wallInfo, e, 'a');
        Double sigmaWallScat=ReturnSigmaFromVelocityRule(&wallInfo, e, 's');
        sigmaWallEffAbs=(1.0-wallInfo.ratioT)*sigmaWallScat+sigmaWallAbs;
        Double sigmaMonitorTotal=ReturnSigmaFromVelocityRule(&monitorInfo, e, 't');
        Double sigmaWallTotal=ReturnSigmaFromVelocityRule(&wallInfo, e, 't');

        if((energy[i] >0)&&(observedAtMonitor[i]!=0)){
            intensityAtSample.push_back(observedAtMonitor[i]/monitorEfficiency/wallEfficiency);
            intensityAtSampleErr.push_back(observedAtMonitorErr[i]/monitorEfficiency/wallEfficiency);
            intensityAtMonitor.push_back(observedAtMonitor[i]/monitorEfficiency/wallEfficiency);
            intensityAtMonitorErr.push_back(observedAtMonitorErr[i]/monitorEfficiency/wallEfficiency);
        }else{
            intensityAtSample.push_back(0);
            intensityAtSampleErr.push_back(0);
            intensityAtMonitor.push_back(0);
            intensityAtMonitorErr.push_back(0);
        }

    }

    std::string fileName("I0E.dat");
//    this->outputResult(fileName);
    this->toContainer(result);

    //ElementContainerArray eca=this->getCorrection();

}


ElementContainer AdvNeutronMonitorDNA::GetIntensityAtSample(ElementContainer monitorCount) {

    SetIntensityAtSource(monitorCount);
    ElementContainer *result = new ElementContainer();
  //  TranslateFromTToE();

//    std::printf("intensity size =%lu\n", observedAtMonitor.size());
    energy = monitorCount.PutX();

    for (UInt4 i=0; i<observedAtMonitor.size(); ++i) {
 //     std::printf("i=%d\n",i);
        Double e;
        if (energy.size() == observedAtMonitor.size()) {
//            e = energy.at(i);
            e = energy.at(i)*MLF_MEV2J; // 20120724 add *MLF_MEV2J
        } else {
//            e = (energy.at(i) + energy.at(i))/2.0;
            e = (energy.at(i) + energy.at(i))/2.0*MLF_MEV2J; // 20120724 add *MLF_MEV2J
        }
        monitorEfficiency=GetMonitorEfficiency(e);
        wallEfficiency=GetWallEfficiency(e);
        Double sigmaWallAbs =ReturnSigmaFromVelocityRule(&wallInfo, e, 'a');
        Double sigmaWallScat=ReturnSigmaFromVelocityRule(&wallInfo, e, 's');
        sigmaWallEffAbs=(1.0-wallInfo.ratioT)*sigmaWallScat+sigmaWallAbs;
        Double sigmaMonitorTotal=ReturnSigmaFromVelocityRule(&monitorInfo, e, 't');
        Double sigmaWallTotal=ReturnSigmaFromVelocityRule(&wallInfo, e, 't');

        if((energy[i] >0)&&(observedAtMonitor[i]!=0)){
            intensityAtSample.push_back(
                                observedAtMonitor[i]/monitorEfficiency
                                *exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)
                                *exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)
                               );
//std::cout<<monitorEfficiency<<std::endl;
//std::cout<<exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)<<std::endl;
//std::cout<<exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)<<std::endl;
            intensityAtSampleErr.push_back(
                                observedAtMonitorErr[i]/monitorEfficiency
                                *exp(-monitorInfo.totalDensity*sigmaMonitorTotal*monitorInfo.width)
                                *exp(-wallInfo.totalDensity*sigmaWallTotal*wallInfo.width)
                               );
            intensityAtMonitor.push_back(observedAtMonitor[i]/monitorEfficiency/wallEfficiency);
            intensityAtMonitorErr.push_back(observedAtMonitorErr[i]/monitorEfficiency/wallEfficiency);
        }else{
            intensityAtSample.push_back(0);
            intensityAtSampleErr.push_back(0);
            intensityAtMonitor.push_back(0);
            intensityAtMonitorErr.push_back(0);

        }

    }

    std::string fileName("I0E.dat");
//    this->outputResult(fileName);
    this->toContainer(*result);

return *result;

}


void AdvNeutronMonitorDNA::outputResult(std::string& fileName) {
    std::cerr << "Fine: AdvNeutronMonitorDNA::outputResult(std::string&): " << __FILE__ << ":" << __LINE__ << ": enter " << std::endl;

    if (this->monitorCount == NULL) {
        /* temporary */
        FILE* fp=fopen(fileName.c_str(),"w");
       std::fprintf(fp, "%15s %15s %15s %15s %15s %15s\n", "time(micro sec)",  "energy(meV)",  "atMonitor", "observed",  "atSample",  "ratio");
        for(UInt4 i=0; i<observedAtMonitor.size(); i++){
          std::fprintf(fp, "%15e %15e %15e %15e %15e %15e\n",
                time[i]*MLF_SEC2MICROSEC,
                energy[i]*MLF_J2MEV,
                intensityAtMonitor[i],
                observedAtMonitor[i],
                intensityAtSample[i],
                intensityAtSample[i]/intensityAtMonitor[i]);
        }
        fflush(fp);
        fclose(fp);
    } else {

        std::ofstream ofs(fileName.c_str());
        if (! ofs.is_open()) {
            std::cerr << "Error: AdvNeutronMonitorDNA::outputResult(std::string&): " << __FILE__ << ":" << __LINE__;
            std::cerr << ": can't open output file: " << fileName << std::endl;
            return;
        }
        std::cerr << "Fine: AdvNeutronMonitorDNA::outputResult(std::string&): " << __FILE__ << ":" << __LINE__;
        std::cerr << ": open output file: " << fileName << std::endl;

        std::string xkey = this->monitorCount->PutXKey();
        std::string ykey = this->monitorCount->PutYKey();
        std::string xunit = this->monitorCount->PutUnit(xkey);
        std::string yunit = this->monitorCount->PutUnit(ykey);
        Bool sectionType = (this->monitorCount->PutSize(xkey) == this->monitorCount->PutSize(ykey) + 1);

        if (sectionType) {
            ofs << std::setw(3+12+12) << xkey + "(" + xunit + ")";
        }
//        ofs << std::setw(12) << "time(micro sec)"    ;
        ofs << std::setw(12) << "energy(meV)"        ;
        ofs << std::setw(12) << "intensityAtMonitor" ;
        ofs << std::setw(12) << "observedAtMonitor"  ;
        ofs << std::setw(12) << "intensityAtSample"  ;
        ofs << std::setw(12) << "ratio"             ;
        ofs << std::endl;
        for (UInt4 i=0; i<observedAtMonitor.size(); ++i) {
            if (sectionType) {
                ofs << "[" ;
                ofs << std::setw(12) << std::setprecision(3) << this->monitorCount->Put(xkey, i  )*MLF_SEC2MICROSEC;
                ofs << "-" ;
                ofs << std::setw(12) << std::setprecision(3) << this->monitorCount->Put(xkey, i+1)*MLF_SEC2MICROSEC;
                ofs << ")" ;
            }
//            ofs << std::setw(16) << std::setprecision(5) << time[i]*SEC2MICROSEC  ;
            ofs << std::setw(12) << std::setprecision(5) << energy[i]*MLF_J2MEV   ;
            ofs << std::setw(18) << std::setprecision(5) << intensityAtMonitor[i] ;
            ofs << std::setw(18) << std::setprecision(5) << observedAtMonitor[i]  ;
            ofs << std::setw(18) << std::setprecision(5) << intensityAtSample[i]  ;
            ofs << std::setw(18) << std::setprecision(5) << intensityAtSample[i]/intensityAtMonitor[i] ;
            ofs << std::endl;
        }
        ofs.close();
    }

    std::cerr << "Fine: AdvNeutronMonitorDNA::outputResult(std::string&): " << __FILE__ << ":" << __LINE__ << ": exit " << std::endl;
}

void AdvNeutronMonitorDNA::toContainer(ElementContainerArray& eca) {
    std::string memberName = std::string("toContainer(ElementContainerArray&)");

//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": enter " << std::endl;

    HeaderBase *header = this->monitorCount->PutHeaderPointer();
    std::string xkey = this->monitorCount->PutXKey();
    std::string ykey = this->monitorCount->PutYKey();
    std::string ekey = this->monitorCount->PutEKey();
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": xkey= " << xkey << std::endl;
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": ykey= " << ykey << std::endl;
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": ekey= " << ekey << std::endl;

    ElementContainer* beamIntensity      = new ElementContainer(*header);
    ElementContainer* sampleIntensity    = new ElementContainer(*header);
    ElementContainer* transmissionRatio  = new ElementContainer(*header);

    beamIntensity->AddToHeader("correction", "intensity at monitor");
    beamIntensity->Add(xkey, this->monitorCount->PutX(), this->monitorCount->PutUnit(xkey));
    beamIntensity->Add(ykey, intensityAtMonitor,         this->monitorCount->PutUnit(ykey));
    beamIntensity->Add(ekey, intensityAtMonitorErr,      this->monitorCount->PutUnit(ykey));
    beamIntensity->SetKeys(xkey, ykey, ekey);
    beamIntensity->Dump();

    sampleIntensity->AddToHeader("correction", "intensity at sample");
    sampleIntensity->Add(xkey, this->monitorCount->PutX(), this->monitorCount->PutUnit(xkey));
    sampleIntensity->Add(ykey, intensityAtSample,          this->monitorCount->PutUnit(ykey));
    sampleIntensity->Add(ekey, intensityAtSampleErr,       this->monitorCount->PutUnit(ykey));
    sampleIntensity->SetKeys(xkey, ykey, ekey);
    sampleIntensity->Dump();

    std::vector<Double> ratioV = *(new std::vector<Double>(observedAtMonitor.size()));
    std::vector<Double> ratioVerr = *(new std::vector<Double>(observedAtMonitor.size()));

    for (UInt4 i=0; i<observedAtMonitor.size(); ++i) {
        ratioV.at(i) = intensityAtSample.at(i)/intensityAtMonitor.at(i);
        ratioVerr.at(i) = intensityAtSample.at(i)/intensityAtMonitor.at(i) * sqrt(pow((intensityAtSampleErr.at(i)/intensityAtSample.at(i)),2.0)
                          +pow((intensityAtMonitorErr.at(i)/intensityAtMonitor.at(i)),2.0));
    }

    transmissionRatio->AddToHeader("correction", "transmission ratio");
    transmissionRatio->Add(xkey,     this->monitorCount->PutX(), monitorCount->PutUnit(xkey));
    transmissionRatio->Add(std::string("ration"), ratioV                                          ); // no dimention
    transmissionRatio->Add(std::string("ratione"), ratioVerr                                      ); // no dimention
    transmissionRatio->SetKeys(xkey, "ration", "ratione");
    transmissionRatio->Dump();

    eca.AddToHeader("correction", "intensity coorection at monitor");
    eca.Add(*beamIntensity);
    eca.Add(*sampleIntensity);

//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": exit " << std::endl;
}


void AdvNeutronMonitorDNA::toContainer(ElementContainer& sampleIntensity) {
    std::string memberName = std::string("toContainer(ElementContainerArray&)");

//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": enter " << std::endl;

    HeaderBase *header = this->monitorCount->PutHeaderPointer();
    std::string xkey = this->monitorCount->PutXKey();
    std::string ykey = this->monitorCount->PutYKey();
    std::string ekey = this->monitorCount->PutEKey();
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": xkey= " << xkey << std::endl;
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": ykey= " << ykey << std::endl;
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": ekey= " << ekey << std::endl;

 //   ElementContainer* sampleIntensity    = new ElementContainer(*header);

 //   std::vector<Double> e =*(new std::vector<Double>(this->monitorCount->PutSize(ekey), 0.0));

    sampleIntensity.InputHeader(*header);
    sampleIntensity.AddToHeader("correction", "intensity at sample");
    sampleIntensity.Add(xkey, this->monitorCount->PutX(), this->monitorCount->PutUnit(xkey));
    sampleIntensity.Add(ykey, intensityAtSample,          this->monitorCount->PutUnit(ykey));
    sampleIntensity.Add(ekey, intensityAtSampleErr,       this->monitorCount->PutUnit(ykey));
    sampleIntensity.SetKeys(xkey, ykey, ekey);

//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": exit " << std::endl;
}


ElementContainerArray AdvNeutronMonitorDNA::getCorrection() {
    std::string memberName = std::string("getCorrection()");

    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": enter " << std::endl;

    HeaderBase *header = this->monitorCount->PutHeaderPointer();
    std::string xkey = this->monitorCount->PutXKey();
    std::string ykey = this->monitorCount->PutYKey();
    std::string ekey = this->monitorCount->PutEKey();
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": xkey= " << xkey << std::endl;
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": ykey= " << ykey << std::endl;
//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": ekey= " << ekey << std::endl;

    ElementContainer* beamIntensity      = new ElementContainer(*header);
    ElementContainer* sampleIntensity    = new ElementContainer(*header);
    ElementContainer* transmissionRatio  = new ElementContainer(*header);

    beamIntensity->AddToHeader("correction", "intensity at monitor");
    beamIntensity->Add(xkey, this->monitorCount->PutX(), this->monitorCount->PutUnit(xkey));
    beamIntensity->Add(ykey, intensityAtMonitor,         this->monitorCount->PutUnit(ykey));
    beamIntensity->Add(ekey, intensityAtMonitorErr,      this->monitorCount->PutUnit(ekey));
    beamIntensity->SetKeys(xkey, ykey, ekey);

    sampleIntensity->AddToHeader("correction", "intensity at sample");
    sampleIntensity->Add(xkey, this->monitorCount->PutX(), this->monitorCount->PutUnit(xkey));
    sampleIntensity->Add(ykey, intensityAtSample,          this->monitorCount->PutUnit(ykey));
    sampleIntensity->Add(ekey, intensityAtSampleErr,       this->monitorCount->PutUnit(ekey));
    sampleIntensity->SetKeys(xkey, ykey, ekey);

    std::vector<Double> ratioV = *(new std::vector<Double>(observedAtMonitor.size()));
    std::vector<Double> ratioVerr = *(new std::vector<Double>(observedAtMonitor.size()));
    for (UInt4 i=0; i<observedAtMonitor.size(); ++i) {
        ratioV.at(i) = intensityAtSample.at(i)/intensityAtMonitor.at(i);
        ratioVerr.at(i) = intensityAtSample.at(i)/intensityAtMonitor.at(i) * sqrt(pow((intensityAtSampleErr.at(i)/intensityAtSample.at(i)),2.0)
                          +pow((intensityAtMonitorErr.at(i)/intensityAtMonitor.at(i)),2.0));
    }

    transmissionRatio->AddToHeader("correction", "transmission ratio");
    transmissionRatio->Add(xkey,     this->monitorCount->PutX(), monitorCount->PutUnit(xkey));
    transmissionRatio->Add(std::string("ration"), ratioV                                          ); // no dimention
    transmissionRatio->Add(std::string("ratione"), ratioVerr                                      ); // no dimention
    transmissionRatio->SetKeys(xkey, "ration", "ratione");

    ElementContainerArray* eca = new ElementContainerArray();
    eca->AddToHeader("correction", "intensity coorection at monitor");
    eca->Add(*beamIntensity);
    eca->Add(*sampleIntensity);
    eca->Add(*transmissionRatio);

//    std::cerr << "Fine: AdvNeutronMonitorDNA::" << memberName << ": " << __FILE__ << ":" << __LINE__ << ": exit " << std::endl;
    return *eca;
}
