#include "MlfArraySlicer.hh"

//////////////// Constructor /////////////////////
MlfArraySlicer::
MlfArraySlicer()
{
    _initialize();
}

////////////// Destructor ///////////////////////
MlfArraySlicer::
~MlfArraySlicer()
{
}
///////////// Constructor with Matrix data //////////////////////
MlfArraySlicer::
MlfArraySlicer( ElementContainerMatrix *ecm, std::string keyOfX, std::string keyOfY )
{
    _initialize();

    // Size Check
    if(ecm->PutTableSize() > 0){
        // Pick up The first array
        ElementContainerArray *eca = ecm->PutPointer(0);
        SetInputP( eca );
        SetAxes( keyOfX, keyOfY, false );
        // Take Run No. from Matrix eader.
        HeaderBase* hh = ecm->PutHeaderPointer();
        _runNo = "Unknown";
        if (hh->CheckKey("RUNNUMBER")==1){
            _runNo = hh->PutString("RUNNUMBER");
        }
        // Take Ei from Matrix header, if not exist, this data may be TOF or invalid
        if (hh->CheckKey("Ei")==1){
            Double ei = hh->PutDouble("Ei");
            std::cout <<  _MessageTag+"Constructor > Ei =" << ei << std::endl;
            _initData(ei);
        }
        else{
            // Try an array header
            _initData(0.0);
        }
    }
}

///////////// Constructor with Array data //////////////////////
MlfArraySlicer::
MlfArraySlicer( ElementContainerArray *eca, std::string keyOfX, std::string keyOfY )
{
    _initialize();

    // Take Run No. from Matrix eader.
    HeaderBase* hh = eca->PutHeaderPointer();
    _runNo = "Unknown";
    if (hh->CheckKey("RUNNUMBER")==1){
        _runNo = hh->PutString("RUNNUMBER");
    }

    SetInputP( eca );
    //SetInput( *eca );
    SetAxes( keyOfX, keyOfY, false );
    _initData(0.0);
}

////////////// Initialize ///////////////////////
void MlfArraySlicer::
_initialize()
{
    _debugMode = false;
    _regions.clear();
    _invalid = true;
    _MessageTag = "MlfArraySlicer::";

    _givenAxesKeys.clear();
    std::pair<std::string,UInt4> tmp;
    tmp.first= "";
    tmp.second= 0;
    _givenAxesKeys.push_back(tmp);
    _givenAxesKeys.push_back(tmp);

}
///////////// Initialize data //////////////////////
void MlfArraySlicer::
_initData( Double ei )
{
    ElementContainerArray* eca = PutInput();

    // Initialize Map data
    _invalid = false;
    _anisoBin2d.clear();
    _ints2d.clear();
    _errs2d.clear();
    _isoBin.clear();
    _Angles.clear();
    _keys.clear();
    _units.clear();
    _numMask = 0;
    _qBin = 0.0;
    _qRange.first = 0.0;
    _qRange.second = 0.0;

    // Check if data size is OK.
    if(eca->PutTableSize() == 0){
        std::cerr << _MessageTag+"_initData > Array size is 0." << std::endl;
        _invalid = true;
        return;
    }

    // Judge Data type from the first ElementContainer
    ElementContainer* ec = eca->PutPointer(0);

    std::string xkey = ec->PutXKey();
    _keys.push_back(xkey);
    _keys.push_back(ec->PutYKey());
    _keys.push_back(ec->PutEKey());
    _units.push_back(ec->PutUnit(xkey));
    _units.push_back(ec->PutUnit(ec->PutYKey()));
    _units.push_back(ec->PutUnit(ec->PutEKey()));

    //[inamura 130620]-->
    HeaderBase* hh_eca=eca->PutHeaderPointer();
    bool hasEi = false;
    bool hasEnergyAxis = false;
    bool isPowder = false;
    _isInelaPowder = false;
    if (hh_eca->CheckKey("Ei")==1){
        ei = hh_eca->PutDouble("Ei");
        hasEi=true;
    }
    if (xkey.find("Energy")!=-1) hasEnergyAxis=true;
    if (hh_eca->CheckKey("SAMPLETYPE")==1){
        if (hh_eca->PutString("SAMPLETYPE")=="Powder") isPowder=true;
    }
    if ((hasEnergyAxis)&&(isPowder)&&(ei>0.0)){
        std::cout <<  _MessageTag+"\nThis is Powder data with Energy axis." << std::endl;
        _isInelaPowder = true;
        _MakePowderMap(ei);
        _ei = ei;
    }else{
        // Prepare 2D Data
        _MakeRectMap();
        if (hasEnergyAxis) _ei=ei;
        else _ei = 0.0;
    }
    /*
    if (xkey == "Energy"){
        std::cout << "\nThis is Energy data."<< std::endl;
        // Not yet take ei?
        if (ei == 0.0){
            // Take Ei from Array header, if not exist, this data is invalid
            HeaderBase* hh = eca->PutHeaderPointer();
            if (hh->CheckKey("Ei")!=1){
                std::cout << "Error!!, Missing Ei in the header."<< std::endl;
                //[inamura 130619]--> if no Ei, treat as TOF
                //_invalid = true;
                //return;
                std::cout << "\nThis is treated as TOF data."<< std::endl;
                // Prepare 2D Data of TOF
                _MakeRectMap();
                _ei = 0.0;
                //<--[inamura 130619]
            }
            ei = hh->PutDouble("Ei");
            std::cout << "MlfArraySlicer::_initData >> Ei =" << ei << std::endl; //[inamura 130619]
            if (ei < 0.0){ //[inamura 130619]
                std::cout << "Error!!, EI value is invalid."<< std::endl;
                _invalid = true;
                return;
            }
        }
        // Calc Q and Prepare 2D Data
        _MakePowderMap(ei);
        _ei = ei;
    }
    else{
        std::cout << "\nThis is TOF data."<< std::endl;
        // Prepare 2D Data of TOF
        _MakeRectMap();
        _ei = 0.0;
    }
    */
    //<--[inamura 130620]
}

