#include "MlfScatAbsoBodyManager.hh"
//////////////////////////////////////////////////////////////////////////
MlfScatAbsoBodyManager::MlfScatAbsoBodyManager(){
    Initialize();
}
//////////////////////////////////////////////////////////////////////////
MlfScatAbsoBodyManager::MlfScatAbsoBodyManager(std::string _detectInfoPath, std::string _nistDataPath){
    Initialize();
    if (SetXmlInfoFile(_detectInfoPath, _nistDataPath)){
    }else{
        std::cout << _MessageTag+"Not found xml path = "+_detectInfoPath+" or "+_nistDataPath<< std::endl;
        Status = false;
    }
}
//////////////////////////////////////////////////////////////////////////
MlfScatAbsoBodyManager::~MlfScatAbsoBodyManager(){
    if (_BXP!=NULL) delete _BXP;
    delete _Xtable_name;
    delete _Xtable_velocity;
    delete _Xtable_cohCS;
    delete _Xtable_incCS;
    delete _Xtable_scaCS;
    delete _Xtable_absCS;

}
//////////////////////////////////////////////////////////////////////////
void MlfScatAbsoBodyManager::Initialize(){
    _MessageTag = "MlfScatAbsoBodyManager::";
    _BXP = new BoostXmlParser();
    _BXP->SetQuiet(true);
    Status = false;
    isDebug = false;
    _DetectorStructureInfo = "";

    _Xtable_name     = new std::vector<std::string>;
    _Xtable_velocity = new std::vector<double>;
    _Xtable_cohCS    = new std::vector<double>;
    _Xtable_incCS    = new std::vector<double>;
    _Xtable_scaCS    = new std::vector<double>;
    _Xtable_absCS    = new std::vector<double>;
    _XML_KEY_NISTDATA = "xml_key_nistdata";
    _XML_KEY_DETDATA  = "xml_key_detdata";
    _XML_NAME_NISTDATA = "NistXsectData.xml";
    isLoadedDefaultNistData = false;

    //_SearchXmlPath="";
    wallInfo.initialize();
    detectorInfo.initialize();
    epsilon=1.0e-05;
    epsilonRatio=1.0e-04;

    Status = _SetDefaultNistData();

}
//////////////////////////////////////////////////////////////////////////
bool MlfScatAbsoBodyManager::_SetDefaultNistData(){
    if (isLoadedDefaultNistData) return true;
    const char *manyopath_c = getenv("MANYO_PATH");
    if (manyopath_c!=NULL){
        char nistdatapath_c[400];
        std::snprintf( nistdatapath_c, sizeof(nistdatapath_c), "%s/share/Manyo/MLF/database/%s", manyopath_c, _XML_NAME_NISTDATA.c_str() );
        std::fstream fo(nistdatapath_c, std::ios::in);
        if (fo.fail()){
	    std::cout << _MessageTag + "_SetDefaultNistData >> Not found Nist data : " << nistdatapath_c << std::endl;
            std::snprintf( nistdatapath_c, sizeof(nistdatapath_c), "%s/../../../share/Manyo/MLF/database/%s",manyopath_c, _XML_NAME_NISTDATA.c_str());
            std::fstream fo2(nistdatapath_c, std::ios::in);
            if (fo2.fail()){
                std::cerr << _MessageTag+"_SetDefaultNistData >> Not found NIST data : " << nistdatapath_c <<std::endl;;
                //std::cerr << nistdatapath_c<<"/share/Manyo/MLF/database/"+_XML_NAME_NISTDATA << std::endl;
                //std::cerr << nistdatapath_c<<"/Manyo/MLF/database/"+_XML_NAME_NISTDATA << std::endl;
                return false;
            }
        }
        std::string nistdatapath_s(nistdatapath_c);
        if (nistdatapath_s!=""){
            if ( SetNistXmlFile( nistdatapath_s ) ){
                isLoadedDefaultNistData = true;
                std::cout << _MessageTag+"_SetDefaultNisData >> succeeded to set NIST atomic data.("+nistdatapath_s +")"<<std::endl;
                return true;
            }
        }
    }
    return false;
}
//////////////////////////////////////////////////////////////////////////
//void MlfScatAbsoBodyManager::SetXmlPath( std::string path ){
//    _SearchXmlPath = path;
//}
//////////////////////////////////////////////////////////////////////////
bool MlfScatAbsoBodyManager::SetNistXmlFile(std::string _nistDataPath){
    if (_BXP==NULL) _BXP = new BoostXmlParser();
    else{
        _BXP->Clear(_XML_KEY_NISTDATA,true);
    }

    isLoadedDefaultNistData = false;
    if (_BXP->Load( _XML_KEY_NISTDATA, _nistDataPath )){
        Status = true;
    }else{
        std::cout << _MessageTag+"SetNistXmlFile >> Not found NIST data ="+_nistDataPath<<std::endl;
        if (_SetDefaultNistData()){
            std::cout << _MessageTag+"SetNistXmlFile >> Use Default NIST data"<<std::endl;
            Status = true;
        }else{
            Status = false;
        }
    }

    return Status;
}
//////////////////////////////////////////////////////////////////////////
bool MlfScatAbsoBodyManager::SetDetectorInfoFile(std::string detectorInfoPath){
    if (_BXP==NULL) _BXP = new BoostXmlParser();
    else{
        _BXP->Clear(_XML_KEY_DETDATA,true);
    }

    if (_BXP->Load( _XML_KEY_DETDATA, detectorInfoPath )){
        Status = true;
        return true;
    }else{
        std::cout << _MessageTag+"SetXmlInfoFile >> not found detectorInfo="+detectorInfoPath << std::endl;
        Status = false;
        return false;
    }
}
//////////////////////////////////////////////////////////////////////////
bool MlfScatAbsoBodyManager::SetXmlInfoFile(std::string detectorInfoName, std::string _nistDatapath){
    if (_BXP==NULL) _BXP = new BoostXmlParser();
    Status = false;
    if (detectorInfoName==""){
        std::cout << _MessageTag+"SetXmlInfoFile >> not found detectorInfo="+detectorInfoName << std::endl;
    }else{
        if (SetDetectorInfoFile(detectorInfoName)){
            if (_nistDatapath!="")
                Status = SetNistXmlFile(_nistDatapath);
            else
                Status = _SetDefaultNistData();
        }else
            Status = false;
    }

    return Status;

    //std::string search_path = _SearchXmlPath;

    /**
    // Load DetectorInfo.xml
    char detinfo_tmp[300];
    std::sprintf( detinfo_tmp, "%s/%s", search_path.c_str(), detectorInfoName.c_str() );
    std::string detinfo_path( detinfo_tmp );

    if (_BXP==NULL) _BXP = new BoostXmlParser();
    else{
        _BXP->Clear();
    }
    if (_BXP->Load( _XML_KEY_DETDATA, detinfo_path )){
    }else{
        std::cout << _MessageTag+"SetNistXsecData >> not found detectorInfo="+detinfo_path << std::endl;
        Status = false;
        return false;
    }

    // Load NistXsectData.xml
    std::string nist_data_xml_file = _XML_NAME_NISTDATA;

    if (_nistDatapath!=""){
        std::string::size_type s = _nistDatapath.find_last_of("/");
        if (s==std::string::npos){
            nist_data_xml_file = _nistDatapath;
        }else{
            nist_data_xml_file = _nistDatapath.substr( s );
            search_path = _nistDatapath.erase(s);
        }
        std::cout << _MessageTag+"SetNistXsecData >> nist_data_xml_file="+nist_data_xml_file<<std::endl;
        std::cout << _MessageTag+"SetNistXsecData >> search path="+search_path<<std::endl;
    }

    char tmp[300];
    std::sprintf( tmp, "%s/%s", search_path.c_str(), nist_data_xml_file.c_str() );
    std::string path( tmp );

    if (_BXP->Load( _XML_KEY_NISTDATA, path )){
        Status = true;
    }else{
        std::cout << _MessageTag+"SetNistXsecData >> Not found NIST data ="+path<<std::endl;
        Status = false;
        return false;
    }

    return true;
    **/
}
//////////////////////////////////////////////////////////////////////////
bool MlfScatAbsoBodyManager::SetDetName( std::string det_name ){
    if (_BXP->hasKey( _XML_KEY_DETDATA )){
    }else{
        std::cout << _MessageTag+"SetDetName >> Not set DetectorInfo file" << std::endl;
        return false;
    }
    SetInfoData(det_name, &wallInfo, &detectorInfo);
    if (this->Status){
    }else{
        return false;
    }
    if (isDebug){
        std::cout << "## wallInfo.weightPerVolume="<< wallInfo.weightPerVolume << std::endl;
        std::cout << "##wallInfo.effectiveAtomicWeight="<<wallInfo.effectiveAtomicWeight<<std::endl;
        std::cout << "##detectorInfo.gasPressure="<<detectorInfo.gasPressure<<std::endl;
        std::cout << "##detectorInfo.temperature="<<detectorInfo.temperature<<std::endl;
    }
    wallInfo.totalDensity=wallInfo.weightPerVolume*MLF_KG2G/wallInfo.effectiveAtomicWeight*MLF_NA;
    if (detectorInfo.weightPerVolume>0.0){
        detectorInfo.totalDensity=detectorInfo.weightPerVolume*MLF_KG2G/detectorInfo.effectiveAtomicWeight*MLF_NA;
    }else{
        detectorInfo.totalDensity=detectorInfo.gasPressure*MLF_ATM2PA/MLF_kB/detectorInfo.temperature; // SI unit
    }
    return true;
}
//////////////////////////////////////////////////////////////////////////
bool MlfScatAbsoBodyManager::AddSigmaToXtable(std::string atomname){

    if (_BXP->hasKey( _XML_KEY_NISTDATA )){
        Double velo,cohCS, incCS, scaCS, absCS;

        bool isIsotope=false;
        char *endp;
        UInt4 val;
        val = strtol( atomname.c_str(), &endp, 10 );
        if (val!=0) isIsotope=true;
        std::string AtomName(endp);

        std::string path = "NistXsecData/No,AtomName="+AtomName;

        bool isSetVelo = false;
        bool isSetCohxs = false;
        bool isSetIncxs = false;
        bool isSetScatxs = false;
        bool isSetAbsxs = false;
        if (_BXP->hasPath( _XML_KEY_NISTDATA, path )){
            velo = 0.0;
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Velocity") ){
                velo = _stools->StringToDouble(
                    _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Velocity", "") );
                isSetVelo=true;
            }
        }else{
            std::cout << _MessageTag+"AddSigmaToXtable>>> we Not found "+path << std::endl;
        }
        if (isIsotope) path += "/Isotope,Name="+atomname;

        if (_BXP->hasPath( _XML_KEY_NISTDATA, path )){
            // cohCS
            cohCS = 0.0;
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Cohxs") ){
                std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Cohxs", "");
                if (tmp.find("--")==std::string::npos) cohCS = _stools->StringToDouble(tmp);
                isSetCohxs = true;
            }
            // incCS
            incCS = 0.0;
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Incxs") ){
                std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Incxs", "");
                if (tmp.find("--")==std::string::npos) incCS = _stools->StringToDouble(tmp);
                isSetIncxs = true;
            }
            // ScaCS
            scaCS = 0.0;
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Scattxs") ){
                std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Scattxs", "");
                if (tmp.find("--")==std::string::npos) scaCS = _stools->StringToDouble(tmp);
                isSetScatxs = true;
            }
            // AbsCS
            absCS = 0.0;
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Absxs") ){
                std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Absxs", "");
                if (tmp.find("--")==std::string::npos) absCS = _stools->StringToDouble(tmp);
                isSetAbsxs = true;
            }
        }else{
            std::cout << _MessageTag+"AddSigmaToXtable >> not found AtomName :"+atomname << std::endl;
            return false;
        }

        if ((isSetVelo)&&(isSetCohxs)&&(isSetIncxs)&&(isSetScatxs)&&(isSetAbsxs)){
            _Xtable_name->push_back(atomname);
            _Xtable_velocity->push_back(velo);
            _Xtable_cohCS->push_back(cohCS);
            _Xtable_incCS->push_back(incCS);
            _Xtable_scaCS->push_back(scaCS);
            _Xtable_absCS->push_back(absCS);
        }else{
            std::cout << _MessageTag+"AddSigmaToXtable >> not get enough params about"+atomname << std::endl;
            return false;
        }
    }
    return true;
}
//////////////////////////////////////////////////////////////////////////
Double MlfScatAbsoBodyManager::GetAtomicWeight(std::string atomname){
    if (_BXP->hasKey(_XML_KEY_NISTDATA)){
    }else{
        std::cout << _MessageTag+"GetAtomicWeight >> SetNistXsecData was not executed correctly." << std::endl;
        Status = false;
        return 0.0;
    }

    char *endp;
    UInt4 val;
    val = strtol( atomname.c_str(), &endp, 10 );
    bool isIsotope=false;
    if (val!=0) isIsotope=true;
    std::string AtomName(endp);

    std::string target_path = "";
    std::string path = "NistXsecData/No,AtomName="+AtomName;
    if (_BXP->hasPath(_XML_KEY_NISTDATA,path)){
        if (isIsotope){
            std::string iso_path = path+"/Isotope,Name="+atomname;
            if (_BXP->hasPath(_XML_KEY_NISTDATA,iso_path))
                target_path = iso_path;
        }else{
            target_path = path;
        }
    }
    if (target_path==""){
        std::cout << _MessageTag+"GetAtomicWeight >> Not found atomneme in database ("+atomname+")" << std::endl;
        Status = false;
        return 0.0;
    }

    double ret = _stools->StringToDouble( _BXP->PutContent( _XML_KEY_NISTDATA, target_path, "MolWeight" ) );
    if (ret!=0.0) Status = true;
    else Status = false;
    return ret;
}
//////////////////////////////////////////////////////////////////////////
void MlfScatAbsoBodyManager::SetInfoData(std::string det_name, struct ScatAbsoInfo* wallInfo, struct ScatAbsoInfo* bodyInfo){

    if (_BXP->hasKey(_XML_KEY_DETDATA)){
    }else{
        std::cout << _MessageTag+"SetInfoData >> SetNistXsecData was not executed correctly." << std::endl;
        Status = false;
        return;
    }
    std::vector<Double> tmpAtomicWeight(2,0.0);
    std::string detector_path = "";
    if (det_name.empty())
        detector_path = "detectorInfo/detectorStructure/detector";
    else
        detector_path = "detectorInfo/detectorStructure/detector,name="+det_name;
    if (_BXP->hasPath( _XML_KEY_DETDATA, detector_path )){
        _DetectorStructureInfo = _BXP->OutToString( _XML_KEY_DETDATA, detector_path, true );
        std::vector<ScatAbsoInfo*> Infos(2,NULL);
        Infos[0] = wallInfo;
        Infos[1] = bodyInfo;

        std::vector<std::string> Comps(2,"");
        Comps[0] = "wall";
        Comps[1] = "body";

        for (UInt4 i=0; i<Comps.size(); i++){
            std::string comp_ele_path = detector_path+"/"+Comps[i]+"/element";
            std::vector<std::string> ele_name_list = _BXP->PutAttValList( _XML_KEY_DETDATA, comp_ele_path, "name" );
            if (ele_name_list.empty()){
                std::cout << _MessageTag+"SetInfoData >> Name is empty, path="<< comp_ele_path << std::endl;
            }else{
                for (std::vector<std::string>::iterator it=ele_name_list.begin(); it!=ele_name_list.end(); ++it){
                    //std::cout << _MessageTag+"SetInfoData >> Set infoabout "+(*it) << std::endl;
                    Infos[i]->atomname.push_back( (*it) );
                    std::string a_element_path = comp_ele_path+",name="+(*it);
                    double v1 = _stools->StringToDouble( _BXP->PutContent( _XML_KEY_DETDATA, a_element_path, "wt-ratio" ) );
                    double v2 = GetAtomicWeight( (*it) );
                    v1=v1*100.0;
                    Infos[i]->atomDensityRatio.push_back(v1/v2);
                    tmpAtomicWeight[i]+=v1;

                    if (AddSigmaToXtable( (*it) )){
                    }else{
                        std::cout << _MessageTag+"SetInfoData >> Not found Atom Info about "+(*it) << std::endl;
                        Status=false;
                        return;
                    }
                }
            }

            std::string form_info_path = detector_path+"/"+Comps[i]+"/form";
            if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path )){
                std::string form_type=_BXP->PutContent( _XML_KEY_DETDATA, form_info_path+"/type", "" );
                if (form_type.find("slab")!=std::string::npos){
                    Infos[i]->form=slab;
                }else if (form_type.find("cylinder")!=std::string::npos){
                    Infos[i]->form=cylinder;
                }else if (form_type.find("column")!=std::string::npos){
                    Infos[i]->form=column;
                }else{
                    std::cout << _MessageTag+"SetInfoData >> Wrong Body type in xml" << std::endl;
                    Status=false;
                    return;
                }

                if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path+"/out_radius" )){
                    double radius = _stools->StringToDouble(
                        _BXP->PutContent( _XML_KEY_DETDATA, form_info_path+"/out_radius", "" ) );
                    Infos[i]->rl=radius*MLF_MM2M;
                }
                if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path+"/in_radius" )){
                    double radius = _stools->StringToDouble(
                        _BXP->PutContent( _XML_KEY_DETDATA, form_info_path+"/in_radius", "" ) );
                    Infos[i]->rs=radius*MLF_MM2M;
                }
                if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path+"/height" )){
                    double height = _stools->StringToDouble(
                        _BXP->PutContent( _XML_KEY_DETDATA, form_info_path+"/haight", "" ) );
                    Infos[i]->height=height*MLF_MM2M;
                }
                if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path+"/width" )){
                    double width = _stools->StringToDouble(
                        _BXP->PutContent( _XML_KEY_DETDATA, form_info_path+"/width", "" ) );
                    Infos[i]->width=width*MLF_MM2M;
                }
            }else{
                std::cout << _MessageTag+"SetInfoData >> Not found wall form info in xml" << std::endl;
                Status=false;
                return;
            }

            form_info_path = detector_path+"/"+Comps[i]+"/ratio_T";
            if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path )){
                Infos[i]->ratioT = _stools->StringToDouble(
                    _BXP->PutContent( _XML_KEY_DETDATA, form_info_path, "" ) );
            }
            form_info_path = detector_path+"/"+Comps[i]+"/temperature";
            if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path )){
                Infos[i]->temperature = _stools->StringToDouble(
                    _BXP->PutContent( _XML_KEY_DETDATA, form_info_path, "" ) );
            }
            form_info_path = detector_path+"/"+Comps[i]+"/pressure";
            if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path )){
                Infos[i]->gasPressure = _stools->StringToDouble(
                    _BXP->PutContent( _XML_KEY_DETDATA, form_info_path, "" ) );
            }
            form_info_path = detector_path+"/"+Comps[i]+"/weight_per_volume";
            if (_BXP->hasPath( _XML_KEY_DETDATA, form_info_path )){
                Infos[i]->weightPerVolume = _stools->StringToDouble(
                    _BXP->PutContent( _XML_KEY_DETDATA, form_info_path, "" ) );
            }
        }
    }else{
            std::cout << _MessageTag+"SetInfoData >> Not found det_name="+det_name+" in detectorStructure/detector info xml" << std::endl;
            Status=false;
            return;
    }

    // normalization of atomDensityRatio and set effectiveAtomicWeight for wall and body
    Double sum=0.0;
    for (UInt4 i=0; i<wallInfo->atomname.size(); i++) {
        sum+=wallInfo->atomDensityRatio[i];
    }
    for (UInt4 i=0; i<wallInfo->atomname.size(); i++) {
        wallInfo->atomDensityRatio[i]/=sum;
    }
    //wallInfo->effectiveAtomicWeight=tmpAtomicWeightWall/sum;
    wallInfo->effectiveAtomicWeight=tmpAtomicWeight[0]/sum;

    sum=0.0;
    for (UInt4 i=0; i<bodyInfo->atomname.size(); i++) {
        sum+=bodyInfo->atomDensityRatio[i];
    }
    for (UInt4 i=0; i<bodyInfo->atomname.size(); i++) {
        bodyInfo->atomDensityRatio[i]/=sum;
    }
    //bodyInfo->effectiveAtomicWeight=tmpAtomicWeightBody/sum;
    bodyInfo->effectiveAtomicWeight=tmpAtomicWeight[1]/sum;

}
//////////////////////////////////////////////////////////////////////////
void MlfScatAbsoBodyManager::SetSigmaDataNIST(Double velocity, std::string atomname, std::string typeCS){

    Double velo,cohCS, incCS, scaCS, absCS;
    bool isFound = false;
    for (UInt4 i=0; i<(_Xtable_name->size()); i++){
        if (_Xtable_name->at(i)==atomname){
            velo=_Xtable_velocity->at(i);
            dataCS[0][0]=velo;
            cohCS = _Xtable_cohCS->at(i);
            incCS = _Xtable_incCS->at(i);
            scaCS = _Xtable_scaCS->at(i);
            absCS = _Xtable_absCS->at(i);
            isFound = true;
            break;
        }
    }

    if (isFound){
    }else{
        if (AddSigmaToXtable( atomname )){
            velo=_Xtable_velocity->back();
            cohCS = _Xtable_cohCS->back();
            incCS = _Xtable_incCS->back();
            scaCS = _Xtable_scaCS->back();
            absCS = _Xtable_absCS->back();
            isFound = true;
        }else{
            std::cout << _MessageTag+"SetSigmaDataNIST >> not found info about "+atomname+" in NIST data" << std::endl;
            dataCS[0][0]=0.0;
            dataCS[0][1]=0.0;
            return;
        }
    }

    if(typeCS.find("_t")!=std::string::npos){

        if (SigmaCoefficientIsReady())
            {
                dataCS[0][1]=incCS*incCSF + cohCS*cohCSF + absCS*absCSF*dataCS[0][0]/velocity;
            }
        else{
            dataCS[0][1]=scaCS+absCS*dataCS[0][0]/velocity;
        }

    }
    else if(typeCS.find("_a")!=std::string::npos){
        dataCS[0][1]=absCS*dataCS[0][0]/velocity;

    }
    else if(typeCS.find("_s")!=std::string::npos){
        dataCS[0][1]=scaCS;

    }
    else if(typeCS.find("_c")!=std::string::npos){
        dataCS[0][1]=cohCS;

    }
    else if(typeCS.find("_i")!=std::string::npos){
        dataCS[0][1]=incCS;

    }
    else {
        std::cerr << "error exit"<<std::endl;
        exit(1);
    }

}
//////////////////////////////////////////////////////////////////////////
void MlfScatAbsoBodyManager::DumpXtable(){
    for (UInt4 i=0; i<(_Xtable_velocity->size()); i++){
        std::cout << (*_Xtable_name)[i] << " : v=" << (*_Xtable_velocity)[i] << ", coh=" <<(*_Xtable_cohCS)[i];
        std::cout << ", inc=" << (*_Xtable_incCS)[i] << ", sca=" << (*_Xtable_scaCS)[i] << ", abs=" << (*_Xtable_absCS)[i] << std::endl;
    }
}
//////////////////////////////////////////////////////////////////////////
Double MlfScatAbsoBodyManager::GetAtomSigmaWithEnergy( std::string atomname, std::string xstype, Double energy ){
    Double cVtoE = (MLF_Mn/2.0)*MLF_J2MEV*1.0e12;    //[meter/micro-sec] -> [meV]
    Double speed = sqrt(energy/cVtoE)*1000.0*1000.0; //[meter/micro-sec] -> [meter/sec]
    const char* c = xstype.c_str();
    return GetAtomSigmaFromVelocityRule( atomname, c[0], speed );
}
//////////////////////////////////////////////////////////////////////////
Double MlfScatAbsoBodyManager::GetAtomSigmaWithLambda( std::string atomname, std::string xstype, Double lambda ){
    Double cVtoLambda = MLF_HBAR*2.*MLF_PI/MLF_Mn*10000.; //[meter/micro-sec]/[kg] -> [Ang]
    Double speed = cVtoLambda/lambda*1000.0*1000.0;       //-> [meter/sec]
    const char* c = xstype.c_str();
    return GetAtomSigmaFromVelocityRule( atomname, c[0], speed );
}

