#include "TreatQhklWithUB.hh"
//////////////////////////////////////////////////////////
TreatQhklWithUB::TreatQhklWithUB()
{
    Initialize();
}
//////////////////////////////////////////////////////////
TreatQhklWithUB::TreatQhklWithUB( ElementContainerMatrix* ecm )
{
    Initialize();
    SetTarget(ecm);
}
//////////////////////////////////////////////////////////
TreatQhklWithUB::~TreatQhklWithUB()
{
    delete _CTP;
}
//////////////////////////////////////////////////////////
void TreatQhklWithUB::Initialize(){
    _Labels.clear();
    _Labels.push_back( "H" );
    _Labels.push_back( "K" );
    _Labels.push_back( "L" );
    _Keys.clear();
    _Keys.push_back( "Q1" );
    _Keys.push_back( "Q2" );
    _Keys.push_back( "Q3" );
    _Units.clear();
    _Units.resize(3, "rlu");
    _indSliceX = 0;
    _indSliceY = 1;
    _indSliceT = 2;
    _Qxbin.clear();
    _Qybin.clear();
    _ViewAxes.clear();
    _ViewAxes.resize(9,0);
    _ViewAxes[0]=1.0;
    _ViewAxes[4]=1.0;
    _ViewAxes[8]=1.0;;

    _MessageTag = "TreatQhklWithUB::";
    _CTP = new CppToPython();
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::SetUBmatrix( std::vector<Double> ubmat ){

    /* given UB matrix
       |Qx|   | ubmat[0], ubmat[1], ubmat[2] | |H|
       |Qy| = | ubmat[3], ubmat[4], ubmat[5] | |K|
       |Qz|   | ubmat[6], ubmat[7], ubmat[8] | |L|

       Inverted UB Matrix ( UBmatrix in this class )
       |H|   | _UBmat[0], _UBmat[1], _UBmat[2] | |Qx|
       |K| = | _UBmat[3], _UBmat[4], _UBmat[5] | |Qy|
       |L|   | _UBmat[6], _UBmat[7], _UBmat[8] | |Qz|

    */
    if (ubmat.size()!=9){
        UtsusemiError(_MessageTag+"SetUBmatrix argument is invalid (Size=9)");
        return false;
    }
    std::vector<Double> ubmat_i=InverseMatrix( ubmat );
    _UBmat.clear();
    _UBmat.resize(9,0.0);
    copy( ubmat_i.begin(), ubmat_i.end(), _UBmat.begin() );
    return true;
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::SetUBmatrix( PyObject* ubmat ){
    if ( ! PyList_Check( ubmat ) ){
        UtsusemiError("SAS.TreatQhklWithUB::SetUBmatrix >>> given ubmat must be list");
        return false;
    }
    UInt4 ubmat_size = (UInt4) PyList_Size( ubmat );
    if (ubmat_size!=9){
        UtsusemiError("SAS.TreatQhklWithUB::SetUBmatrix >>> given ubmat size is not 9 ");
        return false;
    }
    return SetUBmatrix( _CTP->ListToDoubleVector( ubmat ) );
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::SetViewAxesLabels( std::string Q1Label, std::string  Q2Label, std::string Q3Label,std::string Q1Unit, std::string Q2Unit, std::string Q3Unit ){
    _Labels[0] = Q1Label;
    _Labels[1] = Q2Label;
    _Labels[2] = Q3Label;
    _Units[0] = Q1Unit;
    _Units[1] = Q2Unit;
    _Units[2] = Q3Unit;
    return true;
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::SetViewAxes( std::vector<Double> vaxes){
    if (vaxes.size()==9){
        _ViewAxes.clear();
        _ViewAxes.resize(9);
        copy( vaxes.begin(), vaxes.end(), _ViewAxes.begin() );
        return true;
    }else{
        UtsusemiError(_MessageTag+"SetViewAxes >> given axes param size is invalid, 9 required.");
        return false;
    }
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::SetViewAxes( PyObject* Q1, PyObject* Q2, PyObject* Q3){
    if ( (! PyList_Check(Q1)) || (! PyList_Check(Q2)) || (! PyList_Check(Q3)) ){
        UtsusemiError(_MessageTag+"SetViewAxes >>> given arguments must be list");
        return false;
    }
    std::vector<Double> vaxes = _CTP->ListToDoubleVector(Q1);
    std::vector<Double> v2 = _CTP->ListToDoubleVector(Q2);
    std::vector<Double> v3 = _CTP->ListToDoubleVector(Q3);
    for (UInt4 i=0;i<v2.size();i++) vaxes.push_back(v2[i]);
    for (UInt4 i=0;i<v3.size();i++) vaxes.push_back(v3[i]);
    return SetViewAxes( vaxes );
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::Projection(){
    /* |UB matrix| x |vaxes|
       |Qh|   | ubmat[0], ubmat[1], ubmat[2] |-1   |Qx|
       |Qk| = | ubmat[3], ubmat[4], ubmat[5] |   x |Qy|
       |Ql|   | ubmat[6], ubmat[7], ubmat[8] |     |Qz|

       vec(V1) = vaxes[0]*vec(Qh) + vaxes[1]*vec(Qk) + vaxes[2]*vec(Ql)
       vec(V2) = vaxes[3]*vec(Qh) + vaxes[4]*vec(Qk) + vaxes[5]*vec(Ql)
       vec(V3) = vaxes[6]*vec(Qh) + vaxes[7]*vec(Qk) + vaxes[8]*vec(Ql)

       |V1|   |vaxes[0],vaxes[3],vaxes[5]|-1   |Qh|
       |V2| = |vaxes[1],vaxes[4],vaxes[7]|   x |Qk|
       |V3|   |vaxes[2],vaxes[5],vaxes[8]|     |Ql|
    */
    if (_UBmat.empty()){
        UtsusemiError(_MessageTag+"Execute UBmatrix is not set");
        return false;
    }
    if ((_ViewAxes.empty())||(_ViewAxes.size()==9)){
    }else{
        UtsusemiError(_MessageTag+"Execute argument is invalid");
        return false;
    }
    gsl_matrix* UB = gsl_matrix_alloc(3,3);

    if (_ViewAxes.size()==9){
        gsl_matrix* T0 = gsl_matrix_alloc(3,3);
        _SetVectToMatrix( _UBmat, T0 ); // T0 = _UBmat
        gsl_matrix* T1 = gsl_matrix_alloc(3,3);
        gsl_matrix* T2 = gsl_matrix_alloc(3,3);
        _SetViewVectToMatrix( _ViewAxes, T1 );
        _CalcInverseMatrix( T1, T2 ); // T2 = inversed _ViewAxes
        gsl_blas_dgemm( CblasNoTrans, CblasNoTrans, 1.0, T2, T0, 0.0, UB ); // 1.0*[L^(-1)][U] -> T1
        gsl_matrix_free(T0);
        gsl_matrix_free(T1);
        gsl_matrix_free(T2);
    }else{
        _SetVectToMatrix( _UBmat, UB );
    }
    /**
    double a11 = gsl_matrix_get( UB, 0, 0 );
    double a12 = gsl_matrix_get( UB, 1, 0 );
    double a13 = gsl_matrix_get( UB, 2, 0 );
    double a21 = gsl_matrix_get( UB, 0, 1 );
    double a22 = gsl_matrix_get( UB, 1, 1 );
    double a23 = gsl_matrix_get( UB, 2, 1 );
    double a31 = gsl_matrix_get( UB, 0, 2 );
    double a32 = gsl_matrix_get( UB, 1, 2 );
    double a33 = gsl_matrix_get( UB, 2, 2 );
    **/
    double a11 = gsl_matrix_get( UB, 0, 0 );
    double a12 = gsl_matrix_get( UB, 0, 1 );
    double a13 = gsl_matrix_get( UB, 0, 2 );
    double a21 = gsl_matrix_get( UB, 1, 0 );
    double a22 = gsl_matrix_get( UB, 1, 1 );
    double a23 = gsl_matrix_get( UB, 1, 2 );
    double a31 = gsl_matrix_get( UB, 2, 0 );
    double a32 = gsl_matrix_get( UB, 2, 1 );
    double a33 = gsl_matrix_get( UB, 2, 2 );

    ElementContainerMatrix* ecm = Put();
    for (UInt4 i=0;i<(ecm->PutSize());i++){
        if (ecm->PutPointer(i)->PutHeaderPointer()->PutInt4("MASKED")==1) continue;
        for (UInt4 j=0; j<ecm->PutPointer(i)->PutSize(); j++){
            ElementContainer* ec = ecm->PutPointer(i)->PutPointer(j);
            if (ec->PutHeaderPointer()->PutInt4("MASKED")==1) continue;
            std::vector<double>* qx = ec->PutP("Qx");
            std::vector<double>* qy = ec->PutP("Qy");
            std::vector<double>* qz = ec->PutP("Qz");
            UInt4 v_size = qx->size();
            std::vector<double> Q1(v_size,0.0);
            std::vector<double> Q2(v_size,0.0);
            std::vector<double> Q3(v_size,0.0);
            for (UInt4 k=0; k<(qx->size()); k++){
                Q1[k] = a11*(*qx)[k] + a12*(*qy)[k] + a13*(*qz)[k];
                Q2[k] = a21*(*qx)[k] + a22*(*qy)[k] + a23*(*qz)[k];
                Q3[k] = a31*(*qx)[k] + a32*(*qy)[k] + a33*(*qz)[k];
            }

            //ec->Remove("Qx");
            //ec->Remove("Qy");
            //ec->Remove("Qz");
            if (ec->CheckKey(_Keys[0])==1)
                ec->Replace(_Keys[0], Q1);
            else
                ec->Add(_Keys[0], Q1, _Units[0]);
            if (ec->CheckKey(_Keys[1])==1)
                ec->Replace(_Keys[1], Q2);
            else
                ec->Add(_Keys[1], Q2, _Units[1]);
            if (ec->CheckKey(_Keys[2])==1)
                ec->Replace(_Keys[2], Q3);
            else
                ec->Add(_Keys[2], Q3, _Units[2]);
        }
    }
    gsl_matrix_free(UB);

    return true;
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::_SetVectToMatrix( std::vector<double> v, gsl_matrix* M ){
    gsl_matrix_set_all(M,0.0);
    for (UInt4 col=0; col<3; col++){
        for (UInt4 row=0; row<3; row++){
            gsl_matrix_set( M, col, row, v[ col*3 + row ] );
        }
    }
    return true;
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::_SetViewVectToMatrix( std::vector<double> v, gsl_matrix* M ){
    gsl_matrix_set_all(M,0.0);
    for (UInt4 col=0; col<3; col++){
        for (UInt4 row=0; row<3; row++){
            gsl_matrix_set( M, row, col, v[ col*3 + row ] );
        }
    }
    return true;
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::_CalcInverseMatrix( gsl_matrix *Min, gsl_matrix *Mout ){
    double a11 = gsl_matrix_get( Min, 0, 0 );
    double a12 = gsl_matrix_get( Min, 0, 1 );
    double a13 = gsl_matrix_get( Min, 0, 2 );
    double a21 = gsl_matrix_get( Min, 1, 0 );
    double a22 = gsl_matrix_get( Min, 1, 1 );
    double a23 = gsl_matrix_get( Min, 1, 2 );
    double a31 = gsl_matrix_get( Min, 2, 0 );
    double a32 = gsl_matrix_get( Min, 2, 1 );
    double a33 = gsl_matrix_get( Min, 2, 2 );
    double det = a11*a22*a33 + a12*a23*a31 + a13*a21*a32 - a13*a22*a31 - a12*a21*a33 - a11*a23*a32;
    if (det==0.0) return false;

    gsl_matrix_set( Mout, 0, 0, (a22*a33-a23*a32)/det );
    gsl_matrix_set( Mout, 0, 1, -1.0*(a12*a33-a13*a32)/det );
    gsl_matrix_set( Mout, 0, 2, (a12*a23-a13*a22)/det );
    gsl_matrix_set( Mout, 1, 0, -1.0*(a21*a33-a23*a31)/det );
    gsl_matrix_set( Mout, 1, 1, (a11*a33-a13*a31)/det );
    gsl_matrix_set( Mout, 1, 2, -1.0*(a11*a23-a13*a21)/det );
    gsl_matrix_set( Mout, 2, 0, (a21*a32-a22*a31)/det );
    gsl_matrix_set( Mout, 2, 1, -1.0*(a11*a32-a12*a31)/det );
    gsl_matrix_set( Mout, 2, 2, (a11*a22-a12*a21)/det );

    return true;
}
//////////////////////////////////////////////////////////
std::vector<Double> TreatQhklWithUB::InverseMatrix( std::vector<Double> a ){
    std::vector<Double> ret;

    gsl_matrix* Min = gsl_matrix_alloc(3,3);
    gsl_matrix* Mout = gsl_matrix_alloc(3,3);
    gsl_matrix_set_all(Mout, 0.0);
    UInt4 ind = 0;
    for (UInt4 i=0; i<3; i++){
        for (UInt4 j=0; j<3; j++){
            gsl_matrix_set( Min, i, j, a[ind] );
            ind++;
        }
    }

    if (_CalcInverseMatrix( Min, Mout )){
        double a11 = gsl_matrix_get( Mout, 0, 0 );
        ret.push_back(a11);
        double a12 = gsl_matrix_get( Mout, 0, 1 );
        ret.push_back(a12);
        double a13 = gsl_matrix_get( Mout, 0, 2 );
        ret.push_back(a13);
        double a21 = gsl_matrix_get( Mout, 1, 0 );
        ret.push_back(a21);
        double a22 = gsl_matrix_get( Mout, 1, 1 );
        ret.push_back(a22);
        double a23 = gsl_matrix_get( Mout, 1, 2 );
        ret.push_back(a23);
        double a31 = gsl_matrix_get( Mout, 2, 0 );
        ret.push_back(a31);
        double a32 = gsl_matrix_get( Mout, 2, 1 );
        ret.push_back(a32);
        double a33 = gsl_matrix_get( Mout, 2, 2 );
        ret.push_back(a33);
        /*
        if (UtsusemiEnvGetDebugMode()){
            std::cout << a11 << "," << a12 << "," << a13 << std::endl;
            std::cout << a21 << "," << a22 << "," << a23 << std::endl;
            std::cout << a31 << "," << a32 << "," << a33 << std::endl;
        }
        */
    }else{
        //if (UtsusemiEnvGetDebugMode()) std::cout << "Det = 0" << std::endl;
    }
    gsl_matrix_free( Min );
    gsl_matrix_free( Mout );
    return ret;
}
//////////////////////////////////////////////////////////
std::vector<Double> TreatQhklWithUB::PutSliceMaxRange(){
    ElementContainerMatrix* ecm = Put();
    ElementContainer* ec = ecm->PutPointer(0)->PutPointer(0);
    if (ec->CheckKey( _Keys[0] )==0){
        UtsusemiError(_MessageTag+"PutSliceMaxRange >> Should be Execute has not done.");
        std::vector<Double> tmp;
        return tmp;
    }
    std::vector<double> q_mins(3,1.0e32);
    std::vector<double> q_maxs(3,-1.0e32);
    std::vector<UInt4> axIndex(3);
    axIndex[0]=_indSliceX;
    axIndex[1]=_indSliceY;
    axIndex[2]=_indSliceT;
    for (UInt4 i=0; i<(ecm->PutSize()); i++){
        for (UInt4 j=0; j<(ecm->PutPointer(i)->PutSize()); j++){
            ElementContainer* ec = ecm->PutPointer(i)->PutPointer(j);
            for (UInt4 k=0; k<3; k++){
                std::vector<double>* q = ec->PutP(_Keys[axIndex[k]]);
                std::vector<double>::iterator it_min = min_element( q->begin(), q->end() );
                std::vector<double>::iterator it_max = max_element( q->begin(), q->end() );
                if ((*it_min)<q_mins[k]) q_mins[k] = (*it_min);
                if ((*it_max)>q_maxs[k]) q_maxs[k] = (*it_max);
            }
        }
    }
    std::vector<double> ret;
    for (UInt4 i=0; i<3; i++){
        ret.push_back( q_mins[i] );
        ret.push_back( q_maxs[i] );
    }
    return ret;
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::SetSliceAxes( std::string ax1, std::string ax2, std::string ax3){
    transform(ax1.begin(), ax1.end(), ax1.begin(), ::toupper);
    transform(ax2.begin(), ax2.end(), ax2.begin(), ::toupper);
    transform(ax3.begin(), ax3.end(), ax3.begin(), ::toupper);
    std::vector<std::string> p;
    p.push_back(ax1);
    p.push_back(ax2);
    p.push_back(ax3);
    std::vector<bool> c(3,false);
    for (UInt4 i=0;i<3;i++){
        if (p[i]=="X"){
            _indSliceX=i;
            c[0]=true;
        }else if (p[i]=="Y"){
            _indSliceY=i;
            c[1]=true;
        }else if (p[i]=="T"){
            _indSliceT=i;
            c[2]=true;
        }else{
            UtsusemiError(_MessageTag+"SetSliceAxes >> arguments are invalid.");
            return false;
        }
    }
    if (c[0]&&c[1]&&c[2]){
    }else{
        UtsusemiError(_MessageTag+"SetSliceAxes >> arguments are invalid.");
        return false;
    }
    return true;
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::Slice( ElementContainerArray* eca, std::vector<Double> Xrange, std::vector<Double> Yrange, std::vector<Double> Trange){
    if ((Xrange.size()!=3)||(Yrange.size()!=3)||(Trange.size()<2)){
        UtsusemiError(_MessageTag+"Slice arguments of ranges are invalid ( size=3,3,2 ) ");
        return false;
    }

    std::vector<double> QxRangeInfo(3,0.0);
    std::vector<double> QyRangeInfo(3,0.0);
    _Qxbin = PutVectorAsBinCenterZero( Xrange[0], Xrange[1], Xrange[2] );
    _Qybin = PutVectorAsBinCenterZero( Yrange[0], Yrange[1], Yrange[2] );
    QxRangeInfo[0] = _Qxbin[0];
    QxRangeInfo[1] = _Qxbin.back();
    QxRangeInfo[2] = Xrange[2];
    QyRangeInfo[0] = _Qybin[0];
    QyRangeInfo[1] = _Qybin.back();
    QyRangeInfo[2] = Yrange[2];

    std::pair<double,double> QtRangeInfo;
    if (Trange[0]>Trange[1]){
        double tmp = Trange[0];
        Trange[0]=Trange[1];
        Trange[1] = tmp;
    }
    QtRangeInfo.first = Trange[0];
    QtRangeInfo.second = Trange[1];

    UInt4 size_Qxbin = _Qxbin.size();
    UInt4 size_Qybin = _Qybin.size();

    _IQ.clear();
    _Error.clear();
    _Count.clear();
    std::vector<double> tmp( (_Qybin.size()-1), 0.0 );
    _IQ.resize( (_Qxbin.size()-1), tmp );
    _Error.resize( (_Qxbin.size()-1), tmp );
    _Count.resize( (_Qxbin.size()-1), tmp );

    ElementContainerMatrix* ecm = Put();

    for (UInt4 i=0; i<_IQ.size(); i++){
        for (UInt4 j=0; j<_IQ[i].size(); j++){
            _IQ[i][j] = 0.0;
            _Error[i][j] = 0.0;
            _Count[i][j] = 0.0;
        }
    }

    for (UInt4 i=0; i<ecm->PutSize(); i++){
        if (ecm->PutPointer(i)->PutHeaderPointer()->PutInt4("MASKED")==1) continue;
        for (UInt4 j=0; j<ecm->PutPointer(i)->PutSize(); j++){
            ElementContainer* ec = ecm->PutPointer(i)->PutPointer(j);
            if (ec->PutHeaderPointer()->PutInt4("MASKED")==1) continue;
            std::vector<double> iq_int = ec->PutY();
            std::vector<double> iq_err = ec->PutE();

            std::vector<double> qxh = ec->Put(_Keys[_indSliceX]);
            std::vector<double> qyh = ec->Put(_Keys[_indSliceY]);
            std::vector<double> qth = ec->Put(_Keys[_indSliceT]);
            std::vector<double> lmh = ec->Put("Lamb");

            for (UInt4 k=0; k<iq_int.size(); k++){
                double qx = qxh[k];
                double qy = qyh[k];
                double qt = qth[k];
                double lmd = lmh[k];//(lmh[k+1]+lmh[k])/2.0;
                if ( (QtRangeInfo.first<=qt)&&(qt<=QtRangeInfo.second) ){
                    if ((QxRangeInfo[0]<=qx)&&(qx<=QxRangeInfo[1])){
                        if ((QyRangeInfo[0]<=qy)&&(qy<=QyRangeInfo[1])){
                            UInt4 indx = floor( (qx - QxRangeInfo[0])/ QxRangeInfo[2] );
                            UInt4 indy = floor( (qy - QyRangeInfo[0])/ QyRangeInfo[2] );
                            if ((iq_err[k]<0.0)&&(indx>=size_Qxbin)&&(indy>=size_Qybin)){
                            }else{
                                _IQ[indx][indy] += iq_int[k];
                                _Error[indx][indy] += iq_err[k]*iq_err[k];
                                _Count[indx][indy] += 1.0;
                            }
                        }else{
                            //std::cout << "QzRange.first, QzRange.second, qz=" << _QzRange.first << "," << _QzRange.second << "," << qz[k] << std::endl;
                        }
                    }
                }
            }

        }
    }
    for (UInt4 i=0; i<_IQ.size(); i++){
        for (UInt4 j=0; j<_IQ[i].size(); j++){
            if (_Count[i][j]!=0.0){
                _IQ[i][j] = _IQ[i][j]/_Count[i][j];
                _Error[i][j] = sqrt( _Error[i][j] )/_Count[i][j];
            }
        }
    }

    eca->Allocate( _Qxbin.size()-1 );
    for (UInt4 i=0; i<_Qxbin.size()-1; i++){
        ElementContainer* ec = new ElementContainer();
        std::vector<Double> qy_int(_Qybin.size()-1,0.0);
        std::vector<Double> qy_err(_Qybin.size()-1,0.0);
        for (UInt4 j=0; j<_Qybin.size()-1; j++){
            qy_int[j] = _IQ[i][j];
            qy_err[j] = _Error[i][j];
        }
        ec->Add( _Keys[_indSliceY], _Qybin, _Units[_indSliceY] );
        ec->Add( UTSUSEMI_KEY_INTENSITY, qy_int, UTSUSEMI_KEY_COUNTS_UNIT );
        ec->Add( UTSUSEMI_KEY_ERROR, qy_err, UTSUSEMI_KEY_COUNTS_UNIT );
        ec->SetKeys( _Keys[_indSliceY], UTSUSEMI_KEY_INTENSITY, UTSUSEMI_KEY_ERROR );

        std::vector<Double> x_range(2,0.0);
        x_range[0] = _Qxbin[i];
        x_range[1] = _Qxbin[i+1];
        ec->AddToHeader(UTSUSEMI_KEY_HEAD_XRANGE, x_range );
        ec->AddToHeader(_Keys[_indSliceX], (x_range[0]+x_range[1])/2.0 );
        ec->AddToHeader("_UNIT_"+_Keys[_indSliceX], _Units[_indSliceX] ); // For uGao.M2PlotPlus

        eca->Set( i, ec );
    }
    std::vector<std::string> orderKeys(3, ""), orderLabels(3, "");
    orderKeys[0] = _Keys[_indSliceX];
    orderKeys[1] = _Keys[_indSliceY];
    orderKeys[2] = _Keys[_indSliceT];
    orderLabels[0] = _Labels[_indSliceX];
    orderLabels[1] = _Labels[_indSliceY];
    orderLabels[2] = _Labels[_indSliceT];

    eca->AddToHeader( _Keys[_indSliceX], _Qxbin );
    eca->AddToHeader( SAS_TREATQHK_KEYS, orderKeys );
    eca->AddToHeader( SAS_TREATQHK_LABELS, orderLabels );
    eca->AddToHeader( UTSUSEMI_KEY_HEAD_ISHISTOGRAM, 0 );

    return true;
}
//////////////////////////////////////////////////////////
bool TreatQhklWithUB::Slice( ElementContainerArray* eca, PyObject* ax1range, PyObject* ax2range, PyObject* ax3range){
    if ( (! PyList_Check(ax1range)) || (! PyList_Check(ax2range)) || (! PyList_Check(ax3range)) ){
        UtsusemiError("SAS.TreatQhklWithUB::Slice >>> given ranges must be list");
        return false;
    }
    return Slice( eca, _CTP->ListToDoubleVector(ax1range), _CTP->ListToDoubleVector(ax2range), _CTP->ListToDoubleVector(ax3range) );
}
const std::string TreatQhklWithUB::SAS_TREATQHK_KEYS = "SAS_TREATQHK_KEYS";
const std::string TreatQhklWithUB::SAS_TREATQHK_LABELS = "SAS_TREATQHK_LABELS";