bool MlfArraySlicer::
SetAxes(std::string keyX, std::string keyY, bool doInitData ){
    ElementContainerArray* eca = PutInput();
    if (keyX!=""){
        _givenAxesKeys[0].first = "";
        _givenAxesKeys[0].second = 0;
        HeaderBase* hh_eca = eca->PutHeaderPointer();
        // keyX is in ECA header ( type = 5,6,7,8 )
        if (hh_eca->CheckKey(keyX)==1){
            UInt4 k = hh_eca->PutKeyLocation( keyX );
            if (k==4){        // keyX is std::vector<Int4>
                std::vector<Int4> tmp = hh_eca->PutInt4Vector(keyX);
                UInt4 eca_size = eca->PutTableSize();
                if (tmp.size()==eca_size){
                    _givenAxesKeys[0].first = keyX;
                    _givenAxesKeys[0].second = 5;
                }else if (tmp.size()==(eca_size+1)){
                    _givenAxesKeys[0].first = keyX;
                    _givenAxesKeys[0].second = 7;
                }
            }else if (k==5){  // keyX is std::vector<Double>
                std::vector<Double> tmp = hh_eca->PutDoubleVector(keyX);
                UInt4 eca_size = eca->PutTableSize();
                if (tmp.size()==eca_size){
                    _givenAxesKeys[0].first = keyX;
                    _givenAxesKeys[0].second = 6;
                }else if (tmp.size()==(eca_size+1)){
                    _givenAxesKeys[0].first = keyX;
                    _givenAxesKeys[0].second = 8;
                }
            }
        }else{ // keyX is NOT in ECA header ( type = 1,2,3,4 )
            HeaderBase* hh_ec = eca->PutPointer(0)->PutHeaderPointer();
            if (hh_ec->CheckKey(keyX)==1){
                UInt4 k = hh_ec->PutKeyLocation( keyX );
                if ((k==1)||(k==2)){     // KeyX is Int4 or Double
                    _givenAxesKeys[0].first = keyX;
                    _givenAxesKeys[0].second = k; // 1 or 2
                }else if (k==4){         // KeyX is std::vector<Int4>
                    std::vector<Int4> tmp = hh_ec->PutInt4Vector(keyX);
                    if (tmp.size()>=2){
                        _givenAxesKeys[0].first = keyX;
                        _givenAxesKeys[0].second = 3;
                    }
                }else if (k==5){         // KeyX is std::vector<Double>
                    std::vector<Double> tmp = hh_ec->PutDoubleVector(keyX);
                    if (tmp.size()>=2){
                        _givenAxesKeys[0].first = keyX;
                        _givenAxesKeys[0].second = 4;
                    }
                }
            }
        }
        if (_givenAxesKeys[0].first==""){
            std::cout << _MessageTag+"Given KeyX ("+keyX+") is ignored." << std::endl;
            return false;
        }
    }
    if (keyY!=""){
        _givenAxesKeys[1].first = "";
        _givenAxesKeys[1].second = 0;
        HeaderBase* hh_eca = eca->PutHeaderPointer();
        std::vector<Double> ec0_yvec = eca->PutPointer(0)->PutY();
        UInt4 ec0_yvec_size = (UInt4)(ec0_yvec.size());
        // If keyY is in ECA header ( type = 5,6,7,8 )
        if (hh_eca->CheckKey(keyY)==1){
            UInt4 k = hh_eca->PutKeyLocation( keyY );
            if (k==4){         // keyY is std::vector<Int4>
                std::vector<Int4> tmp = hh_eca->PutInt4Vector(keyY);
                if (tmp.size()==ec0_yvec_size){
                    _givenAxesKeys[1].first = keyY;
                    _givenAxesKeys[1].second = 5;
                }else if (tmp.size()==(ec0_yvec_size+1)){
                    _givenAxesKeys[1].first = keyY;
                    _givenAxesKeys[1].second = 7;
                }
            }else if (k==5){   // keyY is std::vector<Double>
                std::vector<Double> tmp = hh_eca->PutDoubleVector(keyY);
                if (tmp.size()==ec0_yvec_size){
                    _givenAxesKeys[1].first = keyY;
                    _givenAxesKeys[1].second = 6;
                }else if (tmp.size()==(ec0_yvec_size+1)){
                    _givenAxesKeys[1].first = keyY;
                    _givenAxesKeys[1].second = 8;
                }
            }
        }else if (eca->PutPointer(0)->CheckKey(keyY)==1){ // keyY is in EC as std::vector
            if ((eca->PutPointer(0)->PutYKey())==keyY){
                std::cerr << _MessageTag+"keyY("+keyY+") is used as Intensity " << std::endl;
                return false;
            }else{
                _givenAxesKeys[1].first = keyY;
                _givenAxesKeys[1].second = 0;
            }
        }
        if (_givenAxesKeys[1].first==""){
            std::cout << _MessageTag+"Given KeyY ("+keyY+") is ignored." << std::endl;
            return false;
        }
    }
    if (doInitData) _initData(_ei);

    return true;
}
//// Make Q and Energy 2D Map ////
void MlfArraySlicer::
_MakePowderMap(Double ei)
{
    ElementContainerArray* eca = PutInput();
    UInt4 dnum = eca->PutTableSize();

    // Prepare std::vector for angle prservation, -1.0 is masked value.
    std::vector<Double> pangles(dnum, -1.0);
    //std::cout << "Data size : " << dnum << std::endl;
    // Get angle data from each Header
    for (UInt4 i=0;i<dnum;i++){
        ElementContainer* ec = eca->PutPointer(i);
        HeaderBase* hh = ec->PutHeaderPointer();
        // Check if not masked
        if (hh->CheckKey("MASKED")!=1 || hh->PutInt4("MASKED") != 1){
            if (hh->CheckKey("PixelPolarAngle")!=1){
                std::cerr << _MessageTag+"_MakePowderMap >  Missing PixelPolarAngle in EC header:"<< i << std::endl;
                _invalid = true;
                return;
            }
            // Store angle(degree)
            pangles[i] = hh->PutDoubleVector("PixelPolarAngle")[0];
        }
        else{
            std::cout <<  _MessageTag+"_MakePowderMap > " << i << ": Masked" << std::endl;
        }
    }
    // Search adjacent angles that both are not masked for start and end.
    UInt4 begin = -1;
    UInt4 end = -1;
    for (UInt4 i=0;i<dnum-1;i++){
        if(pangles[i] >=0.0 && pangles[i+1] >=0.0){
            if(begin == (UInt4)-1){
                begin = i;
            }
            end = i;
        }
    }
    // Inappropriate data?
    if(begin == (UInt4)-1){
        std::cerr << _MessageTag+"_MakePowderMap > Inappropriate mask." << std::endl;
        _invalid = true;
        return;
    }
    // Make radian std::vector without masked ones
    std::vector<Double> pols;
    for (UInt4 i=0;i<dnum;i++){
        if (pangles[i] >= 0.0){
            // convert degree to radian
            Double radAngle = pangles[i]*M_PI/180.0;;
            pols.push_back(radAngle);
        }
    }

    // Add a dummy to the angle std::vector's last
    Double dummy = pangles[end+1]-pangles[end]+pangles[end+1];
    pols.push_back(dummy*M_PI/180.0);

    std::vector<Double> anglebin;
    std::vector<UInt4> angleIndex;
    anglebin.clear();
    angleIndex.clear();

    // Half length of the not masked first bin
    Double hfGap = (pangles[begin+1]-pangles[begin])*M_PI/180.0/2.0;

    // Start point (Not masked one)
    Double theta = pols[0] - hfGap;
    anglebin.push_back(theta);

    // Threshold for judging bank gap
    // Consider a bank gap when the gap is lerger than 1.5 times than prior gap.
    Double gapTh = hfGap*3.0;

    // Calc scattering angles of both side
    for(UInt4 i=0;i<pols.size()-1;i++){
        // Calc a difference from the prior angle
        Double gap = pols[i+1]-pols[i];

        // In case of bank gap or masked data
        if (gap >= gapTh){
            // Calc a left bin from prior data's half angle
            theta = pols[i] + hfGap;
            anglebin.push_back(theta);
            angleIndex.push_back(i);
            // Also write a right bin
            theta = pols[i+1] - hfGap;
            anglebin.push_back(theta);
            angleIndex.push_back(-1);
            //Renew threthold for bank gap
            gapTh = hfGap*3.0;
        }
        // Regular case
        else{
            hfGap = gap/2.0;
            theta = pols[i] + hfGap;
            anglebin.push_back(theta);
            angleIndex.push_back(i);
        }
    }

    // Preserve original angle data in header
    for ( UInt4 i = 0; i < angleIndex.size(); i++){
        if (angleIndex[i] == (UInt4)-1){
            _Angles.push_back(-1.0);
        }
        else{
            // Preserve each angle(degree) in header for making result EC7S header
            _Angles.push_back(pangles[angleIndex[i]]);
        }
    }

    // Get the first ebin that is common for every ElementContainer
    ElementContainer* ec0 = eca->PutPointer(0);
    _isoBin = ec0->PutX();
    // Number of int
    UInt4 ndat = (UInt4)(_isoBin.size())-1;

    UInt4 numA = (UInt4)(anglebin.size());
    // Reserve 2D Area for parallel processing
    _anisoBin2d.resize(numA);
    _ints2d.resize(numA-1);
    _errs2d.resize(numA-1);
    for (UInt4 i=0;i<numA-1;i++){
        _anisoBin2d[i].resize(ndat+1);
        _ints2d[i].resize(ndat);
        _errs2d[i].resize(ndat);
    }
    _anisoBin2d[numA-1].resize(ndat+1);

    Double ki2 = _EtoK2( ei );
    Double ki = sqrt(ki2);

    // For all Q bin
    //HistogramBinToPoint HTP;
    for (UInt4 i=0;i<numA-1;i++){
        // Bank data or masked data?
        if (angleIndex[i] == (UInt4)-1){
            // Put mask data
            for (UInt4 j=0;j<ndat;j++){
                _ints2d[i][j] = MLF_MASKVALUE;
                _errs2d[i][j] = 0.0;
            }
        }else{
            // Store Normal data
            ElementContainer* ec = eca->PutPointer(angleIndex[i]);
            // Convert Intensity to per unit
            //HTP.SetTarget(ec);
            //HTP.Convert();
            //std::vector<Double> yint = HTP.PutY();
            //std::vector<Double> err = HTP.PutE();
            std::vector<Double> yint = ec->PutY();
            std::vector<Double> err = ec->PutE();
            // For each data point
            for (UInt4 j=0;j<ndat;j++){
                if (err[j]<0.0) yint[j] = MLF_MASKVALUE;//[inamura 170131]
                _ints2d[i][j] = yint[j];
                _errs2d[i][j] = err[j];
            }
        }
    }

    // Calc Q for each bin
    for (UInt4 j=0;j < ndat+1;j++){
        Double kf = sqrt(_EtoK2( ei - _isoBin[j] ));
        for (UInt4 i=0;i < anglebin.size();i++){
            Double q = sqrt( ki2 + kf*kf - 2.0*ki*kf*cos(anglebin[i]));
            _anisoBin2d[i][j] = q;

        }
    }
    return;
}