//////////////////////////////////////////////////////////////////////////
Double MlfScatAbsoBodyManager::GetEfficiency(Double eneNeutron, Double thetaDetector){
  Double sigmaDA, sigmaWA, sigmaWS;
  Double energy=eneNeutron*MLF_MEV2J;

  GetSigmas(energy, &sigmaDA, &sigmaWA, &sigmaWS);
  if (isDebug){
      std::printf("=========================\n");
      std::printf(" Energy = %f [meV]\n", eneNeutron );
  }
  return CalcEfficiencyDetector(thetaDetector, sigmaDA, sigmaWS, sigmaWA);
}
//////////////////////////////////////////////////////////////////////////
void MlfScatAbsoBodyManager::GetSigmas(Double energy, Double* sigmaDA, Double* sigmaWA, Double* sigmaWS){
    Double sigmaDetectorA, sigmaWallA, sigmaWallS;
  GetSigmaFromVelocityRule(&wallInfo, &detectorInfo, energy, &sigmaDetectorA, &sigmaWallA, &sigmaWallS);
  *sigmaDA=sigmaDetectorA;
  *sigmaWA=sigmaWallA;
  *sigmaWS=sigmaWallS;
}
//////////////////////////////////////////////////////////////////////////
Double MlfScatAbsoBodyManager::CalcEfficiencyDetector(Double thetaDetector,
                                                  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 radiusInnerDetector=detectorInfo.rs;
  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
  //std::printf("n3He=%e, nwall=%e\n", n3He, nwall);
  if (isDebug){
      std::printf("---------------------------\n");
      std::printf("radiusBody=%f, radiusInnerBody=%f, radiusWall=%f\n", radiusDetector, radiusInnerDetector, radiusWall);
      std::printf("---------------------------\n");
      std::printf("sigmaBA = %e\n", sigmaDA);
      std::printf("sigmaWS = %e\n", sigmaWS);
      std::printf("sigmaWA = %e\n", sigmaWA);
      std::printf("A_body  = %f\n", n3He*sigmaDA );
      std::printf("A_wall  = %f\n", nwall*sigmaWA );
      std::printf("---------------------------\n");
  }
  // integral was done by use of Guauss-Legendre (m=6) method
  UInt4 max=10000;
  UInt4 nDiv;
  Double dx;
  Double x1=0.0;
  Double xi;

  const 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, radiusInnerDetector, 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 MlfScatAbsoBodyManager::ReturnAbsorptionByDetector(Double x, Double theta,
                                                          Double sigmaDA, Double sigmaWS, Double sigmaWA,
                                                          Double radiusDetector, Double radiusInnerDetector, Double radiusWall, Double n3He, Double nwall, Double T){
  Double tx, fx, txWall, sigmaWEffa;

/* Final version*/
  if (x*radiusDetector>radiusInnerDetector){
      tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta);
      txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-0.5*tx;
  }else{
      Double tx_in =2.0*sqrt(radiusInnerDetector*radiusInnerDetector - x*x*radiusDetector*radiusDetector)/cos(theta);
      tx=2.0*radiusDetector*sqrt(1.0-x*x)/cos(theta) - tx_in;
      txWall=sqrt(radiusWall*radiusWall-radiusDetector*radiusDetector*x*x)/cos(theta)-radiusDetector*sqrt(1.0-x*x)/cos(theta);
  }
  sigmaWEffa=(1.0-T)*sigmaWS+sigmaWA;
  fx=(1.0-exp(-n3He*sigmaDA*tx))*exp(-nwall*(sigmaWA+T*sigmaWS)*txWall)*(radiusDetector/radiusWall);
/*end*/

  return fx;
}

