#include "SectorAverageByAngle.hh"
//////////////////////////////////////////////////////////
SectorAverageByAngle::
SectorAverageByAngle()
{
    Initialize();
}
//////////////////////////////////////////////////////////
SectorAverageByAngle::
SectorAverageByAngle( ElementContainerMatrix* ecm )
{
    Initialize();
    SetECM( ecm );
}
//////////////////////////////////////////////////////////
SectorAverageByAngle::
~SectorAverageByAngle()
{
    ClearHist();
}

//////////////////////////////////////////////////////////
void SectorAverageByAngle::
Initialize(){
    _SectorAngleInfo.clear();         /**<  [index][<azim_min, azim_max, pol_min, pol_max>]  */

    _TargetBankIdList.clear();        /**<  Id list to be used for sector average **/

    _NumOfBanks = 0;
    _BankIdList.clear();
    _BankNameList.clear();

    isUsedOnlySB = false;
    _SmallAngleBankIds.clear();       /**<  Id list of banks defined as small angle bank  */
    _SmallAngleBankIds.push_back(0);  /**<  define BankId=0 as small angle bank*/
    _SmallAngleBankIds.push_back(1);  /**<  define BankId=1 as small angle bank*/
    _SmallAngleBankIds.push_back(2);  /**<  define BankId=2 as small angle bank*/
    _SmallAngleBankIds.push_back(3);  /**<  define BankId=2 as small angle bank*/

    _LambdaRangeList.clear();

    _QLambRangeToIq.clear();
    _QLimRangeToIqOfBanks.clear();

    _MessageTag = "SectorAverageByAngle::";

    //_qInt = new std::vector<GslHistogram*> ( _NumOfBanks, NULL );
    //_qErr = new std::vector<GslHistogram*> ( _NumOfBanks, NULL );
    //_qCnt = new std::vector<GslHistogram*> ( _NumOfBanks, NULL );
    _qInt = NULL;
    _qErr = NULL;
    _qCnt = NULL;
    _qRangePointers.clear();

}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetECM( ElementContainerMatrix* ecm ){
    SetInputP( ecm );
    _BankIdList = ecm->PutHeaderPointer()->PutInt4Vector("BANKIDLIST");
    _BankNameList = ecm->PutHeaderPointer()->PutStringVector("BANKNAMELIST");
    _NumOfBanks = _BankIdList.size();
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
ClearHist(){
    if (_qInt!=NULL){
        for (std::vector<GslHistogram*>::iterator it=(*_qInt).begin(); it!=(*_qInt).end(); ++it)
            if ( (*it)!=NULL ) delete (*it);
        delete _qInt;
    }
    if (_qErr!=NULL){
        for (std::vector<GslHistogram*>::iterator it=(*_qErr).begin(); it!=(*_qErr).end(); ++it)
            if ( (*it)!=NULL ) delete (*it);
        delete _qErr;
    }
    if (_qCnt!=NULL){
        for (std::vector<GslHistogram*>::iterator it=(*_qCnt).begin(); it!=(*_qCnt).end(); ++it)
            if ( (*it)!=NULL ) delete (*it);
        delete _qCnt;
    }
    //delete _qInt, _qErr, _qCnt;
    _qInt = NULL;
    _qErr = NULL;
    _qCnt = NULL;
    if (!(_qRangePointers.empty())){
        for (UInt4 i=0; i<_qRangePointers.size(); i++){
            delete [] _qRangePointers[i];
        }
        _qRangePointers.clear();
    }
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetTargetBank( Int4 bank_id ){
    _TargetBankIdList.clear();
    if (bank_id<0){
    }else{
        _TargetBankIdList.push_back( bank_id );
    }
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetTargetBank( std::vector<Int4> bank_id_list ){
    _TargetBankIdList.clear();
    for (std::vector<Int4>::iterator it=bank_id_list.begin(); it!=bank_id_list.end(); ++it)
        _TargetBankIdList.push_back( (*it) );
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
AddTargetBank( Int4 bank_id ){
    if (bank_id<0){
        _TargetBankIdList.clear();
    }else{
        _TargetBankIdList.push_back( bank_id );
    }
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
AddSectAngle( Double azim_min, Double azim_max, Double pol_min, Double pol_max ){
    std::vector<Double> sect_angle(4,0.0);
    sect_angle[0] = azim_min;
    sect_angle[1] = azim_max;
    sect_angle[2] = pol_min;
    sect_angle[3] = pol_max;
    _SectorAngleInfo.push_back( sect_angle );
    isUsedOnlySB = false;
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetSectAngles( std::vector<Double> angle_vect ){
    if ( (angle_vect.size() % 4)!=0 ){
        std::cout << _MessageTag+"SetSectAngles : parameter size is invalid (" << angle_vect.size() << ")" << std::endl;
    }
    for (UInt4 i=0; i<angle_vect.size(); i+=4){
        std::vector<Double> sect_angle(4,0.0);
        sect_angle[0] = angle_vect[i+0];
        sect_angle[1] = angle_vect[i+1];
        sect_angle[2] = angle_vect[i+2];
        sect_angle[3] = angle_vect[i+3];
        _SectorAngleInfo.push_back( sect_angle );
    }
    isUsedOnlySB = false;
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
ShowSectors(){
    std::cout << _MessageTag+"ShowSectors" << std::endl;
    std::cout << "------------------------------------------------" << std::endl;
    std::cout << "| index | azim angle range | polar angle range |" << std::endl;
    std::cout << "------------------------------------------------" << std::endl;
    for (UInt4 i=0; i<_SectorAngleInfo.size(); i++){
        std::vector<Double> tmp = _SectorAngleInfo[i];
        std::cout << "| " << i << " | " << tmp[0] << ", " << tmp[1] << " | " << tmp[2] << ", " << tmp[3] << " |" << std::endl;
    }
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
RemoveSector( Int4 index ){
    if (index<_SectorAngleInfo.size()){
        for (UInt4 i=index; i<(_SectorAngleInfo.size()-1); i++){
            std::vector<Double> tmp = _SectorAngleInfo[i+1];
            _SectorAngleInfo[i].clear();
            _SectorAngleInfo[i].push_back( tmp[0] );
            _SectorAngleInfo[i].push_back( tmp[1] );
            _SectorAngleInfo[i].push_back( tmp[2] );
            _SectorAngleInfo[i].push_back( tmp[3] );
        }
    }
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
ClearAllSectors(){
    _SectorAngleInfo.clear();
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
AddSectByAzimAngleOnSAbank( Double azim_min, Double azim_max, Double r_min, Double r_max ){
    SetTargetBank( _SmallAngleBankIds );
    std::vector<Double> sect_range(4,0.0);
    sect_range[0] = azim_min;
    sect_range[1] = azim_max;
    sect_range[2] = r_min;
    sect_range[3] = r_max;
    _SectorAngleInfo.push_back( sect_range );
    isUsedOnlySB = true;
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetSectByAzimAngleOnSAbank( std::vector<Double> azim_vect ){
    SetTargetBank( _SmallAngleBankIds );
    if ( (azim_vect.size() % 4)!=0 ){
        std::cout << _MessageTag+"SetSectAngles : parameter size is invalid (" << azim_vect.size() << ")" << std::endl;
    }
    for (UInt4 i=0; i<azim_vect.size(); i+=4){
        std::vector<Double> sect_angle(4,0.0);
        sect_angle[0] = azim_vect[i+0];
        sect_angle[1] = azim_vect[i+1];
        sect_angle[2] = azim_vect[i+2];
        sect_angle[3] = azim_vect[i+3];
        _SectorAngleInfo.push_back( sect_angle );
    }
    isUsedOnlySB = true;
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetLambdaRange( Double lam_min, Double lam_max, Int4 bank_id ){
    bool isIncluded = false;
    if ( bank_id==-1 ){
        isIncluded = true;
    }else{
        for (std::vector<Int4>::iterator it=_BankIdList.begin(); it!=_BankIdList.end(); ++it){
            if ( (*it)==bank_id ){
                isIncluded = true;
                break;
            }
        }
    }
    if (isIncluded){
    }else{
        std::cout << _MessageTag+"SetlambdaRange : bank_id is too large, bank_id=" << bank_id << std::endl;
        return;
    }

    if (lam_min>lam_max){
        Double tmp = lam_min;
        lam_min = lam_max;
        lam_min = tmp;
    }
    if (bank_id==-1){
        for (std::vector<Int4>::iterator it=_BankIdList.begin(); it!=_BankIdList.end(); ++it){
            if ( (UInt4)(*it)>=_LambdaRangeList.size() ) _LambdaRangeList.resize( ( (UInt4)(*it)+1 ) );
            _LambdaRangeList[(UInt4)(*it)].clear();
            _LambdaRangeList[(UInt4)(*it)].push_back(lam_min);
            _LambdaRangeList[(UInt4)(*it)].push_back(lam_max);
        }
        /*
        if (_LambdaRangeList.empty()){
            for (UInt4 i=0; i<_NumOfBanks; i++){
                std::vector<Double> tmp(2,0.0);
                _LambdaRangeList.push_back( tmp );
            }
        }
        for (UInt4 i=0; i<_NumOfBanks; i++){
            _LambdaRangeList[i][0] = lam_min;
            _LambdaRangeList[i][1] = lam_max;
        }
        */
    }else{
        if ( bank_id>=_LambdaRangeList.size() ) _LambdaRangeList.resize( (bank_id+1) );
        _LambdaRangeList[bank_id].clear();
        _LambdaRangeList[bank_id].push_back(lam_min);
        _LambdaRangeList[bank_id].push_back(lam_max);
    }

}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetQRange( UInt4 BinType, Double Qmin, Double Qmax, Double deltaQ, Int4 bank_id ){
    // Make bin of Q

    std::vector<Double> Qrange;
    if (BinType==0){
        Double currQ = Qmin-(deltaQ/2.0);
        Qrange.push_back( currQ );
        while(true){
            currQ += deltaQ;
            Qrange.push_back( currQ );
            if (currQ > Qmax) break;
        }
    }else if (BinType==1){
        Double factor = (2.0+deltaQ)/(2.0-deltaQ);
        if (Qmin<=0.0) Qmin = 1.0E-5; // for MLF beam line

        Double currQ = 2.0*Qmin/(1+factor);
        Double cQmin = currQ;
        Double i = 1.0;
        while(currQ<=Qmax){
            Qrange.push_back( currQ );
            currQ =  cQmin * pow(factor, i);
            i += 1.0;
        //currQ = currQ/(1.0-(deltaQ/2.0));
        }
    }else{
        std::cout << _MessageTag+" SetQRange : BinType is invalid. BinType must be 0 or 1, given value=" << BinType << std::endl;
        return;
    }
    std::cout << "Qmin, Qmax, deltaQ = "<<Qmin<<","<< Qmax<<","<<deltaQ<<std::endl;
    //for (UInt4 i=0; i<Qrange.size(); i++) std::cout << Qrange[i] << ",";
    //std::cout << std::endl;
    _MakeQHistogram( Qrange, bank_id );
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetQRange( UInt4 BinType, std::vector<Double> qinfo, Int4 bank_id ){
    if ((BinType!=0)&&(BinType!=1)){
        std::cout << _MessageTag+" SetQRange : BinType is invalid. BinType must be 0 or 1, given value=" << BinType << std::endl;
        return;
    }

    std::vector<Double> Qrange;
    UInt4 ind = 0;
    while(true){
        Double Qmin = qinfo[ind];
        Double deltaQ = qinfo[ind+1];
        Double Qmax = qinfo[ind+2];
        if (BinType==0){
            Double currQ = Qmin-(deltaQ/2.0);
            while(currQ<=Qmax){
                currQ += deltaQ;
                if (Qrange.empty())
                    Qrange.push_back( currQ );
                else if (Qrange.back()<currQ)
                    Qrange.push_back( currQ );
                else{
                }
            }
        }else{
            Double factor = (2.0+deltaQ)/(2.0-deltaQ);
            if (Qmin<=0.0) Qmin = 1.0E-5; // for MLF beam line
            Double currQ = 2.0*Qmin/(1+factor);
            Double cQmin = currQ;
            Double i = 1.0;
            while(currQ<=Qmax){
                if (Qrange.empty())
                    Qrange.push_back( currQ );
                else if (Qrange.back()<currQ)
                    Qrange.push_back( currQ );
                else{
                }
                currQ =  cQmin * pow(factor, i);
                i += 1.0;
                //currQ = currQ/(1.0-(deltaQ/2.0));
            }
        }
        ind += 2;
        if ((ind+2)>=qinfo.size()) break;
    }
    /*
    std::cout << "Qrange = ";
    for (UInt4 i=0; i<Qrange.size(); i++) std::cout << Qrange[i] << ",";
    std::cout << std::endl;
    */
    _MakeQHistogram( Qrange, bank_id );
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
SetQRange( std::vector<Double> qlist, Int4 bank_id ){
    _MakeQHistogram( qlist, bank_id );
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
_MakeQHistogram( std::vector<Double> Qrange, Int4 bank_id ){
    UInt4 num_Qbin = Qrange.size();

    UInt4 NumOfMulTh = 1;
#ifdef MULTH
    NumOfMulTh = MULTH;
#endif

    if (bank_id<0){
        UInt4 num_of_inner_id = 0;
        if (_TargetBankIdList.empty()){
            _hTableOfBanks.clear();
            for (UInt4 i=0; i<_NumOfBanks; i++){
                Int4 tmp_id = _BankIdList[i];
                if ( tmp_id>=_hTableOfBanks.size() ) _hTableOfBanks.resize( (tmp_id+1), -1 );
                _hTableOfBanks[tmp_id] = i;
                num_of_inner_id++;
            }

        }else{
            Int4 uni_id=-1;
            _hTableOfBanks.clear();
            for (UInt4 i=0; i<_NumOfBanks; i++){
                Int4 bid = _BankIdList[i];
                bool isNotFound = true;
                for (UInt4 j=0; j<_TargetBankIdList.size(); j++){
                    if (_TargetBankIdList[j]==bid){
                        if (uni_id<0) {
                            uni_id=num_of_inner_id;
                            num_of_inner_id++;
                        }
                        if ( (UInt4)bid>=_hTableOfBanks.size() ) _hTableOfBanks.resize( ((UInt4)bid+1), -1 );
                        _hTableOfBanks[ (UInt4)bid ] = uni_id;
                        isNotFound = false;
                        break;
                    }
                }
                if (isNotFound){
                    if ( bid>=_hTableOfBanks.size() ) _hTableOfBanks.resize( (bid+1), -1 );
                    _hTableOfBanks[ _BankIdList[i] ] = num_of_inner_id;
                    num_of_inner_id++;
                }
            }
        }
        ClearHist();
        _qInt = new std::vector<GslHistogram*> ( num_of_inner_id, NULL );
        _qErr = new std::vector<GslHistogram*> ( num_of_inner_id, NULL );
        _qCnt = new std::vector<GslHistogram*> ( num_of_inner_id, NULL );
        for (UInt4 i=0; i<num_of_inner_id; i++){
            Double* _qRangeInt = new Double [ num_Qbin ];
            Double* _qRangeErr = new Double [ num_Qbin ];
            Double* _qRangeCnt = new Double [ num_Qbin ];
            _qRangePointers.push_back(_qRangeInt);
            _qRangePointers.push_back(_qRangeErr);
            _qRangePointers.push_back(_qRangeCnt);
            for (UInt4 j=0; j<num_Qbin; j++){
                    _qRangeInt[j] = Qrange[j];
                    _qRangeErr[j] = Qrange[j];
                    _qRangeCnt[j] = Qrange[j];
            }

            (*_qInt)[i] = new GslHistogram( _qRangeInt, num_Qbin, NumOfMulTh );
            (*_qErr)[i] = new GslHistogram( _qRangeErr, num_Qbin, NumOfMulTh );
            (*_qCnt)[i] = new GslHistogram( _qRangeCnt, num_Qbin, NumOfMulTh );
        }

    }else{ // when bank_id is set.
        bool isNotFound = true;
        for (UInt4 i=0; i<_NumOfBanks; i++){
            if (bank_id == _BankIdList[i]){
                isNotFound = false;
                break;
            }
        }
        if (isNotFound){
            std::cout << _MessageTag+"SetQRange : bank_id is invalid (bank_id=" << bank_id << ")"<< std::endl;
            return;
        }

        UInt4 bid = (UInt4)bank_id;
        bool isHistExisted = true;
        if (_TargetBankIdList.empty()){

            if ( bid>=_hTableOfBanks.size() ) _hTableOfBanks.resize( (bid+1), -1 );
            if (_hTableOfBanks[bid]==-1){
                isHistExisted = false;
            }else{
                isHistExisted = true;
            }
        }else{
            bool isNotF = true;
            for (UInt4 i=0; i<_TargetBankIdList.size(); i++){
                if (bid==_TargetBankIdList[i]){
                    isNotF = false;
                    break;
                }
            }
            if (isNotF){
                if ( bid>=_hTableOfBanks.size() ) _hTableOfBanks.resize( (bid+1), -1 );
                if (_hTableOfBanks[bid]==-1){
                    isHistExisted = false;
                }else{
                    isHistExisted = true;
                }
            }else{

                Int4 ind = -1;
                for (UInt4 i=0; i<_TargetBankIdList.size(); i++){
                    UInt4 tmp=_TargetBankIdList[i];
                    if (tmp<_hTableOfBanks.size()){
                        if (_hTableOfBanks[tmp]!=-1){
                            ind = _hTableOfBanks[tmp];
                            break;
                        }
                    }
                }
                if (ind<0){
                    isHistExisted = false;
                }else{
                    isHistExisted = true;
                    _hTableOfBanks[bid] = (Int4)ind;
                }
            } //if (isNotF)
        } //if (_TargetBankIdList.empty()) when bank_id>=0

        Double* _qRange = new Double [ num_Qbin ];
        for (UInt4 i=0; i<num_Qbin; i++)
            _qRange[i] = Qrange[i];
        _qRangePointers.push_back(_qRange);

        if (isHistExisted){
            if (_hTableOfBanks[bid]<0){
                std::cout << _MessageTag+" Bad BankId = " << bid << std::endl;
                return;
            }
            UInt4 ind = _hTableOfBanks[bid];
            delete (*_qInt)[ind];
            delete (*_qErr)[ind];
            delete (*_qCnt)[ind];
            (*_qInt)[ind] = new GslHistogram( _qRange, num_Qbin, NumOfMulTh );
            (*_qErr)[ind] = new GslHistogram( _qRange, num_Qbin, NumOfMulTh );
            (*_qCnt)[ind] = new GslHistogram( _qRange, num_Qbin, NumOfMulTh );
        }else{
            if (_qInt==NULL){
                _qInt = new std::vector<GslHistogram*> ( 1, NULL );
                _qErr = new std::vector<GslHistogram*> ( 1, NULL );
                _qCnt = new std::vector<GslHistogram*> ( 1, NULL );
            }else{
                _qInt->push_back( NULL );
                _qErr->push_back( NULL );
                _qCnt->push_back( NULL );
            }
            UInt4 ind = (_qInt->size())-1;
            (*_qInt)[ind] = new GslHistogram( _qRange, num_Qbin, NumOfMulTh );
            (*_qErr)[ind] = new GslHistogram( _qRange, num_Qbin, NumOfMulTh );
            (*_qCnt)[ind] = new GslHistogram( _qRange, num_Qbin, NumOfMulTh );
            _hTableOfBanks[bid] = (Int4)ind;
        }

    } //if (bank_id<0)

    /*
    std::cout << "#### SetQRange : hTableOfBanks=";
    for (UInt4 i=0; i<_hTableOfBanks.size(); i++){
        std::cout << _hTableOfBanks[i] << ",";
    }
    std::cout << std::endl;

    for (UInt4 i=0; i<cnt; i++)
        std::cout << _qRange[i] << ",";
    std::cout << std::endl;
    */

}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
Increment( ElementContainer* ec, Int4 bank_id, UInt4 multh, bool isDebug ){

    if (bank_id<0) bank_id=0;

    if ( (bank_id>=_hTableOfBanks.size())||(_hTableOfBanks[bank_id]==-1) ){
        std::cout << "@@@@@ Bank_ID invalid bank_id=" << bank_id << std::endl;
        return;
    }

    HeaderBase* hh = ec->PutHeaderPointer();
    std::vector<Double> azim_v = hh->PutDoubleVector("PixelAzimAngle");
    Double azim_angle = azim_v[0];
    std::vector<Double> pola_v = hh->PutDoubleVector("PixelPolarAngle");
    Double pol_angle = pola_v[0];

    // Check pixel is inside of given angle range
    bool isInside = false;
    if (_SectorAngleInfo.empty())
        isInside = true;

    bool isInsidePol = false;
    bool isInsideAzim = false;
    for (UInt4 i=0; i<_SectorAngleInfo.size(); i++){

        std::vector<Double> tmp = _SectorAngleInfo[i];

        if ((tmp[2]==0.0)&&(tmp[3]==0.0)){
            isInsidePol = true;
        }else if ( (pol_angle<=tmp[3])&&(pol_angle>=tmp[2]) ){
            isInsidePol = true;
        }

        if ( (tmp[0]==0.0)&&(tmp[1]==0.0) ){
            isInsideAzim = true;
        }else if (tmp[0]>=0.0) {
            if (tmp[1]>=0.0){
                if (tmp[1]>tmp[0]){
                    if ((azim_angle>=tmp[0])&&(azim_angle<=tmp[1])){
                        isInsideAzim = true;
                    }
                }else{
                    if ( (azim_angle<=tmp[1])||(azim_angle>=tmp[0]) ){
                        isInsideAzim = true;
                    }
                }
            }else{  // tmp[1]<0.0
                if ( (azim_angle<=tmp[1])||(azim_angle>=tmp[0]) ){
                    isInsideAzim = true;
                }
            }
        }else{ // tmp[0]<0.0
            if (tmp[1]>=0.0){
                if ( (azim_angle>=tmp[0])&&(azim_angle<=tmp[1]) ) {
                    isInsideAzim = true;
                }
            }else{ // tmp[1]<0.0
                if (tmp[1]>tmp[0]){
                    if ( (azim_angle>=tmp[0])&&(azim_angle<=tmp[1]) ) {
                        isInsideAzim = true;
                    }
                }else{
                    if ( (azim_angle<=tmp[1])||(azim_angle>=tmp[0]) ) {
                        isInsideAzim = true;
                    }
                }
            }
        }

        if ( (isInsidePol)&&(isInsideAzim) ){
            isInside = true;
        }
    }

    // If pixel is inside
    bool isSetLambdaRange2=true;
    Double lamda_min = _LambdaRangeList[bank_id][0];
    Double lamda_max = _LambdaRangeList[bank_id][1];
    if ((lamda_min==0.0)&&(lamda_max==0.0)) isSetLambdaRange2=false;

    if (isInside){
        UInt4 tmp_id = _hTableOfBanks[bank_id];
        //std::cout << "#### multh,tmp_id=" << multh << "," << tmp_id << std::endl;
        if ( (*_qInt)[tmp_id]!=NULL ){
            std::vector<Double> ii = ec->Put("Intensity");
            std::vector<Double> ee = ec->Put("Error");

            std::vector<Double> lamb = ec->Put("Lamb");
            //std::vector<Double> qx = ec->Put("Qx");
            //std::vector<Double> qy = ec->Put("Qy");
            //std::vector<Double> qz = ec->Put("Qz");  //[inamura 140314]
            std::vector<Double> qxh = ec->Put("Qx");
            std::vector<Double> qyh = ec->Put("Qy");
            std::vector<Double> qzh = ec->Put("Qz");

            Double solid_angle = ec->PutHeaderPointer()->PutDouble("PixelSolidAngle");

            for (UInt4 i=0; i< lamb.size(); i++){
                if (ee[i]<0) continue;

                if (isSetLambdaRange2)
                    if ( (lamb[i]<lamda_min)||(lamb[i]>lamda_max) ) continue;

                //Double q_val = sqrt( qx[i]*qx[i] + qy[i]*qy[i] + qz[i]*qz[i] ); //[inamura 140314]
                Double start_qval = sqrt( qxh[i]*qxh[i] + qyh[i]*qyh[i] + qzh[i]*qzh[i] );
                Double end_qval = sqrt( qxh[i+1]*qxh[i+1] + qyh[i+1]*qyh[i+1] + qzh[i+1]*qzh[i+1] );
                Double qbin  = fabs( start_qval - end_qval );
                Double q_val = sqrt( pow( ((qxh[i+1]+qxh[i])/2.0), 2.0 ) + pow( ((qyh[i+1]+qyh[i])/2.0), 2.0 ) + pow( ((qzh[i+1]+qzh[i])/2.0), 2.0 ) );

                if (isDebug) std::cout << "multh=" << multh << "," << q_val << std::endl;

                if (isInQLambdaToIq( bank_id, lamb[i], q_val )){
                    (*_qInt)[tmp_id]->Increment( q_val, multh, ii[i] );   // Without Jacobian
                    (*_qErr)[tmp_id]->Increment( q_val, multh, ee[i]*ee[i] );
                    //(*_qInt)[tmp_id]->Increment( q_val, multh, ii[i]/qbin );  // With Jacobian
                    //(*_qErr)[tmp_id]->Increment( q_val, multh, ee[i]*ee[i]/qbin/qbin );
                    (*_qCnt)[tmp_id]->Increment( q_val, multh, 1.0 );
                    //(*_qCnt)[tmp_id]->Increment( q_val, multh, solid_angle );
                }
            }
        }else{
            //std::cout << "gslHist=NULL tmp_id="<<tmp_id<< std::endl;
        }
    }else{
        //std::cout << "isInside out" << std::endl;
    }

    return;
}
//////////////////////////////////////////////////////////
bool SectorAverageByAngle::
Execute(){
    ElementContainerMatrix* ecm = PutInput();

#ifdef MULTH
    omp_set_num_threads( MULTH );
#endif
    // Reset GslHistogram
    for (UInt4 i=0; i<(*_qInt).size(); i++){
        if ( (*_qInt)[i]!=NULL ){
            (*_qInt)[i]->Reset();
            (*_qErr)[i]->Reset();
            (*_qCnt)[i]->Reset();
        }
    }

    for (UInt4 i=0; i<ecm->PutSize(); i++){
        ElementContainerArray* eca = ecm->PutPointer(i);
        if (eca->PutHeaderPointer()->PutInt4("MASKED")==1) continue;
        Int4 bankId = eca->PutHeaderPointer()->PutInt4("BANKID");

#ifdef MULTH
#pragma omp parallel for
#if (_OPENMP >= 200805)  // OpenMP 3.0 and later
        for (UInt4 j=0; j<eca->PutSize(); j++){
#else
        for (Int4 j=0; j<eca->PutSize(); j++){
#endif
            ElementContainer *ec = eca->PutPointer(j);
            if ((ec->PutHeaderPointer()->PutInt4("MASKED"))==1) continue;

            UInt4 ThNum = omp_get_thread_num();
            //try{

            Increment( ec, bankId, ThNum );
                //}
                //catch(...){
                //std::cout << _MessageTag+" Error in Increment." << std::endl;
                //}
        }
#else
        for (UInt4 j=0; j<eca->PutSize(); j++){
            ElementContainer *ec = eca->PutPointer(j);
            if ((ec->PutHeaderPointer()->PutInt4("MASKED"))==1) continue;
            try{
                Increment( ec, bankId, 0 );
            }
            catch(...){
                std::cout << _MessageTag+" Error in Increment." << std::endl;
            }
        }
#endif
    }

    ClearOutput();

    for (UInt4 i=0; i<(_qInt->size()); i++){
        std::vector<Double> II = _qInt->at(i)->PutHistogram();
        std::vector<Double> EE = _qErr->at(i)->PutHistogram();
        std::vector<Double> CC = _qCnt->at(i)->PutHistogram();
        std::vector<Double> XX = _qInt->at(i)->PutBin();
        UInt4 v_size = II.size();
        std::vector<Double> Intensity( v_size, 0.0 );
        std::vector<Double> Error( v_size, -1.0 );
        std::vector<Double> Q( v_size, 0.0 );
        for (UInt4 j=0; j<v_size; j++){
            Q[j] = (XX[j]+XX[j+1])/2.0;
            if (CC[j]!=0.0){
                Intensity[j] = II[j]/CC[j];
                Error[j] = sqrt(EE[j])/CC[j];
                //std::cout << "j : II[j],EE[j],CC[j] ="<<j<<" : "<<II[j]<<","<<EE[j]<<","<<CC[j]<<std::endl;
                //Intensity[j] = II[j];
                //Error[j] = sqrt(EE[j]);
            }
        }


        ElementContainer* ec = new ElementContainer();
        HeaderBase* hh = ec->PutHeaderPointer();
        std::string runNo_s = ecm->PutHeaderPointer()->PutString("RUNNUMBER");
        hh->Add( "RUNNUMBER", runNo_s );

        std::string bankName="";
        for (UInt4 j=0; j<(_BankIdList.size()); j++){
            Int4 bid = _BankIdList[j];
            if (_hTableOfBanks[ (UInt4)bid ]!=-1){
                if ( (UInt4)_hTableOfBanks[ (UInt4)bid ]==i ){
                    if (bankName=="") bankName = _BankNameList[j];
                    else bankName += "-"+_BankNameList[j];
                }
            }
        }
        hh->Add( "BANKNAME", bankName );
        hh->Add( "XLABEL", "Q" );
        hh->Add( "YLABEL", "Intensity" );
        std::string Label_s = runNo_s+"("+bankName+")";
        hh->Add( "Label", Label_s );
        ec->Add( "Q", Q, "1/Ang" );
        ec->Add( "Intensity", Intensity, "counts" );
        ec->Add( "Error", Error, "counts" );
        ec->Add( "Qhist", XX, "1/Ang" );
        ec->Add( "CountN", CC, "" );
        ec->SetKeys( "Qhist", "Intensity", "Error" );
        SetOutput( ec );
        //std::cout << _MessageTag+"Execute : make ElementContainer inner bank_id=" << i << std::endl;

    }

    return true;
}

//////////////////////////////////////////////////////////
ElementContainer SectorAverageByAngle::
PutIq( Int4 bank_id ){
    if ( (bank_id>=_hTableOfBanks.size())||(_hTableOfBanks[bank_id]==-1) ){
        std::cout << _MessageTag+"PutIq : bank_id is too large or not included in this ElementContainerMatrix, bank_id= "<< bank_id << std::endl;
        ElementContainer ret;
        return ret;
    }
    if (bank_id==-1) return PutAverage();
    else return Put(_hTableOfBanks[ bank_id ]);
}
//////////////////////////////////////////////////////////
ElementContainer SectorAverageByAngle::
PutAverage(){
    ElementContainerMatrix* ecm = PutInput();
    HeaderBase* hh_ecm = ecm->PutHeaderPointer();
    std::vector<Int4> bank_id_list = hh_ecm->PutInt4Vector( "BANKIDLIST" );

    ElementContainer ec = Put( bank_id_list[0] );

    ElementContainer ret_ec;
    ret_ec.Add( "Qhist", ec.Put("Qhist"), "1/Ang" );
    ret_ec.Add( "Q", ec.Put("Q"), "1/Ang" );

    std::vector<Double> tmp_ii = ec.Put("Intensity");
    std::vector<Double> ret_int(tmp_ii.size(),0.0);
    std::vector<Double> ret_err(tmp_ii.size(),0.0);
    std::vector<Double> ret_cnt(tmp_ii.size(),0.0);
    std::vector<bool> ret_msk(tmp_ii.size(),false);

    for (UInt4 i=0; i<bank_id_list.size(); i++){
        ElementContainer ec = Put( bank_id_list[i] );
        std::vector<Double> tmp_int = ec.Put("Intensity");
        std::vector<Double> tmp_err = ec.Put("Error");
        std::vector<Double> tmp_cnt = ec.Put("CountN");
        for (UInt4 j=0; j<tmp_int.size(); j++){
            ret_int[j] += tmp_int[j]*tmp_cnt[j];
            ret_err[j] += (tmp_err[j]*tmp_cnt[j])*(tmp_err[j]*tmp_cnt[j]);
            if (tmp_err[j]<0) ret_msk[j] = true;
            ret_cnt[j] += tmp_cnt[j];
        }
    }
    for (UInt4 i=0; i<ret_int.size(); i++){
        ret_int[i] = ret_int[i]/ret_cnt[i];
        ret_err[i] = sqrt(ret_err[i])/ret_cnt[i];
        if (ret_msk[i]) ret_err[i] = ret_err[i]*(-1.0);
    }

    ret_ec.Add( "Intensity", ret_int, "counts" );
    ret_ec.Add( "Error", ret_err, "counts" );

    return ret_ec;

}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
ClearQLambdaRangeToIq(){
    _QLambRangeToIq.clear();
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
AddQLambdaRangeToIq( Double lamb, Double Qmin, Double Qmax ){
    std::vector< std::vector<Double> > tmp1;
    std::vector<Double> tmp2(3,0.0);

    if ((Qmin<0.0)||(Qmax<0.0)){
        std::cout << _MessageTag+"AddQLambdaRangeToIq >> Qmin or Qmax < 0 ";
        std::cout << Qmin << "," << Qmax << std::endl;
        return;
    }
    bool isFinAdd = false;
    for (UInt4 i=0; i<_QLambRangeToIq.size(); i++){
        if (_QLambRangeToIq[i][0]>=lamb){
            tmp2[0] = lamb;
            tmp2[1] = Qmin;
            tmp2[2] = Qmax;
            tmp1.push_back( tmp2 );
            isFinAdd = true;
        }
        tmp2[0] = _QLambRangeToIq[i][0];
        tmp2[1] = _QLambRangeToIq[i][1];
        tmp2[2] = _QLambRangeToIq[i][2];
        tmp1.push_back( tmp2 );
    }

    if (isFinAdd){
    }else{
        tmp2[0] = lamb;
        tmp2[1] = Qmin;
        tmp2[2] = Qmax;
        tmp1.push_back( tmp2 );
    }

    ClearQLambdaRangeToIq();

    for (UInt4 i=0; i<tmp1.size(); i++)
        _QLambRangeToIq.push_back(tmp1[i]);

}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
ShowQLambdaRangeToIq(){
    std::cout << "_QLambdaRangeToIq" << std::endl;
    for (UInt4 i=0; i<_QLambRangeToIq.size(); i++){
        std::cout << i << ":" << _QLambRangeToIq[i][0] << ",";
        std::cout << _QLambRangeToIq[i][1] << "," << _QLambRangeToIq[i][2] << std::endl;
    }
}
//////////////////////////////////////////////////////////
std::vector<Double> SectorAverageByAngle::
_getLinearApproximationQLamb( Double lamb, UInt4 index ){
    std::vector<Double> ret;

    if (index>=(_QLambRangeToIq.size()-1)) return ret;

    double lamb0 = _QLambRangeToIq[index][0];
    double lamb1 = _QLambRangeToIq[index+1][0];
    double qmin0 = _QLambRangeToIq[index][1];
    double qmin1 = _QLambRangeToIq[index+1][1];
    double qmax0 = _QLambRangeToIq[index][2];
    double qmax1 = _QLambRangeToIq[index+1][2];

    double qmin = ( (qmin1-qmin0)/(lamb1-lamb0) )*(lamb - lamb0) + qmin0;
    double qmax = ( (qmax1-qmax0)/(lamb1-lamb0) )*(lamb - lamb0) + qmax0;

    ret.push_back(qmin);
    ret.push_back(qmax);

    return ret;
}
//////////////////////////////////////////////////////////
bool SectorAverageByAngle::
isInQLambdaToIq( Double lamb, Double q_val ){
    if (_QLambRangeToIq.empty() ) return true;
    if (_QLambRangeToIq.size()==1) return true;

    bool ret = false;

    if (lamb<_QLambRangeToIq[0][0]){
        std::vector<Double> qq = _getLinearApproximationQLamb( lamb, 0 );
        if (qq.empty()){
        }else if (( qq[0]<=q_val )&&( qq[1]>=q_val ) )
            ret = true;

    }else if (lamb>_QLambRangeToIq[ _QLambRangeToIq.size()-1 ][0]){
        std::vector<Double> qq = _getLinearApproximationQLamb( lamb, (_QLambRangeToIq.size()-2 ) );
        if (qq.empty()){
        }else if (( qq[0]<=q_val )&&( qq[1]>=q_val ) )
            ret = true;
    }else{
        for (UInt4 i=0; i<_QLambRangeToIq.size()-1; i++){
            if (( lamb>=_QLambRangeToIq[i][0] )&&( lamb<=_QLambRangeToIq[i+1][0] )){
                std::vector<Double> qq = _getLinearApproximationQLamb( lamb, i );
                if (qq.empty()){
                }else if (( qq[0]<=q_val )&&( qq[1]>=q_val ) ){
                    ret = true;
                    break;
                }
            }
        }
    }

    return ret;
}


//////////////////////////////////////////////////////////
std::vector<Double> SectorAverageByAngle::
_getLinearApproximationQLamb( UInt4 bankId, Double lamb, UInt4 index ){
    std::vector<Double> ret;

    if (index>=(_QLimRangeToIqOfBanks[bankId].size()-1)) return ret;

    double lamb0 = _QLimRangeToIqOfBanks[bankId][index][0];
    double lamb1 = _QLimRangeToIqOfBanks[bankId][index+1][0];
    double qmin0 = _QLimRangeToIqOfBanks[bankId][index][1];
    double qmin1 = _QLimRangeToIqOfBanks[bankId][index+1][1];
    double qmax0 = _QLimRangeToIqOfBanks[bankId][index][2];
    double qmax1 = _QLimRangeToIqOfBanks[bankId][index+1][2];

    if (((qmin0==0.0)&&(qmax0==0.0)) || ((qmin1==0.0)&&(qmax1==0.0))) return ret;

    double qmin = ( (qmin1-qmin0)/(lamb1-lamb0) )*(lamb - lamb0) + qmin0;
    double qmax = ( (qmax1-qmax0)/(lamb1-lamb0) )*(lamb - lamb0) + qmax0;

    ret.push_back(qmin);
    ret.push_back(qmax);

    return ret;
}
//////////////////////////////////////////////////////////
bool SectorAverageByAngle::
isInQLambdaToIq( UInt4 bankId, Double lamb, Double q_val ){
    if (_QLimRangeToIqOfBanks.empty() ) return true;
    if (_QLimRangeToIqOfBanks.size()<=bankId) return true;
    if (_QLimRangeToIqOfBanks[bankId].empty() ) return true;
    if (_QLimRangeToIqOfBanks[bankId].size()==1) return true;

    bool ret = false;

    if (lamb<_QLimRangeToIqOfBanks[bankId][0][0]){
        std::vector<Double> qq = _getLinearApproximationQLamb( bankId, lamb, 0 );
        if (qq.empty()){
        }else if (( qq[0]<=q_val )&&( qq[1]>=q_val ) )
            ret = true;

    }else if (lamb>_QLimRangeToIqOfBanks[bankId][ _QLimRangeToIqOfBanks[bankId].size()-1 ][0]){
        std::vector<Double> qq = _getLinearApproximationQLamb( bankId, lamb, (_QLimRangeToIqOfBanks[bankId].size()-2 ) );
        if (qq.empty()){
        }else if (( qq[0]<=q_val )&&( qq[1]>=q_val ) )
            ret = true;
    }else{
        for (UInt4 i=0; i<_QLimRangeToIqOfBanks[bankId].size()-1; i++){
            if (( lamb>=_QLimRangeToIqOfBanks[bankId][i][0] )&&( lamb<=_QLimRangeToIqOfBanks[bankId][i+1][0] )){
                std::vector<Double> qq = _getLinearApproximationQLamb( bankId, lamb, i );
                if (qq.empty()){
                }else if (( qq[0]<=q_val )&&( qq[1]>=q_val ) ){
                    ret = true;
                    break;
                }
            }
        }
    }

    return ret;
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
AddQLambdaRangeToIq( UInt4 bankId, Double lamb, Double Qmin, Double Qmax ){
    std::vector< std::vector<Double> > tmp1;
    std::vector<Double> tmp2(3,0.0);

    if (_QLimRangeToIqOfBanks.size()<=bankId){
        _QLimRangeToIqOfBanks.resize( (bankId+1) );
        _QLimRangeToIqOfBanks[bankId].clear();
    }

    if ((Qmin<0.0)||(Qmax<0.0)){
        std::cout << _MessageTag+"AddQLambdaRangeToIq >> Qmin or Qmax < 0 ";
        std::cout << Qmin << "," << Qmax << std::endl;
        return;
    }
    bool isFinAdd = false;
    for (UInt4 i=0; i<_QLimRangeToIqOfBanks[bankId].size(); i++){
        if (_QLimRangeToIqOfBanks[bankId][i][0]>=lamb){
            tmp2[0] = lamb;
            tmp2[1] = Qmin;
            tmp2[2] = Qmax;
            tmp1.push_back( tmp2 );
            isFinAdd = true;
        }
        tmp2[0] = _QLimRangeToIqOfBanks[bankId][i][0];
        tmp2[1] = _QLimRangeToIqOfBanks[bankId][i][1];
        tmp2[2] = _QLimRangeToIqOfBanks[bankId][i][2];
        tmp1.push_back( tmp2 );
    }

    if (isFinAdd){
    }else{
        tmp2[0] = lamb;
        tmp2[1] = Qmin;
        tmp2[2] = Qmax;
        tmp1.push_back( tmp2 );
    }

    ClearQLimRangeToIqOfBanks( bankId );

    for (UInt4 i=0; i<tmp1.size(); i++)
        _QLimRangeToIqOfBanks[bankId].push_back(tmp1[i]);

}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
ClearQLimRangeToIqOfBanks(){
    _QLimRangeToIqOfBanks.clear();
}
//////////////////////////////////////////////////////////
void SectorAverageByAngle::
ClearQLimRangeToIqOfBanks(UInt4 bankId){
    if (_QLimRangeToIqOfBanks.size()<=bankId) return;
    _QLimRangeToIqOfBanks[bankId].clear();
}