//// Make TOF 2D Map ////
void MlfArraySlicer::
_MakeRectMap()
{
    ElementContainerArray* eca = PutInput();
    UInt4 dnum = eca->PutTableSize();

    //std::cout <<  _MessageTag+"_MakeRectMap > Data size : "+ _st->UInt4ToString(dnum) << std::endl;

    // Make 2D std::map data

    // Make Xbin
    std::vector<Double> xbin;
    std::pair<std::string,UInt4> keys = _givenAxesKeys[0];
    std::vector<UInt4> ECindex; // index of EC in ECA

    if (keys.first!=""){
        std::vector<Double> tmp;
        if (keys.second==1){
            tmp.resize(dnum);
            for (UInt4 i=0; i<dnum; i++)
                tmp[i] = double(eca->PutPointer(i)->PutHeaderPointer()->PutInt4(keys.first));
        }
        else if (keys.second==2){
            tmp.resize(dnum);
            for (UInt4 i=0; i<dnum; i++)
                tmp[i] = eca->PutPointer(i)->PutHeaderPointer()->PutDouble(keys.first);
        }else if (keys.second==3){
            tmp.resize(dnum);
            for (UInt4 i=0; i<dnum; i++){
                std::vector<Int4> tmp2 = eca->PutPointer(i)->PutHeaderPointer()->PutInt4Vector(keys.first);
                tmp[i] = (double)(tmp2[0]+tmp2[1])/2.0;
            }
        }else if (keys.second==4){
            tmp.resize(dnum);
            for (UInt4 i=0; i<dnum; i++){
                std::vector<Double> tmp2 = eca->PutPointer(i)->PutHeaderPointer()->PutDoubleVector(keys.first);
                tmp[i] = (tmp2[0]+tmp2[1])/2.0;
            }
        }else if (keys.second==5){
            tmp.resize(dnum);
            std::vector<Int4> tmp2 = eca->PutHeaderPointer()->PutInt4Vector(keys.first);
            for (UInt4 i=0; i<dnum; i++)
                tmp[i] = (double)(tmp2[i]);
        }else if (keys.second==6){
            tmp = eca->PutHeaderPointer()->PutDoubleVector(keys.first);
        }else if (keys.second==7){
            std::vector<Int4> tmp2 =  eca->PutHeaderPointer()->PutInt4Vector(keys.first);
            for (UInt4 i=0; i<tmp2.size(); i++)
                xbin.push_back( (Double)(tmp2[i]) );
        }else if (keys.second==8){
            xbin = eca->PutHeaderPointer()->PutDoubleVector(keys.first);
        }

        // sort x-axis values and make index for EC in ECA
        if (!tmp.empty()){
            ECindex.resize( tmp.size(), 0 );
            std::vector<Double> tmp_org( tmp );
            sort(tmp.begin(), tmp.end());
            for (UInt4 i=0; i<tmp.size(); i++)
                for (UInt4 j=0; j<tmp_org.size(); j++)
                    if (tmp[i]==tmp_org[j]) ECindex[i]=j;
        }

        if (tmp.empty()){
        }else{
            xbin.push_back(tmp[0]-(tmp[1]-tmp[0])/2.0);
            for (UInt4 i=0; i<(dnum-1); i++)
                xbin.push_back( tmp[i] + (tmp[i+1]-tmp[i])/2.0 );
            xbin.push_back(tmp.back()+(tmp.back()-tmp[tmp.size()-2])/2.0 );
        }
    }

    // Make Ybin
    std::vector<Double> eca_header_ybin;

    // If Ybin is in ECA Header
    if ((_givenAxesKeys[1].first!="")&&(_givenAxesKeys[1].second!=0)){
        std::vector<Double> tmp;
        if ((_givenAxesKeys[1].second==5)||(_givenAxesKeys[1].second==7)){     // Ybin is std::vector<Int4>
            std::vector<Int4> tmp_int = eca->PutHeaderPointer()->PutInt4Vector(_givenAxesKeys[1].first);
            tmp.resize( tmp_int.size() );
            for (UInt4 i=0; i<tmp_int.size(); i++)
                tmp[i] = (Double)tmp_int[i];

        }
        else if ((_givenAxesKeys[1].second==6)||(_givenAxesKeys[1].second==8)){ // Ybin is std::vector<Double>
            tmp = eca->PutHeaderPointer()->PutDoubleVector(_givenAxesKeys[1].first);
        }
        // Check size of Ybin, size of Ybin must be ( size of Intensity vect +1 )
        if ((_givenAxesKeys[1].second==5)||(_givenAxesKeys[1].second==6)){ // tmp.size()=ec0.PutY().size()
            eca_header_ybin.resize( tmp.size()+1 );
            eca_header_ybin[0] = tmp[0] - (tmp[1]-tmp[0])/2.0;
            for (UInt4 i=0; i<(tmp.size()-1); i++)
                eca_header_ybin[i+1] = (tmp[i+1]+tmp[i])/2.0;
            eca_header_ybin[ eca_header_ybin.size()-1 ] = tmp.back() + (tmp.back()-tmp[ tmp.size()-2 ])/2.0;
        }else{
            eca_header_ybin.resize( tmp.size() );
            copy( tmp.begin(), tmp.end(), eca_header_ybin.begin() );
        }
    }

    std::vector<Double> xrange;
    _unit_X = "";
    for (UInt4 i=0;i<dnum;i++){
        //std::cout <<"Index : "<< i <<std::endl;
        UInt4 ind = i;
        if (!ECindex.empty()) ind = ECindex[i];
        ElementContainer* ec = eca->PutPointer(ind);
        HeaderBase* hh = ec->PutHeaderPointer();
        if ((_unit_X=="")&&(hh->CheckKey(MLF_KEY_HEAD_XUNIT)==1))
            _unit_X = hh->PutString(MLF_KEY_HEAD_XUNIT);

        if (!(eca_header_ybin.empty())){
            _anisoBin2d.push_back( eca_header_ybin );
        }else{
            std::vector<Double> ybin;
            if (_givenAxesKeys[1].first==""){
                std::vector<Double> ec_bin = ec->PutX();
                ybin.resize( ec_bin.size() );
                copy( ec_bin.begin(), ec_bin.end(), ybin.begin() );
            }else{
                std::vector<Double> ec_vec=ec->Put( _givenAxesKeys[1].first );
                ybin.resize( ec_vec.size() );
                copy( ec_vec.begin(), ec_vec.end(), ybin.begin() );
            }

            UInt4 ybin_size = (UInt4)(ybin.size());
            UInt4 int_size  = (UInt4)(ec->PutY().size());
            if (ybin_size==(int_size+1)){
                _anisoBin2d.push_back(ybin);
            }else if (ybin_size==int_size){
                std::vector<Double> tmp( int_size+1 );
                tmp[0] = ybin[0] - (ybin[1]-ybin[0])/2.0;
                for (UInt4 j=0;j<(ybin_size-1);j++)
                    tmp[j+1] = (ybin[j+1]+ybin[j])/2.0;
                tmp[ tmp.size()-1 ] = ybin[ ybin_size-1 ] + (ybin[ybin_size-1]-ybin[ybin_size-2])/2.0;
                _anisoBin2d.push_back(tmp);
            }else{
                std::cout << _MessageTag+" Y axis info is invalid. Use index." << std::endl;
                std::vector<Double> tmp(ec->PutY().size()+1);
                for (UInt4 j=0; j<tmp.size(); j++)
                    tmp[j] = (Double)j;
                _anisoBin2d.push_back(tmp);
            }
        }
        // Check if not masked
        if (hh->CheckKey("MASKED")!=1 || hh->PutInt4("MASKED") != 1){
            std::vector<Double> yint = ec->PutY();
            std::vector<Double> errs = ec->PutE();

            for (UInt4 j=0; j<yint.size(); j++)                   //[inamura 170131]
                if (errs[j]<0.0) yint[j] = MLF_MASKVALUE;
            _ints2d.push_back(yint);
            _errs2d.push_back(errs);
            // Preserve PolarAngle in header for reconstructing Header
            if (hh->CheckKey("PixelPolarAngle")==1){
                Double angle = hh->PutDoubleVector("PixelPolarAngle")[0];
                _Angles.push_back( angle);
                //std::cout <<"PixelPolarAngle: "<< angle <<std::endl;
            }
            else{
                _Angles.push_back( -1.0);
            }
        }
        else{
            //std::cout <<"Masked Data: "<< i << std::endl;
            // Set Mask value to ints
            _ints2d.push_back(std::vector<Double>(_anisoBin2d[i].size()-1, MLF_MASKVALUE));
            _errs2d.push_back(std::vector<Double>(_anisoBin2d[i].size()-1, -1.0));
            _Angles.push_back( -1.0);
        }
        if (xbin.empty()){
            if (hh->CheckKey(MLF_KEY_HEAD_XRANGE)==1){
                xrange = hh->PutDoubleVector(MLF_KEY_HEAD_XRANGE);
                //_isoBin.push_back(xrange[0]-0.5);
                _isoBin.push_back(xrange[0]);
            }else if (hh->CheckKey(MLF_KEY_HEAD_XAXIS)==1){
                xrange.push_back(hh->PutDouble(MLF_KEY_HEAD_XAXIS));
            }else{
                //Double xx = (Double)i-0.5;
                Double xx = (Double)i;
                //std::cout <<"X bin: "<< xx << std::endl;
                _isoBin.push_back(xx);
            }
        }
    }
    if (xbin.empty()){
        if (xrange.size() == 2){
            //_isoBin.push_back(xrange[1]-0.5);
            _isoBin.push_back(xrange[1]);
        }
        else if (xrange.size()==_anisoBin2d.size()){
            Double x = xrange[0] - (xrange[1]-xrange[0])/2.0;
            _isoBin.push_back( x );
            for (UInt4 i=0;i<(xrange.size()-1);i++){
                _isoBin.push_back( (xrange[i+1]-xrange[i])/2.0 );
            }
            _isoBin.push_back( xrange.back() + (xrange.back()-xrange[ xrange.size()-2 ])/2.0 );
        }
        else{
            //_isoBin.push_back((Double)dnum-0.5);
            _isoBin.push_back((Double)dnum);
        }
    }else{
        _isoBin.resize( xbin.size() );
        copy( xbin.begin(), xbin.end(), _isoBin.begin() );
    }
}