//////////////////////////////////////////////////////////////////////////
Double MlfScatAbsoBodyManager::GetMolecularWeight( std::string form ){
    std::vector< std::pair<std::string,Double> > parts;
    Double ret = 0.0;
    if (_Transform( form, parts )){
        for (UInt4 i=0; i<parts.size(); i++){
            std::cout << parts[i].first << " : " << parts[i].second << std::endl;
            std::vector<Double> info(6,0.0);
            if (_GetAtomInfo( parts[i].first, info )){
                ret += info[0]*parts[i].second;
            }
        }
    }else{
        std::cout << _MessageTag+"GetMolecularWeight : failed tranform of "+form+"." << std::endl;
    }
    return ret;
}

//////////////////////////////////////////////////////////////////////////
Double MlfScatAbsoBodyManager::GetTotalXsectAve( std::string form ){
    std::vector< std::pair<std::string,Double> > parts;
    Double ret = 0.0;
    Double nums = 0.0;
    if (_Transform( form, parts )){
        for (UInt4 i=0; i<parts.size(); i++){
            std::cout << parts[i].first << " : " << parts[i].second << std::endl;
            std::vector<Double> info(6,0.0);
            if (_GetAtomInfo( parts[i].first, info )){
                ret += info[3]*parts[i].second;
                nums += parts[i].second;
            }
        }
        ret /= nums;
    }else{
        std::cout << _MessageTag+"GetTotalXsecAve : failed tranform of "+form+"." << std::endl;
    }
    return ret;
}