//////////////// Set mask value to the 2D Map //////////////////
void MlfArraySlicer::
SetMask( Double x0, Double y0, Double x1, Double y1 )
{
    // TOF data ?
    //if (_ei == 0.0){
    if (!_isInelaPowder){
        x0 = x0 - 0.5;
        for (UInt4 i=0; i < _isoBin.size()-1; i++){
            // Exceed y range end?
            if (x1 < _isoBin[i]){
                break;
            }
            if (x0 <= _isoBin[i+1]){
                for (UInt4 j=0; j < _anisoBin2d[0].size()-1; j++){
                    // Exceed y range end?
                    if (y1 < _anisoBin2d[i][j]){
                        break;
                    }
                    // In masked region?
                    if (y0 <=_anisoBin2d[i][j+1]){
                        // Set mask value
                        _ints2d[i][j] = MLF_MASKVALUE;
                        _errs2d[i][j] = 0.0;
                    }
                }
            }
        }

    }
    else{
        // search y index
        for (UInt4 i=0; i < _isoBin.size()-1; i++){
            // Exceed y range end?
            if (y1 < _isoBin[i]){
                break;
            }
            if (y0 <= _isoBin[i+1]){
                for (UInt4 j=0; j < _anisoBin2d.size()-1; j++){
                    // Exceed y range end?
                    if (x1 < _anisoBin2d[j][i]){
                        break;
                    }
                    // In masked region?
                    if (x0 <=_anisoBin2d[j+1][i]){
                        // Set mask value
                        _ints2d[j][i] = MLF_MASKVALUE;
                        _errs2d[j][i] = 0.0;
                    }
                }
            }
        }
    }
    // Increment mask resions number
    _numMask++;

    std::cout <<  _MessageTag+"SetMask > _numMask= " << _numMask << std::endl;
}

///////// Clear Mask regions /////////////////
void MlfArraySlicer::
ClearMask( )
{
    // Remake 2D std::map data to erase mask regions
    _initData(_ei);
}

//////////////////////////////////////////////////////////
void MlfArraySlicer::
SetClipRegion( Double x0, Double y0, Double x1, Double y1, bool checkY )
{
    if (checkY){
        if( x1 < x0 || y1 < y0){
            std::cerr << _MessageTag+"SetClipRegion > Range error!!" << std::endl;
        }
    }else{
        if( x1 < x0 ){
            std::cerr << _MessageTag+"SetClipRegion > Range error!!" << std::endl;
        }
    }
    //if (_ei > 0.0){
    if (_isInelaPowder){
        if (y1 < _isoBin[0] || y0 > _isoBin[_isoBin.size()-1]){
            std::cerr << _MessageTag+"SetClipRegion > Out of Energy range!!" << std::endl;
            std::cout << "y1,_isoBin[0] ="<<y1<<" < "<<_isoBin[0]<<std::endl;
            std::cout << "y0,_isoBin[0] ="<<y0<<" > "<<_isoBin[_isoBin.size()-1]<<std::endl;
            return;
        }
        if (y0 < _isoBin[0]){
            y0 = _isoBin[0];
        }
        if (y1 > _isoBin[_isoBin.size()-1]){
            y1 = _isoBin[_isoBin.size()-1];
        }
    }
    else{
        if (x1 < _isoBin[0] || x0 > _isoBin[_isoBin.size()-1]){
            std::cerr << _MessageTag+"SetClipRegion > Out of index range!!" << std::endl;
            return;
        }
        if (x0 < _isoBin[0]){
            x0 = _isoBin[0];
        }
        if (x1 > _isoBin[_isoBin.size()-1]){
            x1 = _isoBin[_isoBin.size()-1];
        }
    }

    std::vector<Double> region;
    region.push_back(x0);
    region.push_back(y0);
    region.push_back(x1);
    region.push_back(y1);
    _regions.push_back(region);

    //std::cout << "Set Clip reagion " << _regions.size() << std::endl;

}

//////////////////////////////////////////////////////////
void MlfArraySlicer::
ClearClipRegion( )
{
    _regions.clear();
}

///////////////Make TOF bin or E Bin data ///////////////////
ElementContainerArray MlfArraySlicer::
ExecInteg(bool average, int axis, Double width, Double bin)
{
    // Create an ElementContainerArray for contain results
    ElementContainerArray ret;
    if (ExecInteg( &ret, average, axis, width, bin )){
    }else{
        std::cerr << _MessageTag+"ExecInteg > return empty ElementContainerArray" <<std::endl;
    }
    return ret;
}
bool MlfArraySlicer::
ExecInteg(ElementContainerArray* _eca_res, bool average, int axis, Double width, Double bin)
{
    if (_invalid){
        std::cerr << _MessageTag+"ExecInteg > Invalid data!!" << std::endl;
        return false;
    }

    std::vector< std::vector<Double> >::iterator it = _regions.begin();
    while (it != _regions.end()) {
        std::vector<Double> region = *it;
        // Prepare EC for result
        ElementContainer ec_res;
        if (axis==2){
            _MakeRectDiagCutData(region, bin, width, average, ec_res);
        }else{
            // Energy Data?
            //if (_ei > 0.0){
            if (_isInelaPowder){
                if (axis ==0){
                    _MakeEbinCutData(region, average, ec_res);
                }else{
                    if (width!=0.0) _qBin=fabs(width);
                    else if (bin!=0.0) _qBin=fabs(bin);
                    _MakeQbinCutData(region, average, ec_res, _qBin);
                }
            }
            else{
                if (axis ==0){
                    _MakeRectYbinCutData(region, average, ec_res);
                }else{
                    _MakeRectXbinCutData(region, average, ec_res);
                }
            }
        }
        _eca_res->Add( ec_res);
        it++;
    }
    //return *_eca_res;
    return true;
}

/////// Set Qbin for _Rebin
void MlfArraySlicer::SetQbin( Double bin, Double qmin, Double qmax ){
    _qBin = fabs(bin);
    //if ((qmin==-1.0)&&(qmax==-1.0)&&(_ei>0.0)){
    if ((qmin==-1.0)&&(qmax==-1.0)&&(_isInelaPowder)){
        std::vector<Double>::iterator it_min=min_element( _anisoBin2d[0].begin(), _anisoBin2d[0].end() );
        std::vector<Double>::iterator it_max=max_element( _anisoBin2d[0].begin(), _anisoBin2d[0].end() );
        qmin = *it_min;
        qmax = *it_max;
        for (UInt4 i=1; i<_anisoBin2d.size(); i++){
            it_min=min_element( _anisoBin2d[i].begin(), _anisoBin2d[i].end() );
            it_max=max_element( _anisoBin2d[i].begin(), _anisoBin2d[i].end() );
            if ((*it_max)>qmax) qmax = *it_max;
            if ((*it_min)<qmin) qmin = *it_min;
        }
    }
    if (qmin<qmax){
        _qRange.first = qmin;
        _qRange.second= qmax;
    }else if (qmin>qmax){
        _qRange.first = qmax;
        _qRange.second= qmin;
    }else{
        _qRange.first = 0.0;
        _qRange.second= 0.0;
    }
}
////////// Rebinning(source bins, source ints, source errs, Target bins, Result Int, Result Err)//////////
// Sizes of res_int and res_err must be bins.size() -1, and cleard by 0.0. ///
void MlfArraySlicer::
_Rebin(UInt4 index,    std::vector<Double>& res_bins, std::vector<Double>& res_ints,std::vector<Double>& res_ers)
{
    // Prepare std::vector to store weight of each point
    std::vector<Double> weights(res_bins.size()-1, 0.0);
    // Search the first index of source bin
    UInt4 i=0;
    while (_anisoBin2d[i][index] < res_bins[0]){
        i++;
    }
    // Search the first index of result bin
    UInt4 j=0;
    while (res_bins[j+1] < _anisoBin2d[0][index]){
        j++;
    }

    Double bin, sint, serr, weight;
    // Repeat all source data
    while (i < _ints2d.size()){
        // Break if reached to end of the target data
        if (j >= res_bins.size()-1){
            break;
        }
        // if not masked value
        if (_ints2d[i][index] < MLF_MASKVALUE){
            // Bin width of current target bin
            bin = res_bins[j+1]-res_bins[j];
            sint = _ints2d[i][index];
            serr = _errs2d[i][index];
            //std::cout << i << " : " << res_bins[j] << " : " << sint << std::endl;
            // In case of larger source bin
            if (_anisoBin2d[i+1][index] > res_bins[j+1]){
                weight = res_bins[j+1]-_anisoBin2d[i][index];
                res_ints[j] += sint*weight;
                res_ers[j] += weight*weight*serr*serr;
                weights[j] += weight;
                // Until result bin reaches to source bin
                while (true){
                    j += 1;
                    // End if reach the last point
                    if (j >= res_ints.size()){
                        break;
                    }
                    bin = res_bins[j+1]-res_bins[j];
                    // Not yet reach to prior bin?
                    if (res_bins[j+1] < _anisoBin2d[i+1][index]){
                        weight = res_bins[j+1]-res_bins[j];
                        res_ints[j] += sint*weight;
                        res_ers[j] += weight*weight*serr*serr;
                        weights[j] += weight;
                    }
                    else{
                        weight = _anisoBin2d[i+1][index]-res_bins[j];
                        break;
                    }
                }
            }
            // In case of larger result bin
            else if(_anisoBin2d[i][index] < res_bins[j]){
                // proportional weight
                weight = _anisoBin2d[i+1][index] - res_bins[j];
            }
            else{
                // weight is width of source bin
                weight = _anisoBin2d[i+1][index] - _anisoBin2d[i][index];
            }
            // End if reach the last point
            if (j >= res_bins.size()-1){
                break;
            }
            res_ints[j] += sint*weight;
            res_ers[j] += weight*weight*serr*serr;
            weights[j] += weight;
        }
        // Advance source bin
        i += 1;
        // Advance result bin if source bin exceed
        if (_anisoBin2d[i][index] > res_bins[j+1]){
           j+= 1;
        }
    }
    // Devide integrated values from weight
    for (UInt4 i = 0; i < res_ints.size(); i++){
        // Exist integrated values?
        if (weights[i] > 0.0){
            res_ints[i] = res_ints[i]/weights[i];
            res_ers[i] = sqrt(res_ers[i])/weights[i];
        }
        else{
            //std::cout << "Mask: " << i << std::endl;
            res_ints[i] = MLF_MASKVALUE;
            res_ers[i] = 0.0;
        }
    }
}