//////////////////////////////////////////////////////////////////////////
Double MlfScatAbsoBodyManager::GetNumberDensity( std::string form, Double density ){
    // density   : [g/cm^3]
    // molweight : [g/mol]
    // numeric dencity : [1/cm^3] = density*Na/molweight
    Double mol_weight = GetMolecularWeight( form );
    if (mol_weight>0.0)
        return density/mol_weight*MLF_NA;

    return 0.0;
}
//////////////////////////////////////////////////////////////////////////
bool MlfScatAbsoBodyManager::_Transform( std::string form, std::vector< std::pair<std::string,Double> > &parts ){
    std::vector<std::string> form_split = _stools->SplitString( form,"-" );

    for (UInt4 i=0; i<form_split.size(); i++){
        std::string moji = form_split[i]; // 24Mg2
        UInt4 moji_size=(UInt4)(moji.length());
        std::string iso_nu = "";
        std::string atom = "";
        std::string nums = "";
        bool isIsoFin = false;
        bool isBodyFin = false;

        for (UInt4 j=0; j<moji_size; j++){ // 2, 4, M, g, 2
            Char a_char = moji[j];
            if ((a_char>='0'&& a_char<='9')&&(!isIsoFin)){
                std::string tmp(1,a_char);
                iso_nu += tmp;
            }else if ((!isBodyFin)&&( (a_char>='a'&& a_char<='z') || (a_char>='A' && a_char<='Z') ) ){
                if (!isIsoFin) isIsoFin = true;
                std::string tmp(1,a_char);
                atom += tmp;
            }else if ((isIsoFin)&&(a_char>='0')&&(a_char<='9')){
                if (!isBodyFin) isBodyFin = true;
                std::string tmp(1,a_char);
                nums += tmp;
            }else{
                std::cout << _MessageTag+"_Transform ("+form+") : ignore a charactor (" << a_char << ")" << std::endl;
            }
        }
        std::cout << "iso_nu = "+iso_nu << std::endl;
        std::cout << "atom   = "+atom << std::endl;
        std::cout << "nums   = "+nums << std::endl;
        if ((isIsoFin)&&(atom!="")){
            std::pair<std::string,Double> a_part;
            a_part.first = iso_nu+atom;
            if (nums=="") nums="1";
            a_part.second = _stools->StringToDouble( nums );
            parts.push_back( a_part );
        }else{
            std::cout << _MessageTag+"_Transform ("+form+") : ignore an group (" << moji << ")" << std::endl;
        }
    }

    if (parts.size()!=form_split.size())
        return false;
    else
        return true;
}