////////// Make TOF bin data //////////
void MlfArraySlicer::
_MakeRectYbinCutData(std::vector<Double> region, bool average, ElementContainer& ec_res)
{
    Double x0o = region[0];
    Double y0 = region[1];
    Double x1o = region[2];
    Double y1 = region[3];

       // Calc center index of region
    //UInt4 cIndex = int((x1 - x0)/2.0+x0+0.5);

    UInt4 cIndex = 0;
    bool isSearchIndex = true;
    Double cx = (x1o-x0o)/2.0+x0o;
    Double x0 = 0.0;
    bool isSearchX0 = true;
    Double x1 = 0.0;
    bool isSearchX1 = true;
    for (UInt4 i=0; i<(_isoBin.size()-1); i++){
        if ( (isSearchIndex)&&(cx>=_isoBin[i])&&(cx<_isoBin[i+1]) ){
            cIndex = i;
            isSearchIndex = false;
        }
        if ( (isSearchX0)&&(x0o>=_isoBin[i])&&(x0o<_isoBin[i+1]) ){
            x0 = (double)i;
            isSearchX0 = false;
        }
        //if ( (isSearchX1)&&(x1o>=_isoBin[i])&&(x1o<_isoBin[i+1]) ){  ##[inamura 150514]
        if ( (isSearchX1)&&(x1o>_isoBin[i])&&(x1o<=_isoBin[i+1]) ){
            x1 = (double)i;
            isSearchX1 = false;
        }
    }
    if ((isSearchIndex)||(isSearchX0)||(isSearchX1)){
        std::cerr << _MessageTag+"_MakeRectYbinCutData > Index is out" << std::endl;
        return;
    }

    std::vector<Double> org_x_vec = _anisoBin2d[cIndex];
    std::vector<Double> x_vec;
    x_vec.clear();

    // Make new std::vector of tof, trim from first tof
    UInt4 start = 0;
    // [KCS 2013/05/22 Bug Fix] -->
    //UInt4 end = 0;
    UInt4 end = (UInt4)(org_x_vec.size())-1;
    //<-- [KCS 2013/05/22 Bug Fix]

    for (UInt4 i = 0; i < org_x_vec.size(); i++){
        // Exceed tof range?
        if (org_x_vec[i] > y1){
            end = i - 1;
            break;
        }
        // Check if between tof range
        if (org_x_vec[i] >= y0){
            // First exceed ?
            if (x_vec.size() == 0){
                start = i;
            }
            x_vec.push_back(org_x_vec[i]);
        }
    }

    // Check if exist at least 2 data
    if (x_vec.size() <= 2){
        return;
    }
    int datNum = (int)(x_vec.size()) - 1;
    // Create Intensity and Error Vector
    std::vector<Double> y_vec(datNum, 0.0);
    std::vector<Double> e_vec(datNum, 0.0);
    // Vector for counting integration
    std::vector<Int4> n_vec(datNum, 0);

    // While in specified range
    for (UInt4 index = (UInt4)x0; index <= (UInt4)x1; index++){
        // Add int and Error to result vectors, except both end points
        //std::cout << "#[inamura 211227] _MakeRectYbinCutData  added index="<<index<<std::endl;
        for (UInt4 j=start; j<end;j++){
            Double sint = _ints2d[index][j];
            Double serr = _errs2d[index][j];

            // Check if not in masked region
            if (sint < MLF_MASKVALUE){
                // Add to result std::vector
                y_vec[j-start] += sint;
                e_vec[j-start] += serr * serr ;
                n_vec[j-start] += 1;
            }
        }
    }
    // Calc average?
    for(UInt4 i=0; i < y_vec.size(); i++){
        // Exist data?
        if (n_vec[i] > 0){
            // Average?
            if (average){
                y_vec[i] = y_vec[i]/(Double)n_vec[i];
                e_vec[i] = sqrt(e_vec[i])/(Double)n_vec[i];
            }
            else{
                e_vec[i] = sqrt(e_vec[i]);
            }
        }
        else{
            y_vec[i] = MLF_MASKVALUE;
            e_vec[i] = 0.0;
        }
        //std::cout << i << " : "<< y_vec[i] <<std::endl;
    }


    // Add xbin, int, error vectors
    std::string x_key = _keys[0];
    if (_givenAxesKeys[1].first!="") x_key = _givenAxesKeys[1].first;
    ec_res.Add(x_key, x_vec, _units[0]);
    ec_res.Add(_keys[1], y_vec, _units[1]);
    ec_res.Add(_keys[2], e_vec, _units[2]);
    ec_res.SetKeys( x_key, _keys[1], _keys[2] );

    // Make header and set label
    _makeHeader(region[0], region[2], average, ec_res, false);
    //std::cout << "#[inamura 211227] _MakeRectYbinCutData>> region[0],[2]="<<region[0]<<", "<<region[2]<<std::endl;
    //std::cout << "#[inamura 211227] _MakeRectYbinCutData>> x0,x1="<<x0<<", "<<x1<<std::endl;
    //// Set the center angle to the header
    //_AddAngle(ec_res.PutHeaderPointer(), region[0], region[2]);
}

////////// Make Index Bin data //////////
void MlfArraySlicer::
_MakeRectXbinCutData(std::vector<Double> region, bool average, ElementContainer& ec_res)
{
    //Double x0 = region[0]-0.5;
    Double x0 = region[0];
    Double y0 = region[1];
    //Double x1 = region[2]+0.5;
    Double x1 = region[2];
    Double y1 = region[3];

    //std::cout << "x0: " << x0 << "  y0: " << y0 << "  x1: " << x1 << "  y1: " << y1 << std::endl;

    std::vector <Double> x_vec;

    // Make Index bin
    for (UInt4 i = 0; i < _isoBin.size(); i++){
        // Has the begin of region reached Index bin's first point?
        if (x1 < _isoBin[i]){
            break;
        }
        // Has the end of region exceeded TOF bin's end point?
        if (x0 <= _isoBin[i]){
            x_vec.push_back(_isoBin[i]);
        }
    }

    // Out og range?
    if (x_vec.size() < 2){
        return;
    }
    UInt4 dnum = (UInt4)(x_vec.size())-1;
    //std::cout << "dnum : " << dnum << std::endl;
    // Prepare an integration Counter
    std::vector<UInt4> n_vec(dnum,0);
    std::vector<Double> y_vec(dnum,0.0);
    std::vector<Double> e_vec(dnum,0.0);

    UInt4 index = 0;
    for (UInt4 i = 0; i < _isoBin.size()-1; i++){
        if (x0 <= _isoBin[i]){
            std::vector<Double> tofs = _anisoBin2d[i];
            std::vector<Double> yy =   _ints2d[i];
            std::vector<Double> ee =   _errs2d[i];
            for (UInt4 j = 0; j < tofs.size()-1; j++){
                if (tofs[j] >= y0){
                    if (yy[j] < MLF_MASKVALUE){
                        y_vec[index] += yy[j];
                        e_vec[index] += ee[j]*ee[j];
                        n_vec[index] += 1;
                    }
                    //if (index==0) std::cout << "#[inamura 211227] added j="<<j<<std::endl;
                }
                //if (tofs[j+1] > y1){
                if (tofs[j+1] >= y1){
                    // Check if range is withen a range
                    if (tofs[j] < y0){
                        if (yy[j] < MLF_MASKVALUE){
                            y_vec[index] += yy[j];
                            e_vec[index] += ee[j]*ee[j];
                            n_vec[index] += 1;
                        }
                        //if (index==0) std::cout << "#[inamura 211227] added2 j="<<j<<std::endl;
                    }
                    break;
                }
            }
            index++;
            if (index >= dnum){
                break;
            }
        }

    }

    // Calc average?
    for(UInt4 i=0; i < y_vec.size(); i++){
        if (n_vec[i] > 0){
            if (average){
                y_vec[i] = y_vec[i]/(Double)n_vec[i];
                e_vec[i] = sqrt(e_vec[i])/(Double)n_vec[i];
            }
            else{
                e_vec[i] = sqrt(e_vec[i]);
            }
        }
        else{
            y_vec[i] = MLF_MASKVALUE;
            e_vec[i] = 0.0;
        }
    }


    // Add xbin, int, error vectors
    //
    std::string x_key = "Xvalue";
    if (_givenAxesKeys[0].first!="") x_key = _givenAxesKeys[0].first;
    ec_res.Add(x_key, x_vec, _unit_X);
    ec_res.Add(_keys[1], y_vec, _units[1]);
    ec_res.Add(_keys[2], e_vec, _units[2]);
    ec_res.SetKeys( x_key, _keys[1], _keys[2] );

    // Make header and set label
    _makeHeader(region[1], region[3], average, ec_res, true);
    //std::cout << "#[inamura 211227] _MakeRectXbinCutData>> region[1],[3]="<<region[1]<<", "<<region[3]<<std::endl;
    //std::cout << "#[inamura 211227] _MakeRectXbinCutData>> y0,y1="<<y0<<", "<<y1<<std::endl;

}
////////// Make RectFreeCut data ////////
void MlfArraySlicer::
_MakeRectDiagCutData(std::vector<Double> region, Double bin, Double width, bool average, ElementContainer& ec_res)
{
    // region = [start_x, start_y, end_x, end_y]
    // calc size of cut std::vector
    Double xx = region[2] - region[0];
    Double yy = region[3] - region[1];
    Double vlength = sqrt(xx * xx+ yy * yy);
    //std::cout << "vlength : " <<  vlength << std::endl;
    // Make unit std::vector on cut line
    Double ux = xx / vlength;
    Double uy = yy / vlength;

    Double width2 = width / 2.0;

    // Make  bin on cut line
    std::vector<Double> x_vec;
    Double vbin = 0.0;
    while ( vbin < vlength)
    {
        x_vec.push_back(vbin);
        vbin += bin;
    }
    // add the last point
    x_vec.push_back(vbin);

    UInt4 numBin = (UInt4)(x_vec.size());
    //std::cout << "numBin : " <<  numBin << std::endl;
    // prepare
    std::vector<int> counter = std::vector<int>(numBin, 0);
    std::vector<Double> y_vec = std::vector<Double>(numBin, 0.0);
    std::vector<Double> e_vec = std::vector<Double>(numBin, 0.0);

    UInt4 index=0;
    for (UInt4 ix=0; ix<(_isoBin.size()-1); ix++){
        for (UInt4 iy=0; iy<(_anisoBin2d[ix].size()-1); iy++){
            Double xdat = (_isoBin[ix]+_isoBin[ix+1])/2.0;
            Double ydat = (_anisoBin2d[ix][iy]+_anisoBin2d[ix][iy+1])/2.0;
            Double intd = _ints2d[ix][iy];
            Double errd = _errs2d[ix][iy];
            if (intd==MLF_MASKVALUE) continue;
            if (errd<0.0) continue;

            // shift the origine
            Double xp = xdat - region[0];
            Double yp = ydat - region[1];
            // Calc distance from the line
            Double distance = fabs(xx * yp - yy * xp) / vlength ;
            // Check if in width?
            if (distance > width2){
                continue;
            }
            // Calc Dot
            Double dot = xp  * ux + yp * uy;
            if (dot >= 0.0){
                index = (UInt4)((dot + bin/2.0) / bin);
                if ( index >= numBin){
                    continue;
                }
            }
            else if (fabs(dot) < bin/2.0){
                index = 0;
            }
            else{
                continue;
            }

            y_vec[index] += intd;
            counter[index] += 1;
            e_vec[index] += errd*errd;
        }
    }

    // Calc average?
    for(UInt4 i=0; i < y_vec.size(); i++){
        if (counter[i] > 0){
            if (average){
                y_vec[i] = y_vec[i]/(Double)counter[i];
                e_vec[i] = sqrt(e_vec[i])/(Double)counter[i];
            }
            else{
                e_vec[i] = sqrt(e_vec[i]);
            }
        }
        else{
            y_vec[i] = MLF_MASKVALUE;
            e_vec[i] = -1.0;
        }
    }

    // Add xbin, int, error vectors
    std::string x_key = "Xval";
    ec_res.Add(x_key, x_vec, _units[1]);
    ec_res.Add(_keys[1], y_vec, _units[0]);
    ec_res.Add(_keys[2], e_vec, _units[2]);
    ec_res.SetKeys( x_key, _keys[1], _keys[2] );
    // Make header and set label
    HeaderBase* hh_ec = ec_res.PutHeaderPointer();
    char label[100];
    if (average){
        std::snprintf(label, sizeof(label), "Average of (%.3f,%.3f) to (%.3f,%.3f)", region[0],region[1],region[0],region[1]);
    }
    else{
        std::snprintf(label, sizeof(label), "Integrated (%.3f,%.3f) to (%.3f,%.3f)", region[0],region[1],region[0],region[1]);
    }
    hh_ec->Add("Label",std::string(label));

    // Add runno
    hh_ec->Add("RUNNUMBER", _runNo);
}


////////// Make Q Bin data //////////
void MlfArraySlicer::
_MakeQbinCutData(std::vector<Double> region, bool average, ElementContainer& ec_res, Double qBin)
{

    // Calc the center of Energy range
    Double enc = (region[3] - region[1])/2.0 + region[1];

    // Search start, center, and end points
    UInt4 m1 = (UInt4)(_isoBin.size())-1;;
    UInt4 m0 = -1;
    UInt4 mp = -1;
    for (UInt4 i = 0; i < _isoBin.size(); i++){
        // Exceed the first point?
        if (_isoBin[i] > region[1]){
            // First time?
            if (m0 == (UInt4)-1){
                if (i > 0){
                    m0 = i-1;
                }else{
                    m0 = i;
                }
            }

        }
        // Exceed the center point?
        if (_isoBin[i] > enc){
            // First time?
            if (mp == (UInt4)-1){
                // Center will be the nearest point to the center value
                if (i > 0 && (_isoBin[i] - enc) > (enc - _isoBin[i-1])){
                    mp = i-1;
                }else{
                    mp = i;
                }
            }
        }
        // Exceed the end point?
        if (_isoBin[i] > region[3]){
            // First time?
            if (i > (UInt4)0){
                m1 = i-1;
            }else{
                m1 = i;
            }
            break;
        }
    }
    if (m0 == m1){
        mp = m0;
    }
    //std::cout << m0 << ":" << mp << ":" << m1 << std::endl;

    // Xbin at the center
    std::vector<Double> x_vec;
    UInt4 q0 = -1;
    UInt4 q1 = (UInt4)(_anisoBin2d.size())-2; //[inamura 160307]
    // Get vecters at the center from the precreated 2D data
    for (UInt4 i=0; i < _anisoBin2d.size(); i++){
        // Exceed Q range?
        if (region[2]>0.0)
            if (_anisoBin2d[i][mp] > region[2]){
                q1 = i-1;
                break;
            }
        // Withen X range?
        if (_anisoBin2d[i][mp] >= region[0]){
            x_vec.push_back(_anisoBin2d[i][mp]);
            //std::cout << _anisoBin2d[i][mp] << std::endl;
            if (q0 == (UInt4)-1){
                q0 = i;
            }
        }
    }
    // Out of range?
    if (q0 == (UInt4)-1){
        return;
    }
    // Rebin x_vec with qBin
    if (qBin!=0.0){
        Double q_min = x_vec.front();
        Double q_max = x_vec.back();
        x_vec.clear();
        if (_qRange.first!=_qRange.second){
            q_min = _qRange.first;
            q_max = _qRange.second;
        }
        qBin = fabs(qBin);
        Double q=-qBin/2.0;
        if ( q_min<0.0 ){
            while( q>q_min )
                q -= qBin;
        }else{
            while( q<q_min )
                q += qBin;
        }
        x_vec.push_back(q);
        while( q<q_max ){
            q += qBin;
            x_vec.push_back(q);
        }
    }
    UInt4 dnum = (UInt4)(x_vec.size())-1;

    // Prepare an integration Counter
    std::vector<UInt4> integNo(dnum,0);
    std::vector<Double> y_vec(dnum,0.0);
    std::vector<Double> e_vec(dnum,0.0);

    // While in integration range
    while (m1 >= m0){
        std::vector<Double> yy(dnum,0.0);
        std::vector<Double> ee(dnum,0.0);
        // Rebinning at center bin
        _Rebin(m0,x_vec, yy,ee);
        // Add up
        for(UInt4 i = 0; i < dnum; i++){
            // Both data points are not masked
            if (y_vec[i] < MLF_MASKVALUE && yy[i] < MLF_MASKVALUE){
                y_vec[i] += yy[i];
                if (integNo[1] == 1){
                    e_vec[i] = e_vec[i]*e_vec[i];
                }
                e_vec[i] += ee[i] * ee[i];
                // Counts up integration No.
                integNo[i] += 1;
            }
            // Source data is masked, but object is not.
            else if (y_vec[i] >= MLF_MASKVALUE){
                y_vec[i] = yy[i];
                e_vec[i] = ee[i];
                integNo[i] = 1;
            }
        }
        m0++;
    }

    for(UInt4 i = 0; i < dnum; i++){
        // If not data point is masked
        if (y_vec[i] < MLF_MASKVALUE){
            if (integNo[i] > 0){
                if (average){
                    y_vec[i] = y_vec[i] / (Double)integNo[i];
                    e_vec[i] = sqrt(e_vec[i]) / (Double)integNo[i];
                }
                else{
                    e_vec[i] = sqrt(e_vec[i]);
                }
            }
            else{
                // No data case
                y_vec[i] = MLF_MASKVALUE;
                e_vec[i] = 0.0;
            }
        }
    }

    std::string x_key = _keys[0];
    if (_givenAxesKeys[0].first!="") x_key = _givenAxesKeys[0].first;
    ec_res.Add(x_key, x_vec, "1/A");
    ec_res.Add(_keys[1], y_vec, _units[1]);
    ec_res.Add(_keys[2], e_vec, _units[2]);
    ec_res.SetKeys( x_key, _keys[1], _keys[2] );
    // Make header and set label
    _makeHeader(region[1], region[3], average, ec_res, false);
    // Set the center angle to the header
    _AddAngle(ec_res.PutHeaderPointer(), q0, q1);
}