//////////////////////////////////////////////////////////////////////////
bool MlfScatAbsoBodyManager::_GetAtomInfo( std::string atomname, std::vector<Double> &info ){
    if (info.size()!=6){
        info.clear();
        info.resize(6,0.0);  // MolWeight, cohCS, incCS, scaCS, absCS, velo
    }

    if (_BXP->hasKey( _XML_KEY_NISTDATA )){

        bool isIsotope=false;
        char *endp;
        UInt4 val;
        val = strtol( atomname.c_str(), &endp, 10 );
        if (val!=0) isIsotope=true;
        std::string AtomName(endp);

        std::string path = "NistXsecData/No,AtomName="+AtomName;

        if (_BXP->hasPath( _XML_KEY_NISTDATA, path )){
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Velocity") ){
                info[5] = _stools->StringToDouble(
                    _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Velocity", "") );
            }
        }else{
            std::cout << _MessageTag+"_GetXsect>>> we Not found "+path << std::endl;
        }
        if (isIsotope) path += "/Isotope,Name="+atomname;

        if (_BXP->hasPath( _XML_KEY_NISTDATA, path )){
            // MolWeight
            std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path, "MolWeight");
            if (tmp.find("--")==std::string::npos) info[0] = _stools->StringToDouble(tmp);

            // cohCS
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Cohxs") ){
                std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Cohxs", "");
                if (tmp.find("--")==std::string::npos) info[1] = _stools->StringToDouble(tmp);
            }
            // incCS
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Incxs") ){
                std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Incxs", "");
                if (tmp.find("--")==std::string::npos) info[2] = _stools->StringToDouble(tmp);
             }
            // ScaCS
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Scattxs") ){
                std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Scattxs", "");
                if (tmp.find("--")==std::string::npos) info[3] = _stools->StringToDouble(tmp);
            }
            // AbsCS
            if (_BXP->hasPath( _XML_KEY_NISTDATA, path+"/Absxs") ){
                std::string tmp = _BXP->PutContent( _XML_KEY_NISTDATA, path+"/Absxs", "");
                if (tmp.find("--")==std::string::npos) info[4] = _stools->StringToDouble(tmp);
            }
        }else{
            std::cout << _MessageTag+"_GetXsect >> not found AtomName :"+atomname << std::endl;
            return false;
        }
    }
    std::cout << "--------------------" << std::endl;
    std::cout << "Atom Name = "+atomname << std::endl;
    std::cout << "MolWeight = " << info[0] << std::endl;
    std::cout << "cohCS = " << info[1] << std::endl;
    std::cout << "incCS = " << info[2] << std::endl;
    std::cout << "scaCS = " << info[3] << std::endl;
    std::cout << "absCS = " << info[4] << std::endl;
    std::cout << "velo  = " << info[5] << std::endl;
    std::cout << std::endl;
    return true;
}