////////// Set Polar Angle to Header //////////
void MlfArraySlicer::
_AddAngle(HeaderBase* hh, Int4 index0, Int4 index1)
{
    Double angle0 = _Angles[index0];
    Double angle1 = _Angles[index1];
    if (angle0 < 0.0 || angle1 < 0.0){
        return;
    }
    Double center_angle = (angle0+angle1)/2.0;
    std::vector<Double> vecPpa;
    vecPpa.push_back(center_angle);
    vecPpa.push_back(0.0);
    // Set the center angle to the header
    hh->Add("PixelPolarAngle", vecPpa);
}

////////// Make E bin data //////////
void MlfArraySlicer::
_MakeEbinCutData(std::vector<Double> region, bool average, ElementContainer& ec_res)
{
    Double y0 = region[1];
    Double y1 = region[3];

    // Search start and end points from Y-axis
    UInt4 yEnd = (UInt4)(_isoBin.size())-1;
    UInt4 index = -1;

    // Make xbin range from Enegy-Axis (iso-bin)
    for (UInt4 i = 0; i < _isoBin.size(); i++){
        if (_isoBin[i] > y1){
            yEnd = i;
            break;
        }
        // Exceed the first point?
        if (_isoBin[i] >= y0){
            if(index == -1){
                index = i;
            }
        }
    }
    //std::cout << "Enegy Index range: " << index << " : " << yEnd << std::endl;

    // Q-Range
    Double left = region[0];
    Double right = region[2];

    // Prepare an integration Counter
    std::vector<Double> x_vec;
    std::vector<Double> y_vec;
    std::vector<Double> e_vec;

    UInt4 xnum = (UInt4)(_anisoBin2d.size());

    Double r0, r1;

    // Each X-bin (Y-Axis : Q)
    while(yEnd > index){
        // No data region
        /* //[inamura 140605]
        if ((_anisoBin2d[0][index] > left && _anisoBin2d[0][index+1] > left) or
            (_anisoBin2d[xnum-1][index] < right && _anisoBin2d[xnum-1][index+1] < right)){
            y_vec.push_back(MLF_MASKVALUE);
            e_vec.push_back(0.0);
            x_vec.push_back(_isoBin[index]);
            index++;
            continue;
        }
        */
        // Zero Width case
        if (left == right){
            //[inamura 140605]-->
            if ((_anisoBin2d[0][index] > left && _anisoBin2d[0][index+1] > left) or
                (_anisoBin2d[xnum-1][index] < right && _anisoBin2d[xnum-1][index+1] < right)){
                y_vec.push_back(MLF_MASKVALUE);
                e_vec.push_back(0.0);
                x_vec.push_back(_isoBin[index]);
                index++;
                continue;
            }
            //<--[inamura 140605]
            for(UInt4 k=0; k < xnum-1; k++){
                if (_anisoBin2d[k+1][index] < left && _anisoBin2d[k+1][index+1] < left){
                    continue;
                }
                if ((_anisoBin2d[k+1][index] >= left && _anisoBin2d[k+1][index+1] >= left) || k == xnum - 2 ){
                    // Center or edge point
                    if (_ints2d[k][index] >= MLF_MASKVALUE){
                        y_vec.push_back(MLF_MASKVALUE);
                        e_vec.push_back(0.0);
                    }
                    else{
                        y_vec.push_back(_ints2d[k][index]);
                        e_vec.push_back(_errs2d[k][index]);
                    }
                    x_vec.push_back(_isoBin[index]);
                }
                else{
                    // On the boundary point
                    if (_ints2d[k][index] >= MLF_MASKVALUE){
                        if (_ints2d[k+1][index] >= MLF_MASKVALUE){
                            y_vec.push_back(MLF_MASKVALUE);
                            e_vec.push_back(0.0);
                        }
                        else{
                            y_vec.push_back(_ints2d[k][index]);
                            e_vec.push_back(_errs2d[k][index]);
                        }
                        x_vec.push_back(_isoBin[index]);
                    }
                    else{
                        if (_ints2d[k+1][index] >= MLF_MASKVALUE){
                            y_vec.push_back(_ints2d[k][index]);
                            e_vec.push_back(_errs2d[k][index]);
                            x_vec.push_back(_isoBin[index]);
                        }
                        else{
                            if (_anisoBin2d[k+1][index] >= left){
                                r0 = (_anisoBin2d[k+1][index] - left) / (_anisoBin2d[k+1][index] - _anisoBin2d[k+1][index+1]);
                                r1 = (left - _anisoBin2d[k+1][index+1]) / (_anisoBin2d[k+1][index] - _anisoBin2d[k+1][index+1]);
                            }
                            else{
                                r0 = (_anisoBin2d[k+1][index+1] - left) / (_anisoBin2d[k+1][index+1] - _anisoBin2d[k+1][index]);
                                r1 = (left - _anisoBin2d[k+1][index]) / (_anisoBin2d[k+1][index+1] - _anisoBin2d[k+1][index]);
                            }
                            y_vec.push_back(_ints2d[k][index]*r0 + _ints2d[k+1][index]*r1);
                            e_vec.push_back(sqrt(_errs2d[k][index]*_errs2d[k][index]*r0+_errs2d[k+1][index]*_errs2d[k+1][index]*r1));
                            x_vec.push_back(_isoBin[index]);
                        }
                    }

                }
                break;
            }
        }
        else{
            Double sumcount = 0.0;
            Double sumerr = 0.0;
            Double sumarea = 0.0;
            Double num_counted = 0.0;

            Double l01 = _anisoBin2d[0][index] - left;
            Double l11 = _anisoBin2d[0][index+1] - left;
            Double r01 = _anisoBin2d[0][index] - right;
            Double r11 = _anisoBin2d[0][index+1] - right;
            Double l00, l10, r00, r10;

            Double area;    // Weight for minuend
            Double exarea;  // Weight for subtracter
            Double effect;


            // Search data within X-range
            for(UInt4 k=0; k < xnum-1; k++){
                l00 = l01;
                l10 = l11;
                l01 = _anisoBin2d[k+1][index] - left;
                l11 = _anisoBin2d[k+1][index+1] - left;
                r00 = r01;
                r10 = r11;
                r01 = _anisoBin2d[k+1][index] - right;
                r11 = _anisoBin2d[k+1][index+1] - right;

                if (_ints2d[k][index] >= MLF_MASKVALUE){
                    continue;
                }
                // Calc minuend's qrea (Weight)
                // Branch of 3 x 3 ways by slicing method of parallelogram
                if (l01 < 0){
                    if (l11 < 0){
                        continue;
                    }
                    else if (l10 < 0){
                        area = l11 * l11 / (l11 - l01);
                    }
                    else{
                        area = l11 * l11 / (l11 - l01) - l10 * l10 / (l10 - l00);
                    }
                }
                else if(l00 < 0 ){
                    if (l11 < 0) {
                        area = l01 * l01 / (l01 - l11);
                    }
                    else if (l10 < 0){
                        area = l01 + l11;
                    }
                    else{
                        area = (l01 + l11) - l10 * l10 / (l10 - l00);
                    }
                }
                else{
                    if (l11 < 0){
                        area = l01 * l01 / (l01 - l11) - l00 * l00 / (l00 - l10);
                    }
                    else if (l10 < 0){
                        area = (l01 + l11) - l00 * l00 / (l00 - l10);
                    }
                    else{
                        area = (l01 - l00) + (l11 - l10);
                    }
                }
                // Calc Subtracter's area (Weight)
                // Branch of 3 x 3 ways by slicing method of parallelogram
                if (r01 < 0){
                    if (r11 < 0){
                        exarea = 0;
                    }
                    else if (r10 < 0){
                        exarea = r11 * r11 / (r11 - r01);
                    }
                    else{
                        exarea = r11 * r11 / (r11 - r01) - r10 * r10 / (r10 - r00);
                    }
                }
                else if (r00 < 0){
                    if (r11 < 0){
                        exarea = r01 * r01 / (r01 - r11);
                    }
                    else if (r10 < 0){
                        exarea = r01 + r11;
                    }
                    else{
                        exarea = (r01 + r11) - r10 * r10 / (r10 - r00);
                    }
                }
                else{
                    if (r11 < 0 ){
                        exarea = r01 * r01 / (r01 - r11) - r00 * r00 / (r00 - r10);
                    }
                    else if (r10 < 0){
                        exarea = (r01 + r11) - r00 * r00 / (r00 - r10);
                    }
                    else{
                        break;
                    }
                }
                // Calc Intensity and err's effective weight
                effect = area - exarea;
                sumcount = sumcount + _ints2d[k][index] * effect;

                sumerr = sumerr + _errs2d[k][index] * _errs2d[k][index] * effect * effect;
                sumarea = sumarea + effect;
                num_counted = num_counted + 1.0;

            }
            if (sumarea == 0.0){
                y_vec.push_back(MLF_MASKVALUE);
                e_vec.push_back(0.0);
            }
            else{
                if (average){
                    y_vec.push_back(sumcount / sumarea);
                    e_vec.push_back(sqrt(sumerr) / sumarea);
                }
                else{
                    y_vec.push_back(sumcount / sumarea * ( num_counted ));
                    e_vec.push_back(sqrt(sumerr) / sumarea * ( num_counted ));
                }
            }
            x_vec.push_back(_isoBin[index]);
        }
        index++;
    }
    // The last point
    x_vec.push_back(_isoBin[index]);

    // Cut off masked redion in taile
    index = (UInt4)(y_vec.size())-1;
    while ( index > 0){
        if (y_vec[index] < MLF_MASKVALUE){
            break;
        }
        x_vec.pop_back();
        y_vec.pop_back();
        e_vec.pop_back();
        --index;
    }
    //std::cout << "Size of x : " << x_vec.size() << std::endl;
    //std::cout << "Size of y : " << y_vec.size() << std::endl;

    // Add xbin, int, error vectors
    ec_res.Add(_keys[0], x_vec, _units[0]);
    ec_res.Add(_keys[1], y_vec, _units[1]);
    ec_res.Add(_keys[2], e_vec, _units[2]);
    ec_res.SetKeys( _keys[0], _keys[1], _keys[2] );

    // Make header and set label
    _makeHeader(region[0], region[2], average, ec_res, false);
}

////////// Make Header and  Set Label //////////
void MlfArraySlicer::
_makeHeader(Double y0, Double y1, bool average, ElementContainer& ec_res, bool reverse)
{
    // Add xbin, int, error vectors
    HeaderBase hh_ec;
    char label[100];
    /*
    if (_ei > 0.0 || reverse){
        if (average){
            std::sprintf(label,  "Average of %.3f to %.3f", y0, y1);
        }
        else{
            std::sprintf(label, "Integrated %.3f to %.3f", y0, y1);
        }
    }
    else{
        if (average){
            std::sprintf(label,  "Average of %d to %d", (int)(y0), (int)(y1));
        }
        else{
            std::sprintf(label, "Integrated %d to %d",(int)(y0), (int)(y1));
        }
    }
    */
    if (average){
      std::snprintf(label, sizeof(label), "Ave of %.3f to %.3f", y0, y1);
    }
    else{
      std::snprintf(label, sizeof(label), "Integ %.3f to %.3f", y0, y1);
    }
    hh_ec.Add("Label",std::string(label));

    // Add runno
    hh_ec.Add("RUNNUMBER", _runNo);
    ec_res.InputHeader( hh_ec);

    return;
}

double MlfArraySlicer::_EtoK2( double E ){
    double cK2toE = MLF_HBAR*MLF_HBAR/(2.0*MLF_Mn)*1.0e20*MLF_J2MEV;
    return E/cK2toE;
}

ElementContainer MlfArraySlicer::CutAlongX( Double ymin, Double ymax, bool average ){
    ElementContainer ret;
    if (CutAlongX( &ret, ymin, ymax, average )){
    }else{
        std::cerr << _MessageTag+"CutAlongX > return empty ElementContainer" <<std::endl;
    }
    return ret;
}
bool MlfArraySlicer::CutAlongX( ElementContainer* _ec, Double ymin, Double ymax, bool average ){
    if ( ymin>ymax ){
        Double tmp = ymin;
        ymin = ymax;
        ymax = tmp;
    }
    Double xmin;
    Double xmax;
    //if (_ei>0.0){
    if (_isInelaPowder){
        std::vector<Double>::iterator it_min=min_element( _anisoBin2d[0].begin(), _anisoBin2d[0].end() );
        std::vector<Double>::iterator it_max=max_element( _anisoBin2d[0].begin(), _anisoBin2d[0].end() );
        xmin = *it_min;
        xmax = *it_max;
        for (UInt4 i=1; i<_anisoBin2d.size(); i++){
            it_min=min_element( _anisoBin2d[i].begin(), _anisoBin2d[i].end() );
            it_max=max_element( _anisoBin2d[i].begin(), _anisoBin2d[i].end() );
            if ((*it_max)>xmax) xmax = *it_max;
            if ((*it_min)<xmin) xmin = *it_min;
        }
    }else{
        xmin = _isoBin[0];
        xmax = _isoBin[_isoBin.size()-1];
    }
    ClearClipRegion();
    SetClipRegion( xmin, ymin, xmax, ymax );
    ElementContainerArray* _eca = new ElementContainerArray();
    if (ExecInteg(_eca, average, 1)){
        ElementContainer* ec = _eca->PutPointer(0);
        _ec->InputHeader( ec->PutHeader() );
        std::vector<std::string> keys = ec->PutKeys();
        for (UInt4 i=0; i<keys.size(); i++)
            _ec->Add( keys[i], ec->Put(keys[i]), ec->PutUnit(keys[i]));
        _ec->SetKeys( ec->PutXKey(), ec->PutYKey(), ec->PutEKey() );
        delete _eca;
        return true;
    }
    else{
        delete _eca;
        return false;
    }
}
ElementContainer MlfArraySlicer::CutAlongY( Double xmin, Double xmax, bool average ){
    ElementContainer ret;
    if (CutAlongY( &ret, xmin, xmax, average )){
    }else{
        std::cerr << _MessageTag+"CutAlongY > return empty ElementContainer" <<std::endl;
    }
    return ret;
}
bool MlfArraySlicer::CutAlongY( ElementContainer* _ec, Double xmin, Double xmax, bool average ){
    if ( xmin>xmax ){
        Double tmp = xmin;
        xmin = xmax;
        xmax = tmp;
    }
    Double ymin = 1.0e32;
    Double ymax = -1.0e32;
    //if (_ei>0.0){
    if (_isInelaPowder){
        ymin = _isoBin[0];
        ymax = _isoBin[_isoBin.size()-1];
    }else{
        std::vector<Double>::iterator it_min=min_element( _anisoBin2d[0].begin(), _anisoBin2d[0].end() );
        std::vector<Double>::iterator it_max=max_element( _anisoBin2d[0].begin(), _anisoBin2d[0].end() );
        ymin = *it_min;
        ymax = *it_max;
        for (UInt4 i=1; i<_anisoBin2d.size(); i++){
            it_max=max_element( _anisoBin2d[i].begin(), _anisoBin2d[i].end() );
            it_min=min_element( _anisoBin2d[i].begin(), _anisoBin2d[i].end() );
            if ((*it_max)>ymax) ymax = *it_max;
            if ((*it_min)<ymin) ymin = *it_min;
        }
    }
    ClearClipRegion();
    SetClipRegion( xmin, ymin, xmax, ymax );
    ElementContainerArray* _eca = new ElementContainerArray();
    if (ExecInteg(_eca, average, 0)){
        ElementContainer* ec = _eca->PutPointer(0);
        _ec->InputHeader( ec->PutHeader() );
        std::vector<std::string> keys = ec->PutKeys();
        for (UInt4 i=0; i<keys.size(); i++)
            _ec->Add( keys[i], ec->Put(keys[i]), ec->PutUnit(keys[i]));
        _ec->SetKeys( ec->PutXKey(), ec->PutYKey(), ec->PutEKey() );
        delete _eca;
        return true;
    }
    else{
        delete _eca;
        return false;
    }
}
ElementContainer MlfArraySlicer::CutDiagonal( Double x0, Double y0, Double x1, Double y1, Double width, Double bin, bool average ){
    ElementContainer ret;
    if (CutDiagonal( &ret, x0, y0, x1, y1, width, bin, average )){
    }else{
        std::cerr << _MessageTag+"CutDiagonal > return empty ElementContainer" <<std::endl;
    }
    return ret;
}
bool MlfArraySlicer::CutDiagonal( ElementContainer* _ec, Double x0, Double y0, Double x1, Double y1, Double width, Double bin, bool average ){
    ClearClipRegion();
    SetClipRegion( x0, y0, x1, y1, false );
    ElementContainerArray* _eca = new ElementContainerArray();
    if (ExecInteg(_eca, average, 2, width, bin)){
        ElementContainer* ec = _eca->PutPointer(0);
        _ec->InputHeader( ec->PutHeader() );
        std::vector<std::string> keys = ec->PutKeys();
        for (UInt4 i=0; i<keys.size(); i++)
            _ec->Add( keys[i], ec->Put(keys[i]), ec->PutUnit(keys[i]));
        _ec->SetKeys( ec->PutXKey(), ec->PutYKey(), ec->PutEKey() );
        delete _eca;
        return true;
    }
    else{
        delete _eca;
        return false;
    }
}
