#include "UtsusemiD4Matrix.hh"

//////////////////////////////////////////////////////////////////////
UtsusemiD4Matrix::
UtsusemiD4Matrix(){
    _Initialize();
}

//////////////////////////////////////////////////////////////////////
UtsusemiD4Matrix::
UtsusemiD4Matrix( bool is_debug_mode){
    _Initialize();
    isDebugMode = is_debug_mode;
}

//////////////////////////////////////////////////////////////////////
UtsusemiD4Matrix::
~UtsusemiD4Matrix(){
    _ClearVirtualMat(); //[inamura 160622]
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
_Initialize(){
    MessageTag = "UtsusemiD4Matrix >> ";
    MAX_SIZE_OF_ONE_BLOCK = 1000.0;
    //MAX_SIZE_OF_ONE_BLOCK = 0.3;
    isDebugMode = false;
    //isDebugMode = true;
    isFilesOpened = false;
    d4mat_param_file = "None";
    _isGoodResult = true;
    _isDirectGeometry = true;
    _Ef_fixed = -1.0;

    ax_titles.clear();
    ax_titles.push_back("Q1");
    ax_titles.push_back("Q2");
    ax_titles.push_back("Q3");
    ax_titles.push_back(UTSUSEMI_KEY_HW);

    ax_titles.clear();
    ax_titles.push_back(UTSUSEMI_KEY_MOMENTTRANSFER_UNIT);
    ax_titles.push_back(UTSUSEMI_KEY_MOMENTTRANSFER_UNIT);
    ax_titles.push_back(UTSUSEMI_KEY_MOMENTTRANSFER_UNIT);
    ax_titles.push_back(UTSUSEMI_KEY_ENERGY);

    _AxisDefIndex.resize(4,0);

    _ClearAllParams();

    // For VirtualD4Mat
    _VirtualD4Mat=NULL;
    _isVirtual=false;
    _VirtualAngleInfo.clear();
    _hwInfoForVirtualMatrix.clear();
}

//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
SetEf( double _ef ){
    if (_ef<=0.0) return false;
    _Ef_fixed = _ef;
    _isDirectGeometry = false;
    return true;
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SetMaxSizeOfBlock( Double _size ){
    if (_size<0.0) return;
    if (_size>2000.0) _size = 2000.0;
    MAX_SIZE_OF_ONE_BLOCK = _size;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
AllocateNewMat( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> titles, std::vector<std::string> units, std::string data_dir, std::string paramfile ){
    _isGoodResult = false;
    _ClearAllParams();
    _ClearVirtualMat();

    range_list.push_back( a1range );
    range_list.push_back( a2range );
    range_list.push_back( a3range );
    range_list.push_back( a4range );

    for (UInt4 i=0;i<4;i++){
        if ( (range_list[i].size()<2) || (range_list[i].size()>3) ){
            UtsusemiError( MessageTag+"AllocateNewMat > Invalid range, param="+stools->UInt4ToString(i) );
            return;
        }
    }
    if (titles.size()!=4){
        UtsusemiError( MessageTag+"AllocateNewMat > Invalid size of titles (must be 4)" );
        return;
    }
    for (UInt4 i=0;i<4;i++){
        ax_titles.push_back( titles[i] );
    }
    if (units.size()!=4){
        UtsusemiError( MessageTag+"AllocateNewMat > Invalid size of units (must be 4)" );
        return;
    }
    for (UInt4 i=0;i<4;i++){
        ax_units.push_back( units[i] );
    }


    for (UInt4 i=0;i<4;i++){
        if (range_list[i].size()==2){
            NumBin.push_back(1);
            range_list[i].push_back( range_list[i][1]-range_list[i][0] );
        }else{
            std::vector<Double> ret = CalcRangeAsBinCenterZero( range_list[i][0], range_list[i][1], range_list[i][2] );
            range_list[i][0] = ret[0];
            range_list[i][1] = ret[1];
            NumBin.push_back( UInt4( ret[2] ) );
            //NumBin.push_back( UInt4( round((range_list[i][1]-range_list[i][0])/range_list[i][2]) ) );
        }
    }
    UtsusemiMessage( MessageTag+"AllocateNewMat > NumBin="+stools->UInt4ToString(NumBin[0])+","
                     +stools->UInt4ToString(NumBin[1])+","+stools->UInt4ToString(NumBin[2])+","+stools->UInt4ToString(NumBin[3]) );

    size_of_Ax.push_back(NumBin[1]*NumBin[2]*sizeof(float)*3);
    size_of_Ax.push_back(NumBin[2]*sizeof(float)*3);
    size_of_Ax.push_back(sizeof(float)*3);
    size_of_Ax.push_back(NumBin[0]*NumBin[1]*NumBin[2]*sizeof(float)*3);
    UtsusemiMessage( MessageTag+"AllocateNewMat > size_of_Ax="+stools->UInt4ToString(size_of_Ax[0])+","+
                     stools->UInt4ToString(size_of_Ax[1])+","+stools->UInt4ToString(size_of_Ax[2])+","+stools->UInt4ToString(size_of_Ax[3]) );

    int num_of_blocks = 0;



    float one_plane_size = (float)(size_of_Ax[3]/1024./1024.);

    if ( one_plane_size> MAX_SIZE_OF_ONE_BLOCK ){
        num_of_blocks = 1;
    }else{
        num_of_blocks = int( MAX_SIZE_OF_ONE_BLOCK/one_plane_size );
    }

    if (isDebugMode){
        std::cout << MessageTag << "one_plane_size=" << one_plane_size << "MB" << std::endl;
        std::cout << MessageTag << "MAX_SIZE_ONE_BLOCK=" << MAX_SIZE_OF_ONE_BLOCK << std::endl;
        std::cout << MessageTag << "MAX_SIZE_OF_ONE_BLOCK/one_plane_size = ";
        std::cout << MessageTag << (MAX_SIZE_OF_ONE_BLOCK/one_plane_size) << std::endl;
        std::cout << MessageTag << "num_of_blocks=" << num_of_blocks << std::endl;
    }

    std::string data_name_base( paramfile );

    std::string::size_type ind = paramfile.find_last_of(".xml");
    if (ind == std::string::npos) {
        d4mat_param_file = paramfile+".xml";
    }else{
        d4mat_param_file = paramfile;
        data_name_base.erase( ind-3 );
    }
    if (data_dir.substr( data_dir.size()-1 )!=std::string("/")){
        d4mat_data_dir = data_dir+"/";
    }else{
        d4mat_data_dir = std::string( data_dir );
    }

    for (UInt4 i=0;i<NumBin[3];i+=num_of_blocks){
        index_of_blocks.push_back(i);
        char ff[10];
        std::snprintf( ff, sizeof(ff), "%05d", i );
        std::string fst = ff;
        std::string fname = data_name_base+"_"+fst+".bin";
        if (isDebugMode) std::cout << MessageTag << "fname=" << fname<< std::endl;
        name_of_blocks.push_back(fname);
    }
    index_of_blocks.push_back(NumBin[3]);

    Int4 ret = SaveParamXml( d4mat_data_dir, d4mat_param_file );
    if (ret==-1){
        UtsusemiError( MessageTag+"AllocateNewMat > Fail to make new param.xml.");
        return;
    }

    FILE* fp;
    float data[3];
    UtsusemiMessage( MessageTag+"Size of data="+stools->UInt4ToString(sizeof(data)));

    for (UInt4 i=0;i<(index_of_blocks.size()-1);i++){
        std::string datapath = d4mat_data_dir + name_of_blocks[i];
        if ((fp=fopen(datapath.c_str(),"wb"))==NULL){
            UtsusemiError( MessageTag+"AllocateNewMat > Cannot open file="+datapath);
            return;
        }

        for (UInt4 i4=index_of_blocks[i];i4<index_of_blocks[i+1];i4++){
            UtsusemiMessage( MessageTag+"AllocateNewMat > step ="+stools->UInt4ToString(i4)+"/"+stools->UInt4ToString(NumBin[3]));
            for (UInt4 i1=0;i1<NumBin[0];i1++){
                for (UInt4 i2=0;i2<NumBin[1];i2++){
                    for (UInt4 i3=0;i3<NumBin[2];i3++){
                        data[0] = UTSUSEMIMASKVALUE32;
                        data[1] = float(0.0);
                        data[2] = float(0.0);
                        if ((int)std::fwrite( data, sizeof(data), 1, fp ) !=1){
                            //usleep(50000);
                            std::this_thread::sleep_for(std::chrono::milliseconds(50));
                            if ((int)std::fwrite( data, sizeof(data), 1, fp ) !=1){
                                UtsusemiError( MessageTag+"AllocateNewMat > Failed to write");
                                return;
                            }
                        }
                    }
                }
            }
        }
        fclose( fp );
    }
    _isGoodResult = true;
    return;
}


//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
AllocateVirtualMat( std::vector<Double> latticeConst, std::vector<Double> Uvec, std::vector<Double> Vvec, std::vector<Double> rotateSteps,
                    std::vector<Double> viewAxes, std::vector<Double> hwInfo, std::vector<Double> phiSteps,
                    std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> titles, std::vector<std::string> units ){
    if (_isDirectGeometry) UtsusemiMessage( MessageTag+"AllocateVirtualMat > Direct Geometry ");
    else  UtsusemiMessage( MessageTag+"AllocateVirtualMat > Inverted Geometry ");
    _isGoodResult = false;
    _ClearAllParams();

    range_list.push_back( a1range );
    range_list.push_back( a2range );
    range_list.push_back( a3range );
    range_list.push_back( a4range );

    for (UInt4 i=0;i<4;i++){
        if ( (range_list[i].size()<2) || (range_list[i].size()>3) ){
            UtsusemiError( MessageTag+"AllocateVirtualMat > Invalid range, param="+stools->UInt4ToString(i));
            return;
        }
    }
    if (titles.size()!=4){
        UtsusemiError( MessageTag+"AllocateVirtualMat > Invalid size of titles (must be 4)");
        return;
    }

    for (UInt4 i=0;i<4;i++){
        ax_titles.push_back( titles[i] );
    }
    if (units.size()!=4){
        UtsusemiError( MessageTag+"AllocateVirtualMat > Invalid size of units (must be 4)");
        return;
    }
    for (UInt4 i=0;i<4;i++){
        ax_units.push_back( units[i] );
    }

    for (UInt4 i=0;i<4;i++){
        if (range_list[i].size()==2){
            NumBin.push_back(1);
            range_list[i].push_back( range_list[i][1]-range_list[i][0] );
        }else{
            std::vector<Double> ret = CalcRangeAsBinCenterZero( range_list[i][0], range_list[i][1], range_list[i][2] );
            range_list[i][0] = ret[0];
            range_list[i][1] = ret[1];
            NumBin.push_back( UInt4( ret[2] ) );
        }
    }

    size_of_Ax.push_back(NumBin[1]*NumBin[2]);
    size_of_Ax.push_back(NumBin[2]);
    size_of_Ax.push_back(1);
    size_of_Ax.push_back(NumBin[0]*NumBin[1]*NumBin[2]);

    if (isDebugMode){
        std::cout << MessageTag << "NumBin = " << NumBin[0] << "," << NumBin[1] << "," << NumBin[2] << "," << NumBin[3] << std::endl;
        std::cout << MessageTag << "size_of_Ax=" << size_of_Ax[0] <<","<< size_of_Ax[1] << ","<< size_of_Ax[2] <<","<< size_of_Ax[3] << std::endl;
    }

    _ClearVirtualMat();
    if (_VirtualD4Mat==NULL) _VirtualD4Mat = new std::vector< std::vector<float>* >(NumBin[3], NULL);

    UtsusemiUnitConverter* UCC = new UtsusemiUnitConverter();

    for (UInt4 i=0; i<NumBin[3]; i++) _VirtualD4Mat->at(i)=new std::vector<float>( size_of_Ax[3],0.0 );

    Double Ei = hwInfo[0];
    Double delta_hw = hwInfo[1];

    std::vector<Double> hw_range= CalcRangeAsBinCenterZero( hwInfo[2], hwInfo[3], delta_hw );
    std::vector<Double> hw_list( (UInt4)(hw_range[2]),0.0 );

    for (UInt4 i=0; i<(UInt4)(hw_range[2]); i++)
        hw_list[i] = hw_range[0] + delta_hw*(double(i)+0.5);

    if (isDebugMode){
        std::cout << "-----------------------" << std::endl;
        std::cout << "Ei="<<Ei<<", dhw="<<delta_hw<<std::endl;
        for (UInt4 i=0; i<hw_list.size(); i++)
            std::cout << hw_list[i]<<",";
        std::cout << std::endl;

        for (UInt4 i=0;i<latticeConst.size();i++) std::cout << latticeConst[i] << ",";
        std::cout << std::endl;
        for (UInt4 i=0;i<Uvec.size();i++) std::cout << Uvec[i] << ",";
        std::cout << std::endl;
        for (UInt4 i=0;i<Vvec.size();i++) std::cout << Vvec[i] << ",";
        std::cout << std::endl;
        for (UInt4 i=0;i<viewAxes.size();i++) std::cout << viewAxes[i] << ",";
        std::cout << std::endl;
    }

#ifdef MULTH
    omp_set_num_threads( UtsusemiGetNumOfMulTh() );
#endif

    Double origin_rotate_Y = 0.0;
    for (UInt4 i=0;i<rotateSteps.size(); i+=2)
        if (rotateSteps[i]==ROTATE_AXIS_Y)
            origin_rotate_Y = rotateSteps[i+1];
    for (UInt4 i_phi=0; i_phi<phiSteps.size(); i_phi++){
        bool isSetPhi=false;
        for (UInt4 i=0;i<rotateSteps.size(); i+=2){
            if (rotateSteps[i]==ROTATE_AXIS_Y){
                rotateSteps[i+1]=origin_rotate_Y+phiSteps[i_phi];
                isSetPhi=true;
            }
        }
        if (isSetPhi){
        }else{
            rotateSteps.push_back(1.0);
            rotateSteps.push_back(phiSteps[i_phi]);
        }
        //std::cout << "i_phi="<<i_phi<<", phi="<<phiSteps[i_phi]<<std::endl;
        UtsusemiSqeCalc2* VCS = new UtsusemiSqeCalc2();
        std::vector<Double> A = VCS->MakeProjectionMatrix( latticeConst, Uvec, Vvec, rotateSteps, viewAxes );
        delete VCS;

        Double ki = 0.0;
        if (_isDirectGeometry){
            ki = sqrt( UCC->EtoK2( Ei ) );
        }
        // Efs are required!!
        // isDirectGeometry is required!!
        std::vector<Double> Efs( _VirtualAngleInfo.size(), _Ef_fixed );


#pragma omp parallel for
#if (_OPENMP >= 200805)  // OpenMP 3.0 and later
        for (UInt4 i=0;i<_VirtualAngleInfo.size();i++){
#else
        for (Int4 i=0;i<_VirtualAngleInfo.size();i++){
#endif
            Double PA = _VirtualAngleInfo[i]->first;  // Polar angle
            Double AA = _VirtualAngleInfo[i]->second; // Azimuth angle
            Double px = sin(PA)*cos(AA);
            Double py = sin(PA)*sin(AA);
            Double pz = cos(PA);
            Double kf=0.0;
            Double Ef = 0.0;
            if (_isDirectGeometry){
            }else{
                Ef = Efs[i];
                kf = sqrt( UCC->EtoK2( Ef ) );
            }

            for (UInt4 k=0;k<hw_list.size();k++){
                Double hw = hw_list[k];

                if (_isDirectGeometry){
                    kf = sqrt( UCC->EtoK2( Ei-hw ) );
                }else{
                    ki = sqrt( UCC->EtoK2( Ef+hw ) );
                }

                Double qx = -kf*px;
                Double qy = -kf*py;
                Double qz = ki-kf*pz;

                /*
                Double Vx = qz*A[0] + qx*A[1] + qy*A[2] + hw*A[3];
                Double Vy = qz*A[4] + qx*A[5] + qy*A[6] + hw*A[7];
                Double Vz = qz*A[8] + qx*A[9] + qy*A[10] + hw*A[11];
                Double Vw = qz*A[12] + qx*A[13] + qy*A[14] + hw*A[15];
                */
                Double Vx = qx*A[0] + qy*A[1] + qz*A[2] + hw*A[3];
                Double Vy = qx*A[4] + qy*A[5] + qz*A[6] + hw*A[7];
                Double Vz = qx*A[8] + qy*A[9] + qz*A[10] + hw*A[11];
                Double Vw = qx*A[12] + qy*A[13] + qz*A[14] + hw*A[15];


                UInt4 i_Vw = (UInt4)( float( (Vw - range_list[3][0])/range_list[3][2] ) );
                if (i_Vw>=NumBin[3]) {
                    //std::cout << "i_Vw is over, Vw="<<Vw<<", i_Vw="<<i_Vw<<std::endl;
                    continue;
                }
                UInt8 ind;
                if (_CalcIndexVirtual( Vx, Vy, Vz, &ind )==-1) continue;
                if (ind>=(_VirtualD4Mat->at(i_Vw)->size())){
                    //std::cout << "ind is over, ind="<<ind<<",size="<<_VirtualD4Mat->at(i_Vw)->size()<<std::endl;
                    //std::cout << "Vx="<<Vx<<", Vy="<<Vy<<",Vz="<<Vz<<",Vw="<<Vw<<std::endl;
                    //std::cout << "hw="<<hw<<",phi="<<phiSteps[i_phi]<<std::endl;
                }else{
                    _VirtualD4Mat->at(i_Vw)->at(ind) ++;
                }
            }
        }
    }
    delete UCC;
    _isGoodResult = true;
    _isVirtual=true;
    return;
}
//////////////////////////////////////////////////////////////////////
std::vector<Double> UtsusemiD4Matrix::
EstimateRangeOfVirtualMat( std::vector<Double> latticeConst, std::vector<Double> Uvec, std::vector<Double> Vvec, std::vector<Double> rotateSteps,
                          std::vector<Double> viewAxes, std::vector<Double> hwInfo, std::vector<Double> phiSteps ){
    _isGoodResult = false;

    UtsusemiUnitConverter* UCC = new UtsusemiUnitConverter();
    Double Ei = hwInfo[0];
    Double delta_hw = hwInfo[1];

    std::vector<Double> hw_range= CalcRangeAsBinCenterZero( hwInfo[2], hwInfo[3], delta_hw );
    std::vector<Double> hw_list( (UInt4)(hw_range[2]),0.0 );

    for (UInt4 i=0; i<(UInt4)(hw_range[2]); i++)
        hw_list[i] = hw_range[0] + delta_hw*(double(i)+0.5);


    UInt4 NumOfMulTh = UtsusemiGetNumOfMulTh();
#ifdef MULTH
    omp_set_num_threads( NumOfMulTh );
#endif

    std::vector< std::vector<Double>* > _Ranges( NumOfMulTh );
    for (UInt4 i=0; i<NumOfMulTh; i++){
        _Ranges[i] = new std::vector<Double>( 8 );
        _Ranges[i]->at(0) = 1.0e32;  // Vx min
        _Ranges[i]->at(1) = -1.0e32; // Vx max
        _Ranges[i]->at(2) = 1.0e32;  // Vx min
        _Ranges[i]->at(3) = -1.0e32; // Vx max
        _Ranges[i]->at(4) = 1.0e32;  // Vx min
        _Ranges[i]->at(5) = -1.0e32; // Vx max
        _Ranges[i]->at(6) = 1.0e32;  // Vx min
        _Ranges[i]->at(7) = -1.0e32; // Vx max
    }

    Double origin_rotate_Y = 0.0;
    for (UInt4 i=0;i<rotateSteps.size(); i+=2)
        if (rotateSteps[i]==ROTATE_AXIS_Y)
            origin_rotate_Y = rotateSteps[i+1];
    for (UInt4 i_phi=0; i_phi<phiSteps.size(); i_phi++){
        bool isSetPhi=false;
        for (UInt4 i=0;i<rotateSteps.size(); i+=2){
            if (rotateSteps[i]==ROTATE_AXIS_Y){
                rotateSteps[i+1]=origin_rotate_Y+phiSteps[i_phi];
                isSetPhi=true;
            }
        }
        if (isSetPhi){
        }else{
            rotateSteps.push_back(1.0);
            rotateSteps.push_back(phiSteps[i_phi]);
        }
        //std::cout << "i_phi="<<i_phi<<", phi="<<phiSteps[i_phi]<<std::endl;
        UtsusemiSqeCalc2* VCS = new UtsusemiSqeCalc2();
        std::vector<Double> A = VCS->MakeProjectionMatrix( latticeConst, Uvec, Vvec, rotateSteps, viewAxes );
        delete VCS;

        Double ki = 0.0;
        if (_isDirectGeometry){
            ki = sqrt( UCC->EtoK2( Ei ) );
        }
        // Efs are required!!
        // _isDirectGeometry is required!!
        std::vector<Double> Efs( _VirtualAngleInfo.size(), _Ef_fixed );


#pragma omp parallel for
#if (_OPENMP >= 200805)  // OpenMP 3.0 and later
        for (UInt4 i=0;i<_VirtualAngleInfo.size();i++){
#else
        for (Int4 i=0;i<_VirtualAngleInfo.size();i++){
#endif
            Double PA = _VirtualAngleInfo[i]->first;  // Polar angle
            Double AA = _VirtualAngleInfo[i]->second; // Azimuth angle
            Double px = sin(PA)*cos(AA);
            Double py = sin(PA)*sin(AA);
            Double pz = cos(PA);
            Double kf=0.0;
            Double Ef = 0.0;
            if (_isDirectGeometry){
            }else{
                Ef = Efs[i];
                kf = sqrt( UCC->EtoK2( Ef ) );
            }

            UInt4 ThNum = omp_get_thread_num();

            for (UInt4 k=0;k<hw_list.size();k++){
                Double hw = hw_list[k];

                if (_isDirectGeometry){
                    kf = sqrt( UCC->EtoK2( Ei-hw ) );
                }else{
                    ki = sqrt( UCC->EtoK2( Ef+hw ) );
                }

                Double qx = -kf*px;
                Double qy = -kf*py;
                Double qz = ki-kf*pz;

                /*
                Double Vx = qz*A[0] + qx*A[1] + qy*A[2] + hw*A[3];
                Double Vy = qz*A[4] + qx*A[5] + qy*A[6] + hw*A[7];
                Double Vz = qz*A[8] + qx*A[9] + qy*A[10] + hw*A[11];
                Double Vw = qz*A[12] + qx*A[13] + qy*A[14] + hw*A[15];
                */
                Double Vx = qx*A[0] + qy*A[1] + qz*A[2] + hw*A[3];
                Double Vy = qx*A[4] + qy*A[5] + qz*A[6] + hw*A[7];
                Double Vz = qx*A[8] + qy*A[9] + qz*A[10] + hw*A[11];
                Double Vw = qx*A[12] + qy*A[13] + qz*A[14] + hw*A[15];

                if (Vx<(_Ranges[ThNum]->at(0))) _Ranges[ThNum]->at(0) = Vx;
                if (Vx>(_Ranges[ThNum]->at(1))) _Ranges[ThNum]->at(1) = Vx;
                if (Vy<(_Ranges[ThNum]->at(2))) _Ranges[ThNum]->at(2) = Vy;
                if (Vy>(_Ranges[ThNum]->at(3))) _Ranges[ThNum]->at(3) = Vy;
                if (Vz<(_Ranges[ThNum]->at(4))) _Ranges[ThNum]->at(4) = Vz;
                if (Vz>(_Ranges[ThNum]->at(5))) _Ranges[ThNum]->at(5) = Vz;
                if (Vw<(_Ranges[ThNum]->at(6))) _Ranges[ThNum]->at(6) = Vw;
                if (Vw>(_Ranges[ThNum]->at(7))) _Ranges[ThNum]->at(7) = Vw;
            }
        }
    }
    delete UCC;

    std::vector<Double> ret(8,0.0);
    for (UInt4 i=0; i<8; i++)
        ret[i] = _Ranges[0]->at(i);
    for (UInt4 i=1; i<NumOfMulTh; i++){
        if ((_Ranges[i]->at(0))<ret[0]) ret[0] = _Ranges[i]->at(0);
        if ((_Ranges[i]->at(1))>ret[1]) ret[1] = _Ranges[i]->at(1);
        if ((_Ranges[i]->at(2))<ret[2]) ret[2] = _Ranges[i]->at(2);
        if ((_Ranges[i]->at(3))>ret[3]) ret[3] = _Ranges[i]->at(3);
        if ((_Ranges[i]->at(4))<ret[4]) ret[4] = _Ranges[i]->at(4);
        if ((_Ranges[i]->at(5))>ret[5]) ret[5] = _Ranges[i]->at(5);
        if ((_Ranges[i]->at(6))<ret[6]) ret[6] = _Ranges[i]->at(6);
        if ((_Ranges[i]->at(7))>ret[7]) ret[7] = _Ranges[i]->at(7);
    }

    for (UInt4 i=0; i<NumOfMulTh; i++)
        delete _Ranges[i];

    _isGoodResult = true;
    return ret;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
_CalcVirtualAngleInfo( std::string wfile, std::string dfile ){
    _isGoodResult = false;
    UtsusemiNeunetEventDecoderBase *ED = new UtsusemiNeunetEventDecoderBase();
    if (ED->SetParametersFromFiles( wfile, dfile)!=0){
        std::string msg = MessageTag+"_CalcVirtualAngleInfo : param files are invalid."+wfile+","+dfile;
        UtsusemiError( msg );
        delete ED;
        return;
    }

    ED->CalcPixelPosition();
    UInt4 psize = (UInt4)(ED->_pixelPositionVect.size());
    if (psize<=0){
        std::string msg = MessageTag+"_CalcVirtualAngleInfo : param files are invalid."+wfile+","+dfile;
        UtsusemiError( msg );
        delete ED;
        return;
    }

    for (UInt4 i=0; i<_VirtualAngleInfo.size(); i++)
        if (_VirtualAngleInfo[i]!=NULL) delete _VirtualAngleInfo[i];
    _VirtualAngleInfo.clear();
    _VirtualAngleInfo.resize( psize, NULL );
    for (UInt4 i=0; i<psize; i++){
        std::vector<Double>* p = ED->_pixelPositionVect[i];
        if (p!=NULL){
            Double L2 = sqrt( (p->at(0))*(p->at(0)) + (p->at(1))*(p->at(1)) + (p->at(2))*(p->at(2)) );
            if (_VirtualAngleInfo[i]==NULL) _VirtualAngleInfo[i]=new std::pair<Double,Double>;
            //_VirtualAngleInfo[i]->first = 180.0/M_PI*acos( (*p)[2]/L2 );
            //_VirtualAngleInfo[i]->second= 180.0/M_PI*acos( (*p)[0]/sqrt( (*p)[0]*(*p)[0]+(*p)[1]*(*p)[1] ) )*(*p)[1]/sqrt( (*p)[1]*(*p)[1] );
            _VirtualAngleInfo[i]->first = acos( (p->at(2))/L2 );
            _VirtualAngleInfo[i]->second= acos( (p->at(0))/sqrt( (p->at(0))*(p->at(0))+(p->at(1))*(p->at(1)) ) )*(p->at(1))/sqrt( (p->at(1))*(p->at(1)) );
        }
    }

    delete ED;
    return;
}
 //////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
_CalcVirtualAngleInfo( ElementContainerMatrix* _ecm ){
    _isGoodResult = false;
    for (UInt4 i=0; i<_VirtualAngleInfo.size(); i++)
        if (_VirtualAngleInfo[i]!=NULL) delete _VirtualAngleInfo[i];
    _VirtualAngleInfo.clear();
    for (UInt4 i=0; i<(_ecm->PutSize()); i++){
        ElementContainerArray* eca = _ecm->PutPointer(i);
        if ((eca->PutHeaderPointer()->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)&&
            (eca->PutHeaderPointer()->PutInt4(UTSUSEMI_KEY_HEAD_MASKED)==1)) continue;
        for (UInt4 j=0; j<(eca->PutSize()); j++){
            HeaderBase* hh = eca->PutPointer(j)->PutHeaderPointer();
            if ((hh->CheckKey(UTSUSEMI_KEY_HEAD_MASKED)==1)&&(hh->PutInt4(UTSUSEMI_KEY_HEAD_MASKED)==1)) continue;
            std::pair<Double,Double>* p = new std::pair<Double,Double>;
            p->first = hh->PutDouble(UTSUSEMI_KEY_HEAD_POLARANGLE);
            p->second= hh->PutDouble(UTSUSEMI_KEY_HEAD_AZIMANGLE);
           _VirtualAngleInfo.push_back(p);
        }
    }
    return;
}
//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
_CalcIndexVirtual( Double a1, Double a2, Double a3, UInt8 *ind ){

    if (a1 < range_list[0][0]) return -1;
    if (a1 > range_list[0][1]) return -1;
    if (a2 < range_list[1][0]) return -1;
    if (a2 > range_list[1][1]) return -1;
    if (a3 < range_list[2][0]) return -1;
    if (a3 > range_list[2][1]) return -1;

    UInt4 i1 = (UInt4)( float( (a1 - range_list[0][0])/range_list[0][2] ) );
    UInt4 i2 = (UInt4)( float( (a2 - range_list[1][0])/range_list[1][2] ) );
    UInt4 i3 = (UInt4)( float( (a3 - range_list[2][0])/range_list[2][2] ) );

    *ind = (UInt8)(size_of_Ax[0]*i1 + size_of_Ax[1]*i2 + size_of_Ax[2]*i3);
    return 0;
}
//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
_OpenFiles(){
    if (name_of_blocks.size()==0) return -1;
    if (isFilesOpened) CloseMat();

    fs_list.clear();
    for (UInt4 i=0;i<name_of_blocks.size();i++){
        FILE* fp;
        std::string datafile = d4mat_data_dir + name_of_blocks[i];
        if ((fp=fopen(datafile.c_str(),"r+b"))==NULL){
            UtsusemiError(MessageTag+"_OpenFiles > Cannot open file="+datafile );
            return -1;
        }
        UtsusemiMessage(MessageTag+"_OpenFiles > File Block: "+datafile+" is opened " );
        fs_list.push_back(fp);
    }
    isFilesOpened=true;
    return 0;
}

//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
OpenMat( std::string datapath, std::string paramfile ){
    _isGoodResult = false;

    Int4 r1 = _ReadParamXml( datapath, paramfile );

    if (r1==0){
        Int4 r2 = _OpenFiles();
        if (r2==0){
            _isGoodResult = true;
            _ClearVirtualMat(); //[inamura 160621]
        }
    }
    return _isGoodResult;
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
CloseMat(){
    if (isFilesOpened){
        for (UInt4 i=0;i<fs_list.size();i++){
            fclose( fs_list[i] );
        }
    }

    isFilesOpened=false;
    UtsusemiMessage(MessageTag+"CloseMat > Closed all files.");
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
_ClearAllParams(){

    if (isFilesOpened) CloseMat();
    fs_list.clear();
    range_list.clear();
    NumBin.clear();
    name_of_blocks.clear();
    index_of_blocks.clear();
    file_components.clear();
    size_of_Ax.clear();
    ax_titles.clear();

}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
_ClearVirtualMat(){
    if (_VirtualD4Mat!=NULL){
        for(UInt4 i=0; i<(_VirtualD4Mat->size()); i++) delete _VirtualD4Mat->at(i);
        delete _VirtualD4Mat;
        _VirtualD4Mat=NULL;
    }
    _isVirtual=false;
}
//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
_AddToMatFromText( std::string filename, bool isAdd ){
    if (!isFilesOpened) _OpenFiles();

    // ver03
    FILE* fp;
    if ((fp=fopen(filename.c_str(),"r"))==NULL){
        UtsusemiError(MessageTag+"_AddToMatFromText > Cannot open file "+filename);
        return -1;
    }
    if (isAdd){
        file_components.push_back( filename );
    }else{
        std::vector<std::string> temp;
        temp.clear();
        for (UInt4 i=0;i<file_components.size();i++) temp.push_back(file_components[i]);
        file_components.clear();
        for (UInt4 i=0;i<temp.size();i++){
            if (filename!=temp[i]) file_components.push_back(temp[i]);
        }
    }

    // ver04
    int ret = 0;
    float a1,a2,a3,a4,Intens,Error;
    std::vector<float> a1v,a2v,a3v,a4v,iiv,eev;
    a1v.clear();
    a2v.clear();
    a3v.clear();
    a4v.clear();
    iiv.clear();
    eev.clear();

    while( (ret=fscanf( fp, "%f,%f,%f,%f,%f,%f", &a1,&a2,&a3,&a4,&Intens,&Error))!=EOF){
        if (Error<0.0) continue;
        a1v.push_back(a1);
        a2v.push_back(a2);
        a3v.push_back(a3);
        a4v.push_back(a4);
        iiv.push_back(Intens);
        eev.push_back(Error);
    }
    fclose(fp);


    float data[3]={0.0,0.0,0.0};
    UInt4 target = 0;
    UInt8 ind = 0;
    float a_sign;
    if (isAdd){
        a_sign = 1.0;
    }else{
        a_sign = -1.0;
    }
    for (UInt4 i=0;i<iiv.size();i++){
        //_CalcIndex( a1v[i],a2v[i],a3v[i],a4v[i],&target,&ind );
        if (_CalcIndex( a1v[i],a2v[i],a3v[i],a4v[i],&target,&ind )==-1) continue;
        fseek( fs_list[ target ], (long)ind, SEEK_SET );
        if (fread( data, sizeof(float), 3, fs_list[ target ] )!=3){
            UtsusemiError( MessageTag+"_AddToMatFromText Failed to read" );
            return -1;
        }else{
            if (data[2]<0.5) {
                data[0] = a_sign*iiv[i];
            }else{
                data[0] += a_sign*iiv[i];
            }
            data[1] += a_sign*eev[i]*eev[i];
            data[2] += a_sign;
            fseek( fs_list[ target ], -1*(Int4)sizeof(data), SEEK_CUR );
            //std::fwrite( &data, sizeof(data), 1, fs_list[ target ] );
            //std::fwrite( data, sizeof(data), 1, fs_list[ target ] );
            if ((int)std::fwrite( data, sizeof(data), 1, fs_list[ target ] ) !=1){
                //usleep(50000);
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
                if ((int)std::fwrite( data, sizeof(data), 1, fs_list[ target ] ) !=1){
                    UtsusemiError( MessageTag + "_AddToMatFromText Failed to write" );
                    return -1;
                }
            }
        }

    }

    if( (ret = SaveParamXml( d4mat_data_dir, d4mat_param_file ))!=0 )        return -1;

    return 0;

}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
AddToMatFromText( std::string filename ){
    Int4 ret;
    ret = _AddToMatFromText( filename, true );
    if (ret==0){
        _isGoodResult = true;
    }else{
        _isGoodResult = false;
    }
}

//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
AddToMatFromPyList( std::string title, PyObject *ax1, PyObject *ax2, PyObject *ax3, PyObject *ax4, PyObject *ii, PyObject *ee ){
    if (!isFilesOpened) _OpenFiles();

    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( ax1 );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( ax2 );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( ax3 );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( ax4 );
    std::vector< Double > II = __gCppToPython.ListToDoubleVector( ii );
    std::vector< Double > EE = __gCppToPython.ListToDoubleVector( ee );

    if ((AX1.size()!=AX2.size())||(AX2.size()!=AX3.size())||(AX3.size()!=AX4.size())){
        std::string msg = MessageTag + "AddToMatFromPyList > Cannot Add given lists to D4Mat 1";
        msg += stools->UInt4ToString((UInt4)(AX1.size()))+","+stools->UInt4ToString((UInt4)(AX2.size()))+",";
        msg += stools->UInt4ToString((UInt4)(AX3.size()))+","+stools->UInt4ToString((UInt4)(AX4.size()));
        UtsusemiError( msg );
        return -1;
    }
    if ((AX1.size()!=II.size())||(II.size()!=EE.size())){
        std::string msg = MessageTag + "AddToMatFromPyList > Cannot Add given lists to D4Mat 2";
        msg += stools->UInt4ToString((UInt4)(AX1.size()))+","+stools->UInt4ToString((UInt4)(II.size()))+","+stools->UInt4ToString((UInt4)(EE.size()));
        UtsusemiError( msg );
        return -1;
    }

    UInt4 target=0;
    UInt8 ind=0;
    float data_out[3]={0.0,0.0,0.0};

    for (UInt4 i=0;i<AX1.size();i++){
        //_CalcIndex( AX1[i],AX2[i],AX3[i],AX4[i],&target,&ind );
        if (_CalcIndex( AX1[i],AX2[i],AX3[i],AX4[i],&target,&ind )==-1) continue;
        fseek( fs_list[ target ], (long)ind, SEEK_SET );
        if (fread( data_out, sizeof(float), 3, fs_list[ target ] )!=3){
            UtsusemiError(MessageTag +"AddToMatFromPyList > Failed to read.");
            return -1;
        }else{
            if (data_out[2]<0.5){
                data_out[0] = (float)II[i];
            }else{
                data_out[0] += (float)II[i];
            }
            data_out[1] += (float)(EE[i]*EE[i]);
            data_out[2] += 1.0;
            fseek( fs_list[ target ], -1*(Int4)sizeof(data_out), SEEK_CUR );
            //std::fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] );
            if ((int)std::fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] ) !=1){
                //usleep(50000);
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
                if ((int)std::fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] ) !=1){
                    UtsusemiError(MessageTag +"AddToMatFromPyList > Failed to write.");
                    return -1;
                }
            }
        }
    }

    Int4 ret;
    file_components.push_back( title );

    if( (ret = SaveParamXml( d4mat_data_dir, d4mat_param_file ))!=0 )        return -1;

    return 0;
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SavePyListToBin( std::string filepath, PyObject *ax1, PyObject *ax2, PyObject *ax3, PyObject *ax4, PyObject *ii, PyObject *ee ){
    _isGoodResult = false;

    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( ax1 );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( ax2 );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( ax3 );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( ax4 );
    std::vector< Double > II = __gCppToPython.ListToDoubleVector( ii );
    std::vector< Double > EE = __gCppToPython.ListToDoubleVector( ee );

    if ((AX1.size()!=AX2.size())||(AX2.size()!=AX3.size())||(AX3.size()!=AX4.size())){
        std::string msg = MessageTag + "SavePyListToBin > Cannot Add given lists to D4Mat 1";
        msg += stools->UInt4ToString((UInt4)(AX1.size()))+","+stools->UInt4ToString((UInt4)(AX2.size()))+",";
        msg += stools->UInt4ToString((UInt4)(AX3.size()))+","+stools->UInt4ToString((UInt4)(AX4.size()));
        UtsusemiError( msg );
        return;
    }
    if ((AX1.size()!=II.size())||(II.size()!=EE.size())){
        std::string msg = MessageTag + "SavePyListToBin > Cannot Add given lists to D4Mat 2";
        msg += stools->UInt4ToString((UInt4)(AX1.size()))+","+stools->UInt4ToString((UInt4)(II.size()))+","+stools->UInt4ToString((UInt4)(EE.size()));
        UtsusemiError( msg );
        return;
    }

    FILE* fp;
    if ((fp=fopen(filepath.c_str(),"wb"))==NULL){
        UtsusemiError(MessageTag +"SavePyListToBin > Cannot open file="+filepath);
        return;
    }
    float data[6];
    for (UInt4 i=0;i<AX1.size();i++){
        if (II[i] > -1000000.0 ){
            data[0]= float( AX1[i] );
            data[1]= float( AX2[i] );
            data[2]= float( AX3[i] );
            data[3]= float( AX4[i] );
            data[4]= float( II[i] );
            data[5]= float( EE[i] );
            //std::fwrite( data, sizeof(data), 1, fp );
            if ((int)std::fwrite( data, sizeof(data), 1, fp ) !=1){
                //usleep(50000);
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
                if ((int)std::fwrite( data, sizeof(data), 1, fp ) !=1){
                    UtsusemiError(MessageTag +"SavePyListToBin > Failed to write");
                    return;
                }
            }

        }
    }
    fclose(fp);

    AX1.clear();
    AX2.clear();
    AX3.clear();
    AX4.clear();
    II.clear();
    EE.clear();

    _isGoodResult = true;
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SubtractFromMatByText( std::string filename ){
    Int4 ret;
    ret = _AddToMatFromText( filename, false );
    if (ret==0){
        _isGoodResult = true;
    }else{
        _isGoodResult = false;
    }
}

//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
_AddToMatFromBin( std::string filename, bool isAdd ){
    if (!isFilesOpened) _OpenFiles();

    FILE* fp;

    if ((fp=fopen(filename.c_str(),"rb"))==NULL){
        UtsusemiError( MessageTag + "_AddToMatFromBin > Cannot open file " +filename );
        return -1;
    }

    if (isAdd){
        file_components.push_back( filename );
    }else{
        std::vector<std::string> temp;
        temp.clear();
        for (UInt4 i=0;i<file_components.size();i++) temp.push_back(file_components[i]);
        file_components.clear();
        for (UInt4 i=0;i<temp.size();i++){
            if (filename!=temp[i]) file_components.push_back(temp[i]);
        }
    }


    int ret;
    //float a1,a2,a3,a4,Intens,Error;
    float data[6];
    std::vector<float> a1v,a2v,a3v,a4v,iiv,eev;
    a1v.clear();
    a2v.clear();
    a3v.clear();
    a4v.clear();
    iiv.clear();
    eev.clear();
    while((ret=(int)fread( data, sizeof(data),1,fp))==1){
        if (data[5]<0.0) continue;
        a1v.push_back( data[0] );
        a2v.push_back( data[1] );
        a3v.push_back( data[2] );
        a4v.push_back( data[3] );
        iiv.push_back( data[4] );
        eev.push_back( data[5] );
    }
    fclose(fp);
    UInt4 target=0;
    UInt8 ind=0;
    float data_out[3]={0.0,0.0,0.0};
    float a_sign = 1.0;
    if (!isAdd){
        a_sign = -1.0;
    }
    UInt4 sum_of_points = (UInt4)(iiv.size());
    UtsusemiMessage( MessageTag + "_AddToMatFromBin > --- Under loading data (size="+stools->UInt4ToString(sum_of_points)+")" );
    UInt4 step_points = (UInt4)( ((Double)sum_of_points-1.0)/5.0 );
    for (UInt4 i=0;i<iiv.size();i++){
        //if ((i % 100000)==0) std::cout << i <<"/"<< sum_of_points << std::endl;
        if ((step_points!=0)&&( ( i % step_points )==0 )) UtsusemiMessage( MessageTag + "_AddToMatFromBin > "+stools->Int4ToString((int)(i/step_points)*20)+" %" );
        //_CalcIndex( a1v[i],a2v[i],a3v[i],a4v[i],&target,&ind );
        if (_CalcIndex( a1v[i],a2v[i],a3v[i],a4v[i],&target,&ind )==-1) continue;
        fseek( fs_list[ target ], (long)ind, SEEK_SET );
        if (fread( data_out, sizeof(data_out), 1, fs_list[ target ] )!=1){
            UtsusemiError( MessageTag + "_AddToMatFromBin > Failed to read.");
            return -1;
        }else{
            if (data_out[2]<0.5){
                data_out[0] = a_sign*iiv[i];
            }else{
                data_out[0] += a_sign*iiv[i];
            }
            data_out[1] += a_sign*eev[i]*eev[i];
            data_out[2] += a_sign;
            fseek( fs_list[ target ], -1*(Int4)sizeof(data_out), SEEK_CUR );
            //std::fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] );
            if ((int)std::fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] ) !=1){
                //usleep(50000);
                std::this_thread::sleep_for(std::chrono::milliseconds(50));
                if ((int)std::fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] ) !=1){
                    UtsusemiError( MessageTag + "_AddToMatFromBin > Failed to write.");
                    return -1;
                }
            }
        }
    }
    //std::cout << std::endl;

    if( (ret = SaveParamXml( d4mat_data_dir, d4mat_param_file ))!=0 )        return -1;

    return 0;
}

//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
AddToMatFromBin( std::string filename ){
    Int4 ret = _AddToMatFromBin( filename, true );
    if (ret==0){
        _isGoodResult = true;
    }else{
        _isGoodResult = false;
    }
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
AddToMatFromBinFolder( std::string folderpath, std::string _ext ){
    _isGoodResult = false;
    const boost::filesystem::path target( folderpath.c_str() );
    if (boost::filesystem::exists( target )){
        BOOST_FOREACH( const boost::filesystem::path& p_a_file,
                       std::make_pair( boost::filesystem::directory_iterator( target ),
                                       boost::filesystem::directory_iterator() ) ){
            if (!boost::filesystem::is_directory(p_a_file)){
                std::string a_file( p_a_file.string() );
                if (a_file.find(_ext)!=std::string::npos){
                    if (_AddToMatFromBin( a_file, true )<0) return false;
                }
            }
        }
    }
    _isGoodResult = true;
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SubtractFromMatByBin( std::string filename ){
    Int4 ret;
    ret = _AddToMatFromBin( filename, false );
    if (ret==0){
        _isGoodResult = true;
    }else{
        _isGoodResult = false;
    }
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
_CalcRangeInfo( UInt4 dim, std::vector<Double> &a1r, std::vector<Double> &a2r, std::vector<Double> &a3r, std::vector<Double> &a4r,
                std::vector<std::string> &def_axes, std::vector<UInt4> &def_ind, std::vector< std::vector<Double> > &arlist, std::vector<UInt4> &numlist ){
    if ((a1r.size()<2)||(a2r.size()<2)||(a3r.size()<2)||(a4r.size()<2)) return false;
    if (a1r[0]<range_list[0][0]) a1r[0] = range_list[0][0];
    if (a1r[1]>range_list[0][1]) a1r[1] = range_list[0][1];
    if (a2r[0]<range_list[1][0]) a2r[0] = range_list[1][0];
    if (a2r[1]>range_list[1][1]) a2r[1] = range_list[1][1];
    if (a3r[0]<range_list[2][0]) a3r[0] = range_list[2][0];
    if (a3r[1]>range_list[2][1]) a3r[1] = range_list[2][1];
    if (a4r[0]<range_list[3][0]) a4r[0] = range_list[3][0];
    if (a4r[1]>range_list[3][1]) a4r[1] = range_list[3][1];
    a1r.push_back( range_list[0][2] );
    a2r.push_back( range_list[1][2] );
    a3r.push_back( range_list[2][2] );
    a4r.push_back( range_list[3][2] );

    arlist.clear();
    arlist.resize(4);
    arlist[0]= a1r;
    arlist[1]= a2r;
    arlist[2]= a3r;
    arlist[3]= a4r;

    // Set index for each Axis in "ranges"
    UInt4 indX  = 99;
    UInt4 indY  = 99;
    UInt4 indZ  = 99;
    UInt4 indT  = 99;

    for (UInt4 i=0;i<def_axes.size();i++){
        if ((def_axes[i]=="X")||(def_axes[i]=="x"))
            indX = i;

        if ((def_axes[i]=="Y")||(def_axes[i]=="y"))
            indY = i;

        if (dim==1){
            if ((def_axes[i]=="T")||(def_axes[i]=="t")){
                if (indY==99) indY = i;
                else if (indZ==99) indZ = i;
                else indT = i;
            }
        }else if (dim==2){
            if ((def_axes[i]=="T")||(def_axes[i]=="t")){
                if (indZ==99) indZ = i;
                else indT = i;
            }
        }else if (dim>=3){
            if ((def_axes[i]=="Z")||(def_axes[i]=="z"))
                indZ = i;
            if ((def_axes[i]=="T")||(def_axes[i]=="t"))
                indT = i;
        }else return false;
    }

    def_ind.clear();
    def_ind.resize(4);
    def_ind[0] = indX;
    def_ind[1] = indY;
    def_ind[2] = indZ;
    def_ind[3] = indT;

    // Get ranges of each axis for slicing
    std::vector<Double> xrange = CalcRangeAsBinCenterZero( arlist[indX][0],arlist[indX][1],arlist[indX][2] );
    std::vector<Double> yrange = CalcRangeAsBinCenterZero( arlist[indY][0],arlist[indY][1],arlist[indY][2] );
    std::vector<Double> zrange = CalcRangeAsBinCenterZero( arlist[indZ][0],arlist[indZ][1],arlist[indZ][2] );
    std::vector<Double> trange = CalcRangeAsBinCenterZero( arlist[indT][0],arlist[indT][1],arlist[indT][2] );

    arlist[indX][0] = xrange[0];
    arlist[indX][1] = xrange[1];
    if (dim==1){
        arlist[indY][2] = arlist[indY][1]-arlist[indY][0];
        arlist[indZ][2] = arlist[indZ][1]-arlist[indZ][0];
        arlist[indT][2] = arlist[indT][1]-arlist[indT][0];
    }else if (dim==2){
        arlist[indY][0] = yrange[0];
        arlist[indY][1] = yrange[1];
        arlist[indZ][2] = arlist[indZ][1]-arlist[indZ][0];
        arlist[indT][2] = arlist[indT][1]-arlist[indT][0];
    }else if (dim==3){
        arlist[indY][0] = yrange[0];
        arlist[indY][1] = yrange[1];
        arlist[indZ][0] = zrange[0];
        arlist[indZ][1] = zrange[1];
        arlist[indT][2] = arlist[indT][1]-arlist[indT][0];
    }else if (dim==4){
        arlist[indY][0] = yrange[0];
        arlist[indY][1] = yrange[1];
        arlist[indZ][0] = zrange[0];
        arlist[indZ][1] = zrange[1];
        arlist[indT][0] = trange[0];
        arlist[indT][1] = trange[1];
    }else{
        UtsusemiError( MessageTag+"_CalcRangeInfo > dim is invalid." );
        return false;
    }

    if (isDebugMode) {
        std::cout << "-----------------------------------"<<std::endl;
        std::cout << "xrange="<< xrange[0] <<","<<xrange[1]<<","<<arlist[indX][2]<<std::endl;
        std::cout << "yrange="<< yrange[0] <<","<<yrange[1]<<","<<arlist[indY][2]<<std::endl;
        std::cout << "zrange="<< arlist[indZ][0] <<","<<arlist[indZ][1]<<","<<arlist[indZ][2]<<std::endl;
        std::cout << "trange="<< arlist[indT][0] <<","<<arlist[indT][1]<<","<<arlist[indT][2]<<std::endl;
        std::cout << "-----------------------------------"<<std::endl;
        std::cout << "range_list[0]="<<range_list[0][0]<<","<<range_list[0][1]<<","<<range_list[0][2]<<std::endl;
        std::cout << "range_list[1]="<<range_list[1][0]<<","<<range_list[1][1]<<","<<range_list[1][2]<<std::endl;
        std::cout << "range_list[2]="<<range_list[2][0]<<","<<range_list[2][1]<<","<<range_list[2][2]<<std::endl;
        std::cout << "range_list[3]="<<range_list[3][0]<<","<<range_list[3][1]<<","<<range_list[3][2]<<std::endl;
    }

    numlist.clear();
    numlist.resize(4,1);
    numlist[0] = (UInt4)xrange[2];
    if (dim==2) numlist[1] = (UInt4)yrange[2];
    if (dim==3){
        numlist[1] = (UInt4)yrange[2];
        numlist[2] = (UInt4)zrange[2];
    }
    if (dim==4){
        numlist[1] = (UInt4)yrange[2];
        numlist[2] = (UInt4)zrange[2];
        numlist[3] = (UInt4)trange[2];
    }
    return true;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
_SliceMat( ElementContainerMatrix* _ecm, UInt4 dim, std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings, std::vector<std::string> key_axes ){
    if (_isVirtual){
    }else if (isFilesOpened){
    }else _OpenFiles();

    std::vector< std::vector<Double> > ArList;
    std::vector<UInt4> def_ind,NumList;
    if (_CalcRangeInfo( dim, a1range, a2range, a3range, a4range, def_axes, def_ind, ArList, NumList )){
    }else{
        return false;
    }
    if (foldings.empty()) foldings.resize(4,-1.0);

    UInt4 indX = def_ind[0];
    UInt4 indY = def_ind[1];
    UInt4 indZ = def_ind[2];
    UInt4 n_X = NumList[0];
    UInt4 n_Y = NumList[1];
    UInt4 n_Z = NumList[2];

    for (UInt4 i=0; i<4; i++) _AxisDefIndex[i] = def_ind[i];

    // Setting Foldings
    bool isFoldingFYminusFX = false; // Y=X line
    bool isFoldingFYplusFX = false;  // Y=-X line
    UInt4 indFX=0;
    UInt4 indFY=0;

    if ((foldings.size()==7)&&(foldings[4]>0.0)){
            if (foldings[4]==1){
            isFoldingFYminusFX = true;
        }else if (foldings[4]==2){
            isFoldingFYplusFX = true;
        }else if (foldings[4]==3){
            isFoldingFYminusFX = true;
            isFoldingFYplusFX = true;
        }else{
        }
        indFX = (UInt4)foldings[5];
        indFY = (UInt4)foldings[6];
    }

    if ((dim>2)&&(key_axes.size()<dim)){
        UtsusemiError( MessageTag+"Slice > key_axes is invalid." );
        return false;
    }

    // Make and initialize temporal matrix for sliced data
    float ***dArray, ***eArray, ***cArray;
    dArray = new float**[ n_X ];
    eArray = new float**[ n_X ];
    cArray = new float**[ n_X ];
    for (UInt4 i=0;i<n_X;i++){
        dArray[i] = new float*[ n_Y ];
        eArray[i] = new float*[ n_Y ];
        cArray[i] = new float*[ n_Y ];
        for (UInt4 j=0;j<n_Y;j++){
            dArray[i][j] = new float[ n_Z ];
            eArray[i][j] = new float[ n_Z ];
            cArray[i][j] = new float[ n_Z ];
        }
    }
    for (UInt4 i=0;i<n_X;i++){
        for (UInt4 j=0;j<n_Y;j++){
            for (UInt4 k=0;k<n_Z;k++){
                dArray[i][j][k]=eArray[i][j][k]=cArray[i][j][k]=0.0;
            }
        }
    }

    std::vector<UInt4> iXs(4,0);
    std::vector<Double> fXs(4,0.0);

    for (UInt4 iX3=0; iX3<NumBin[3]; iX3++){
        Double x3 = range_list[3][0] + range_list[3][2]*(double(iX3)+0.5);
        fXs[3] = 0.0;
        if (foldings[3]==0.0) fXs[3] = fabs(x3);
        else if (foldings[3]>0.0){
            if ( (foldings[3]<=fabs(x3))&&(fabs(x3)<=(2.0*foldings[3])) ) fXs[3] = 2.0*foldings[3] - fabs(x3);
            else if ( ((-1.0*foldings[3])<x3)&&(x3<foldings[3]) ) fXs[3] = fabs(x3);
        }else fXs[3] = x3;

        if ( (fXs[3]<ArList[3][0])||(fXs[3]>=ArList[3][1]) ) continue;

        UInt4 ind3 = 0;
        UInt4 file_target = 0;
        if (_isVirtual){
            ind3 = iX3;
        }else{
            ind3 = iX3 * size_of_Ax[3];
            for (UInt4 j=0;j<(index_of_blocks.size()-1);j++){
                if ( (iX3>=index_of_blocks[j])&&(iX3<index_of_blocks[j+1]) ) {
                    file_target = j;
                    ind3 = (iX3 - index_of_blocks[j])*size_of_Ax[3];
                    break;
                }
            }
        }

        iXs[3] = (UInt4)((fXs[3] - ArList[3][0])/ArList[3][2]);

        for (UInt4 iX0=0; iX0<NumBin[0]; iX0++){
            for (UInt4 iX1=0; iX1<NumBin[1]; iX1++){
                for (UInt4 iX2=0; iX2<NumBin[2]; iX2++){
                    fXs[0] = range_list[0][0] + range_list[0][2]*(double(iX0)+0.5);
                    fXs[1] = range_list[1][0] + range_list[1][2]*(double(iX1)+0.5);
                    fXs[2] = range_list[2][0] + range_list[2][2]*(double(iX2)+0.5);

                    // Folding along diagonal line
                    if ((isFoldingFYminusFX)&&(fXs[indFY]<fXs[indFX])){
                        Double tmp = fXs[indFX];
                        fXs[indFX] = fXs[indFY];
                        fXs[indFY] = tmp;
                    }
                    if ((isFoldingFYplusFX)&&(fXs[indFY]<(-fXs[indFX]))){
                        Double tmp = -fXs[indFX];
                        fXs[indFX] = -fXs[indFY];
                        fXs[indFY] = tmp;
                    }

                    // Folding along axis direction
                    bool isBreak = false;
                    for (UInt4 iXn = 0; iXn<3; iXn++){
                        if (foldings[iXn]==0.0) fXs[iXn] = fabs(fXs[iXn]);
                        else if (foldings[iXn]>0.0){
                            if ( (foldings[iXn]<=fabs(fXs[iXn]))&&(fabs(fXs[iXn])<=(2.0*foldings[iXn])) ) fXs[iXn] = 2.0*foldings[iXn] - fabs(fXs[iXn]);
                            else if ( ((-1.0*foldings[iXn])<fXs[iXn])&&(fXs[iXn]<foldings[iXn]) ) fXs[iXn] = fabs(fXs[iXn]);
                        }
                        if ( (fXs[iXn]<ArList[iXn][0])||(fXs[iXn]>=ArList[iXn][1]) ){
                            isBreak = true;
                            break;
                        }
                        iXs[iXn] = (UInt4)((fXs[iXn] - ArList[iXn][0])/ArList[iXn][2]);
                    }
                    if (isBreak) continue;

                    if (_isVirtual){
                        UInt4 ind = iX0 * size_of_Ax[0] + iX1 * size_of_Ax[1] + iX2 * size_of_Ax[2];
                        float intensity = _VirtualD4Mat->at(ind3)->at(ind);
                        dArray[ iXs[indX] ][ iXs[indY] ][ iXs[indZ] ] += intensity;
                        eArray[ iXs[indX] ][ iXs[indY] ][ iXs[indZ] ] += intensity;
                        cArray[ iXs[indX] ][ iXs[indY] ][ iXs[indZ] ] += intensity;
                    }else{
                        UInt4 ind = iX0 * size_of_Ax[0] + iX1 * size_of_Ax[1] + iX2 * size_of_Ax[2] + ind3;
                        float dat[3];
                        fseek( fs_list[ file_target ], ind, SEEK_SET );
                        if ((int)fread( dat, sizeof(dat), 1, fs_list[ file_target ] )!=1){
                            UtsusemiError( MessageTag + "SliceMat failed to read data" );
                        }else{
                            if (dat[2]!=0.0){
                                dArray[ iXs[indX] ][ iXs[indY] ][ iXs[indZ] ] += dat[0];
                                eArray[ iXs[indX] ][ iXs[indY] ][ iXs[indZ] ] += dat[1];
                                cArray[ iXs[indX] ][ iXs[indY] ][ iXs[indZ] ] += dat[2];
                            }
                        }
                    } // if _isVirtual
                } // Loop NumBin[2]
            }// Loop NumBin[1]
        }// Loop NumBin[0]
    }// Loop NumBin[3]

    std::vector< std::vector< std::vector<Double> > > outDArray, outEArray;
    std::vector<Double> oxArray, oyArray, ozArray;

    oxArray.resize(n_X+1);
    oyArray.resize(n_Y+1);
    ozArray.resize(n_Z+1);

    for (UInt4 i=0; i<(n_X+1); i++)
        oxArray[i] = ArList[indX][0] + ArList[indX][2]*double(i);

    for (UInt4 i=0; i<(n_Y+1); i++)
        oyArray[i] = ArList[indY][0] + ArList[indY][2]*double(i);

    for (UInt4 i=0; i<(n_Z+1); i++)
        ozArray[i] = ArList[indZ][0] + ArList[indZ][2]*double(i);

    if (dim>2){
        std::string keyX = key_axes[0];
        std::string keyY = key_axes[1];
        std::string keyZ = key_axes[2];

        _ecm->Allocate( n_X );
        Double xval=0.0;
        Double yval=0.0;
        Double zval=0.0;
        std::string xtitle = "X";
        std::string ytitle = "Y";
        std::string ztitle = "Z";

        for (UInt4 i=0; i<n_X; i++){
            ElementContainerArray *eca = new ElementContainerArray();
            HeaderBase* eca_hh = eca->PutHeaderPointer();
            std::vector<Double> xr(2);
            xr[0]=oxArray[i];
            xr[1]=oxArray[i+1];
            eca_hh->Add(UTSUSEMI_KEY_HEAD_XRANGE, xr);
            xval = (xr[0]+xr[1])/2.0;

            eca->Allocate( n_Y );
            for (UInt4 j=0; j<n_Y; j++){
                ElementContainer* ec = new ElementContainer();
                HeaderBase* ec_hh = ec->PutHeaderPointer();
                std::vector<Double> yr(2);
                yr[0]=oyArray[j];
                yr[1]=oyArray[j+1];
                ec_hh->Add("YRANGE", yr);
                yval = (yr[0]+yr[1])/2.0;

                std::vector<Double> Int( n_Z, 0.0 );
                std::vector<Double> Err( n_Z, 0.0 );
                std::vector<Double> vx( n_Z, xval );
                std::vector<Double> vy( n_Z, yval );
                std::vector<Double> vz( n_Z, 0.0 );
                for (UInt4 k=0;k<n_Z;k++){
                    vz[k] = (ozArray[k]+ozArray[k+1])/2.0;
                    if (cArray[i][j][k]!=0.0){
                        Int[k] = dArray[i][j][k]/cArray[i][j][k];
                        Err[k] = sqrt(eArray[i][j][k])/cArray[i][j][k];
                    }else{
                        Int[k] = 0.0;
                        Err[k] = -1.0;
                    }
                }
                ec->Add( ztitle, ozArray );
                ec->Add( UTSUSEMI_KEY_INTENSITY, Int );
                ec->Add( UTSUSEMI_KEY_ERROR, Err );
                ec->SetKeys( ztitle, UTSUSEMI_KEY_INTENSITY, UTSUSEMI_KEY_ERROR );

                ec->Add( keyX, vx );
                ec->Add( keyY, vy );
                ec->Add( keyZ, vz );

                eca->Set( j, ec );
            }
            _ecm->Set( i, eca );
        }

        _ecm->PutHeaderPointer()->Add("SLICE3DKEYS",key_axes);
    }else if (dim==2){
        datArray.clear();
        errArray.clear();
        XArray.clear();
        YArray.clear();

        XArray.resize(n_X+1);
        YArray.resize(n_Y+1);
        for (UInt4 i=0; i<(n_X+1); i++){
            XArray[i] = ArList[indX][0] + ArList[indX][2]*double(i);
        }
        for (UInt4 i=0; i<(n_Y+1); i++){
            YArray[i] = ArList[indY][0] + ArList[indY][2]*double(i);
        }

        for (UInt4 i=0;i<n_X;i++){
            std::vector<Double> datY(n_Y,0.0);
            std::vector<Double> datE(n_Y,0.0);
            for (UInt4 j=0;j<n_Y;j++){
                if (cArray[i][j][0]!=0.){
                    datY[j]= dArray[i][j][0]/cArray[i][j][0];
                    datE[j]= sqrt( eArray[i][j][0] )/cArray[i][j][0];
                }else{
                    datY[j]= UTSUSEMIMASKVALUE64;
                    datE[j]= 0.0;
                }
            }
            datArray.push_back(datY);
            errArray.push_back(datE);
        }
        if (_ecm!=NULL)
            _ecm->Add( PutSlicedECA() );
    }else{
        datArray.clear();
        errArray.clear();
        XArray.clear();
        YArray.clear();

        XArray.resize(n_Y+1,0.0);
        YArray.resize(n_X+1,0.0);
        for (UInt4 i=0; i<(n_X+1); i++){
            YArray[i] = ArList[indX][0] + ArList[indX][2]*double(i);
        }
        std::vector<Double> datY(n_X,0.0);
        std::vector<Double> datE(n_X,0.0);
        for (UInt4 i=0;i<n_X;i++){
            if (cArray[i][0][0]!=0.){
                datY[i] = dArray[i][0][0]/cArray[i][0][0];
                datE[i] = sqrt( eArray[i][0][0] )/cArray[i][0][0];
            }else{
                datY[i]= UTSUSEMIMASKVALUE64;
                datE[i]= 0.0;
            }
        }
        datArray.push_back(datY);
        errArray.push_back(datE);
        if (_ecm!=NULL)
            _ecm->Add( PutSlicedECA() );
    }

    for (UInt4 i=0;i<n_X;i++){
        for (UInt4 j=0;j<n_Y;j++){
            delete [] dArray[i][j];
            delete [] eArray[i][j];
            delete [] cArray[i][j];
        }
        delete [] dArray[i];
        delete [] eArray[i];
        delete [] cArray[i];
    }
    delete [] dArray;
    delete [] eArray;
    delete [] cArray;

    return true;
}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SliceMat( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings ){
    std::vector<std::string> dammy;
    _isGoodResult = _SliceMat(NULL, 2, a1range, a2range, a3range, a4range, def_axes, foldings, dammy);
}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SliceMat1d( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings ){
    std::vector<std::string> dammy;
    _isGoodResult = _SliceMat(NULL, 1, a1range, a2range, a3range, a4range, def_axes, foldings, dammy);
}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SliceVirtualMat( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings ){
    _isGoodResult = false;
    if (_VirtualD4Mat==NULL) return;
    std::vector<std::string> dammy;
    _isGoodResult = _SliceMat(NULL, 2, a1range, a2range, a3range, a4range, def_axes, foldings, dammy);
    return;
}
//////////////////////////////////////////////////////////////////////
std::vector<Double> UtsusemiD4Matrix::
PutSliceResults( UInt4 type, UInt4 index ){
    std::vector<Double> ret;
    ret.push_back(-1.0);
    if (index>datArray.size()){
        UtsusemiError(MessageTag + "Arguments is too large < " + stools->UInt4ToString((UInt4)(datArray.size())));
        return ret;
    }
    if (type==0){
        return datArray[index];
    }else if (type==1){
        return errArray[index];
    }else if (type==2){
        return XArray;
    }else if (type==3){
        return YArray;
    }else{
        UtsusemiError(MessageTag + "type is invalid.(0=Intensity, 1=Error, 2=X array, 3=Y array)");
        return ret;
    }
}

//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
_CalcIndex( Double a1, Double a2, Double a3, Double a4, UInt4 *target, UInt8 *ind ){

    if (a1 < range_list[0][0]) return -1;
    if (a1 > range_list[0][1]) return -1;
    if (a2 < range_list[1][0]) return -1;
    if (a2 > range_list[1][1]) return -1;
    if (a3 < range_list[2][0]) return -1;
    if (a3 > range_list[2][1]) return -1;
    if (a4 < range_list[3][0]) return -1;
    if (a4 > range_list[3][1]) return -1;

    UInt4 i1 = (UInt4)( float( (a1 - range_list[0][0])/range_list[0][2] ) );
    UInt4 i2 = (UInt4)( float( (a2 - range_list[1][0])/range_list[1][2] ) );
    UInt4 i3 = (UInt4)( float( (a3 - range_list[2][0])/range_list[2][2] ) );
    UInt4 i4 = (UInt4)( float( (a4 - range_list[3][0])/range_list[3][2] ) );

    UInt4 div_i4 = i4;

    for (UInt4 i=0;i<(index_of_blocks.size()-1);i++){
        if ( (i4>=index_of_blocks[i])&&(i4<index_of_blocks[i+1]) ) {
            *target = i;
            div_i4= i4 - index_of_blocks[i];
            break;
        }
    }

    *ind = (UInt8)(size_of_Ax[0]*i1 + size_of_Ax[1]*i2 + size_of_Ax[2]*i3 + size_of_Ax[3]*div_i4);
    return 0;
}
//////////////////////////////////////////////////////////////////////
std::vector<Double> UtsusemiD4Matrix::
PickUpInten( Double a1, Double a2, Double a3, Double a4 ){
    if (!isFilesOpened) _OpenFiles();
    std::vector<Double> ret;
    UInt4 target = 0;
    UInt8 ind = 0;
    float data[3];

    //_CalcIndex( a1, a2, a3, a4, &target, &ind );
    if (_CalcIndex( a1, a2,a3, a4, &target, &ind )==-1){
        data[0]=0.0;
        data[1]=0.0;
        data[2]=0.0;
    }else{
        fseek( fs_list[ target ], (long)ind, SEEK_SET );
        if (fread( data, sizeof(float), 3, fs_list[ target ] )!=3) {
            UtsusemiError( MessageTag + "Fail to read data from file." );
            return ret;
        }
        if (isDebugMode) {
            std::cout << MessageTag << "target file=" << name_of_blocks[ target ] << std::endl;
            std::cout << MessageTag << "ind = " << ind << std::endl;
            std::cout << MessageTag << "Intensity = " << data[0] << std::endl;
            std::cout << MessageTag << "Error = " << data[1] << std::endl;
            std::cout << MessageTag << "Counts = " << data[2] << std::endl;
        }
    }
    if (data[2]==0.0){
        ret.push_back(0.0);
        ret.push_back(0.0);
    }else{
        ret.push_back( Double( data[0]/data[2] ) );
        ret.push_back( Double( sqrt( data[1] )/data[2] ) );
    }
    return ret;
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
ReplaceInten( Double a1, Double a2, Double a3, Double a4, Double Inten, Double Error, Double Counts ){
    if (!isFilesOpened) _OpenFiles();

    UInt4 target = 0;
    UInt8 ind = 0;
    //_CalcIndex( a1, a2, a3, a4, &target, &ind );
    if (_CalcIndex( a1,a2,a3,a4,&target,&ind )==-1){
        UtsusemiError(MessageTag + "This argument is out of range ");
    }else{
        float data[3];
        data[0] = float(Inten);
        data[1] = float(Error);
        data[2] = float(Counts);
        fseek( fs_list[ target ], (long)ind, SEEK_SET );
        //std::fwrite( &data, sizeof(data), 1, fs_list[ target ] );
        if ((int)std::fwrite( data, sizeof(data), 1, fs_list[ target ] )!=1){
            UtsusemiError( MessageTag + "Failed to replace data" );
        }
    }
}

//////////////////////////////////////////////////////////////////////
ElementContainerArray UtsusemiD4Matrix::
PutSlicedECA(){
    ElementContainerArray eca;
    if (datArray.size()==0){
        return eca;
    }

    eca.AddToHeader(UTSUSEMI_KEY_HEAD_ISHISTOGRAM,0);
    eca.AddToHeader(MLF_KEY_HEAD_XUNIT,ax_units[_AxisDefIndex[0]]);
    for (UInt4 i=0;i<(XArray.size()-1);i++){
        std::vector<Double> v_int = PutSliceResults(0,i);
        std::vector<Double> v_err = PutSliceResults(1,i);

        ElementContainer ec;

        std::vector<Double> xrange;
        xrange.push_back(XArray[i]);
        xrange.push_back(XArray[i+1]);
        ec.AddToHeader(UTSUSEMI_KEY_HEAD_XRANGE,xrange);
        ec.AddToHeader(MLF_KEY_HEAD_XUNIT,ax_units[_AxisDefIndex[0]]);

        ec.Add("Y",YArray,ax_units[_AxisDefIndex[1]]);
        ec.Add(UTSUSEMI_KEY_INTENSITY,v_int,UTSUSEMI_KEY_ARB_UNIT);
        ec.Add(UTSUSEMI_KEY_ERROR,v_err,UTSUSEMI_KEY_ARB_UNIT);
        ec.SetKeys("Y",UTSUSEMI_KEY_INTENSITY,UTSUSEMI_KEY_ERROR);
        eca.Add(ec);
    }

    return eca;
}

//////////////////////////////////////////////////////////////////////
std::vector<Double> UtsusemiD4Matrix::
PutAxRange( UInt4 i_ax ){
    std::vector<Double> ret;
    ret.clear();
    if ((i_ax<0)||(i_ax>3)){
        UtsusemiError( MessageTag + "Argument is out of range. (" + stools->UInt4ToString(i_ax)+ ")" );
        ret.push_back(-1);
    }else{
        //[inamura 160622]-->
        //for (UInt4 i=0;i<3;i++){
        //    ret.push_back( range_list[i_ax][i] );
        //}
        ret.resize(3);
        ret[0] = range_list[i_ax][0] + range_list[i_ax][2]*0.5;
        ret[1] = ret[0] + range_list[i_ax][2]*((double)(NumBin[i_ax])-1.0);
        ret[2] = range_list[i_ax][2];
        //<--[inamura 160622]
    }

    return ret;
}

//////////////////////////////////////////////////////////////////////
std::string UtsusemiD4Matrix::
PutAxTitle( UInt4 i_ax ){
    if ((i_ax<0)||(i_ax>3)){
        UtsusemiError( MessageTag + "Argument is out of range. (" + stools->UInt4ToString(i_ax)+ ")" );
        return "None";
    }else{
        return ax_titles[i_ax];
    }

}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SetAxTitle( UInt4 i_ax, std::string title ){
    if ((i_ax<0)||(i_ax>3)){
        UtsusemiError( MessageTag + "Argument is out of range. (" + stools->UInt4ToString(i_ax)+ ")" );
    }else{
        ax_titles[i_ax] = title;
    }
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SetAxTitles( std::vector<std::string> titles, bool isSaved ){
    if ((titles.size()==0)||(titles.size()>4)){
      UtsusemiError( MessageTag + "Vector size of argument is out of range. (" + stools->UInt4ToString((UInt4)(titles.size()))+ ")" );
    }else{
        for (UInt4 i=0;i<titles.size();i++){
            SetAxTitle( i, titles[i] );
        }
    }
    if (isSaved) SaveParamXml( d4mat_data_dir, d4mat_param_file );
}
//////////////////////////////////////////////////////////////////////
std::string UtsusemiD4Matrix::
PutAxUnit( UInt4 i_ax ){
    if ((i_ax<0)||(i_ax>3)){
        UtsusemiError( MessageTag + "Argument is out of range. (" + stools->UInt4ToString(i_ax)+ ")" );
        return "None";
    }else{
        return ax_units[i_ax];
    }

}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SetAxUnit( UInt4 i_ax, std::string unit ){
    if ((i_ax<0)||(i_ax>3)){
        UtsusemiError( MessageTag + "Argument is out of range. (" + stools->UInt4ToString(i_ax)+ ")" );
    }else{
        ax_units[i_ax] = unit;
    }
}

//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SetAxUnits( std::vector<std::string> units, bool isSaved ){
    if ((units.size()==0)||(units.size()>4)){
      UtsusemiError( MessageTag + "Vector size of argument is out of range. (" + stools->UInt4ToString((UInt4)(units.size()))+ ")" );
    }else{
        for (UInt4 i=0;i<units.size();i++){
            SetAxUnit( i, units[i] );
        }
    }
    if (isSaved) SaveParamXml( d4mat_data_dir, d4mat_param_file );
}

//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
SaveParamXml( std::string datapath, std::string filename ){
    BoostXmlParser *bxmlp = new BoostXmlParser();
    bxmlp->SetQuiet( !(UtsusemiEnvGetDebugMode()) );
    //mxml_node_t *tree,*node1,*node2,*node3,*node4;

    std::vector<std::string> att_v, val_v;
    std::string _KEY = "d4mat_key";
    bxmlp->CreateNewTree(_KEY);

    bxmlp->AddElement(_KEY,"D4Matrix/numOfFileBlocks", stools->UInt4ToString( (UInt4)(name_of_blocks.size()) ) );

    // D4Matrix/blocks/block
    bxmlp->AddElement(_KEY,"D4Matrix/blocks", "" );
    for (Int4 i=0; i<name_of_blocks.size(); i++){
        att_v.clear();
        val_v.clear();
        att_v.push_back("i");
        val_v.push_back( stools->Int4ToString( i ) );
        //bxmlp->AddElement(_KEY,"D4Matrix/blocks/block",att_v,val_v);
        std::string path_block = "D4Matrix/blocks/block,i="+stools->Int4ToString( i );
        bxmlp->AddElement(_KEY,path_block,"");
        bxmlp->AddElement(_KEY,path_block+"/filename",name_of_blocks[i]);

        for (Int4 j=0;j<3;j++){
            std::string st_ax = "ax"+stools->Int4ToString(j+1);
            std::string st_range = "";
            st_range = stools->DoubleToString( Double( range_list[j][0] ) )+",";
            st_range+= stools->DoubleToString( Double( range_list[j][1] ) )+",";
            st_range+= stools->DoubleToString( Double( range_list[j][2] ) );
            bxmlp->AddElement(_KEY, (path_block+"/"+st_ax), st_range );
        }
        std::string st_range="";
        st_range = stools->DoubleToString( Double(range_list[3][0]+range_list[3][2]*index_of_blocks[i]) );
        st_range += ",";
        st_range += stools->DoubleToString( Double(range_list[3][0]+range_list[3][2]*index_of_blocks[i+1]) );
        st_range += "," + stools->DoubleToString( Double( range_list[3][2] ) );
        bxmlp->AddElement(_KEY, (path_block+"/ax4"), st_range );

    }

    // D4Matrix/axisTitle
    bxmlp->AddElement(_KEY, "D4Matrix/axisTitle", "" );
    for (Int4 i=0;i<4;i++){
        std::string st = "ax"+stools->Int4ToString(i+1);
        bxmlp->AddElement(_KEY, ("D4Matrix/axisTitle/"+st), ax_titles[i] );
        bxmlp->AddElement(_KEY, ("D4Matrix/axisUnit/"+st), ax_units[i] );
    }

    // D4Matrix/numOfFileComponents
    bxmlp->AddElement(_KEY, "D4Matrix/numOfFileComponents", stools->UInt4ToString( (UInt4)(file_components.size()) ) );

    // D4Matrix/fileComponents
    bxmlp->AddElement(_KEY, "D4Matrix/fileComponents","" );
    if (file_components.size()!=0){
        for (UInt4 i=0;i<file_components.size();i++){
            bxmlp->AddElement(_KEY, "D4Matrix/fileComponents/filepath,i="+stools->Int4ToString( i ), file_components[i] );
        }
    }

    if (datapath.substr( datapath.size()-1 )!=std::string("/")){
        datapath = datapath+"/";
    }
    std::string filepath = datapath + filename;
    bxmlp->Save( filepath );

    delete bxmlp;

    return 0;

}
//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
_ReadParamXml( std::string datapath, std::string filename ){

    _ClearAllParams();

    for (UInt4 i=0;i<4;i++){
        std::vector<Double> v;
        v.clear();
        for (UInt4 j=0;j<3;j++) v.push_back(0.0);
        range_list.push_back(v);
    }

    BoostXmlParser *bxmlp = new BoostXmlParser();
    bxmlp->SetQuiet( !(UtsusemiEnvGetDebugMode()) );
    if (datapath.substr( datapath.size()-1 )!=std::string("/")){
        datapath = datapath+"/";
    }
    std::string filepath = datapath + filename;
    std::string _KEY = "loaded_xml";
    bxmlp->Load(_KEY, filepath );

    UInt4 num_of_file_blocks = 0;
    if (bxmlp->hasPath(_KEY, "D4Matrix/numOfFileBlocks")){
        std::string tmp = bxmlp->PutContent(_KEY, "D4Matrix/numOfFileBlocks","");
        num_of_file_blocks = stools->StringToUInt4( tmp );
    }

    UInt4 num_of_file_compos = 0;
    if (bxmlp->hasPath(_KEY, "D4Matrix/numOfFileComponents")){
        std::string tmp = bxmlp->PutContent(_KEY, "D4Matrix/numOfFileComponents","");
        num_of_file_compos = stools->StringToUInt4( tmp );
    }
    for (UInt4 i=0; i<num_of_file_blocks; i++){
        std::string ind = stools->UInt4ToString( i );
        std::string path = "D4Matrix/blocks/block,i="+stools->UInt4ToString( i );
        if (bxmlp->hasPath(_KEY,path+"/filename")){
            name_of_blocks.push_back( bxmlp->PutContent(_KEY,path+"/filename","") );
        }else{

            delete bxmlp;
            return -1;
        }

        if (i==0){
            for (UInt4 j=0;j<4;j++){
                std::string target = "ax" + stools->UInt4ToString( j+1 );
                if (bxmlp->hasPath(_KEY,path+"/"+target)){
                    std::vector<std::string> arv= stools->SplitString( bxmlp->PutContent(_KEY,path+"/"+target,""), "," );
                    if (arv.size()==3){
                        range_list[j][0] = stools->StringToDouble(arv[0]);
                        range_list[j][1] = stools->StringToDouble(arv[1]);
                        range_list[j][2] = stools->StringToDouble(arv[2]);
                    }else{
                        delete bxmlp;
                        return -1;
                    }
                }else{
                    delete bxmlp;
                    return -1;
                }
            }
            index_of_blocks.push_back(0);
            if (num_of_file_blocks==1){
                index_of_blocks.push_back( UInt4( round( ( range_list[3][1]-range_list[3][0] )/range_list[3][2] ) ) );
            }
        }else{ // i!=0
            if (bxmlp->hasPath(_KEY,path+"/ax4")){
                std::vector<std::string> arv= stools->SplitString( bxmlp->PutContent(_KEY,path+"/ax4",""), "," );
                Double arv0 = stools->StringToDouble(arv[0]);
                Double arv1 = stools->StringToDouble(arv[1]);
                index_of_blocks.push_back( UInt4( round( (arv0-range_list[3][0])/range_list[3][2] ) ) );
                if (i==(num_of_file_blocks-1)){
                    range_list[3][1] = arv1;
                    index_of_blocks.push_back( UInt4( round( ( arv1-range_list[3][0] )/range_list[3][2] ) ) );
                }
            }else{
                delete bxmlp;
                return -1;
            }
        }
    }

    for (UInt4 i=0;i<4;i++){
      NumBin.push_back( (UInt4)(round((range_list[i][1]-range_list[i][0])/range_list[i][2])) );
    }

    size_of_Ax.push_back(NumBin[1]*NumBin[2]*sizeof(float)*3);
    size_of_Ax.push_back(NumBin[2]*sizeof(float)*3);
    size_of_Ax.push_back(sizeof(float)*3);
    size_of_Ax.push_back(NumBin[0]*NumBin[1]*NumBin[2]*sizeof(float)*3);
    if (isDebugMode) {
        std::cout << MessageTag << "size_of_Ax=" << size_of_Ax[0] <<","<< size_of_Ax[1] << ",";
        std::cout << size_of_Ax[2] <<","<< size_of_Ax[3] << std::endl;
    }

    std::string path = "D4Matrix/axisTitle";
    ax_titles.clear();
    ax_titles.resize(4,"");
    if (bxmlp->hasPath(_KEY,path)){
        for (UInt4 i=0; i<4; i++){
            std::string st = "ax" + stools->UInt4ToString( i+1 );
            if (bxmlp->hasPath(_KEY,path+"/"+st)){
                ax_titles[i]= bxmlp->PutContent(_KEY,path+"/"+st,"");
            }else{
                delete bxmlp;
                return -1;
            }
        }
    }

    path = "D4Matrix/axisUnit";
    ax_units.clear();
    ax_units.resize(4,"");
    if (bxmlp->hasPath(_KEY,path)){
        for (UInt4 i=0; i<4; i++){
            std::string st = "ax" + stools->UInt4ToString( i+1 );
            if (bxmlp->hasPath(_KEY,path+"/"+st)){
                ax_units[i]= bxmlp->PutContent(_KEY,path+"/"+st,"");
            }else{
                delete bxmlp;
                return -1;
            }
        }
    }

    path = "D4Matrix/fileComponents";
    file_components.clear();
    file_components.resize( num_of_file_compos,"");
    for (UInt4 i=0;i<num_of_file_compos;i++){
        std::string ind = stools->UInt4ToString( i );
        if (bxmlp->hasPath(_KEY,(path+"/filepath,i="+ind))){
            file_components[i]=bxmlp->PutContent(_KEY,(path+"/filepath,i="+ind),"");
        }else{
            UtsusemiError( MessageTag + "Invalid xml file.(missing file)");
            delete bxmlp;
            return -1;
        }
    }

    if (isDebugMode){
        for (UInt4 i=0;i<4;i++){
            std::cout << MessageTag << "range_list["<< i << "]=" << range_list[i][0];
            std::cout << "," << range_list[i][1] << "," << range_list[i][2] << std::endl;
        }
        std::cout << MessageTag << "index of blocks = ";
        std::cout << MessageTag << index_of_blocks[ 0 ] << std::endl;
        for (UInt4 i=0;i<name_of_blocks.size();i++){
            std::cout << MessageTag << "File=" << name_of_blocks[i] << std::endl;
            std::cout << MessageTag << index_of_blocks[i+1] <<std::endl;
        }
        std::cout << MessageTag << "File components " << std::endl;
        for (UInt4 i=0;i<file_components.size();i++){
            std::cout << MessageTag << file_components[i] << std::endl;
        }
        std::cout << MessageTag << "d4mat_data_dir=" << d4mat_data_dir << std::endl;
        std::cout << MessageTag << "d4mat_param_file=" << d4mat_param_file << std::endl;
    }

    delete bxmlp;
    d4mat_data_dir = datapath;
    d4mat_param_file = filename;
    return 0;

}


//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
AddMatToMat( std::string dir_from, std::string file_from, std::string dir_to, std::string file_to ){
    UtsusemiMessage( MessageTag+"Add Matrix dir="+dir_from+" to Matrix dir= "+dir_to );

    if (isFilesOpened) CloseMat();

    _isGoodResult = false;

    Int4 r1 = _ReadParamXml( dir_from, file_from );
    if (r1!=0) return;

    std::string from_d4mat_data_dir(d4mat_data_dir);
    std::string from_d4mat_param_file(d4mat_param_file);
    std::vector< std::vector<Double> > from_range_list;
    from_range_list.clear();
    for (UInt4 i=0;i<range_list.size();i++){
        std::vector<Double> tmp;
        tmp.clear();
        for (UInt4 j=0;j<range_list[i].size();j++) tmp.push_back(range_list[i][j]);
        from_range_list.push_back(tmp);
    }

    std::vector<UInt4> from_NumBin;
    from_NumBin.clear();
    for (UInt4 i=0;i<NumBin.size();i++) from_NumBin.push_back( NumBin[i] );

    std::vector<std::string> from_name_of_blocks;
    from_name_of_blocks.clear();
    for (UInt4 i=0;i<name_of_blocks.size();i++)
        from_name_of_blocks.push_back( name_of_blocks[i] );

    std::vector<UInt4> from_index_of_blocks;
    from_index_of_blocks.clear();
    for (UInt4 i=0;i<index_of_blocks.size();i++)
        from_index_of_blocks.push_back( index_of_blocks[i] );

    std::vector<std::string> from_file_components;
    from_file_components.clear();
    for (UInt4 i=0;i<file_components.size();i++)
        from_file_components.push_back( file_components[i] );

    std::vector<UInt4> from_size_of_Ax;
    std::vector<std::string> from_ax_titles;
    std::vector<std::string> from_ax_units;
    from_size_of_Ax.clear();
    from_ax_titles.clear();
    from_ax_units.clear();
    for (UInt4 i=0;i<4;i++){
        from_size_of_Ax.push_back( size_of_Ax[i] );
        from_ax_titles.push_back( ax_titles[i] );
        from_ax_units.push_back( ax_units[i] );
    }

    CloseMat();
    _ClearAllParams();

    if (isDebugMode){
        std::cout << "from_d4mat_data_dir=" << from_d4mat_data_dir << std::endl;
        std::cout << "from_d4mat_param_file=" << from_d4mat_param_file << std::endl;
        for (UInt4 i=0;i<from_range_list.size();i++){
            for (UInt4 j=0;j<from_range_list[i].size();j++){
                std::cout << "from_range_list=" << from_range_list[i][j];
                std::cout << " at " << i << "," << j << std::endl;
            }
        }
        for (UInt4 i=0;i<from_ax_titles.size();i++){
            std::cout << "title(AX" << i << ")" << from_ax_titles[i] << std::endl;
        }
    }

    if (OpenMat( dir_to, file_to )){
    }else return;

    FILE* fp;
    Double ax0,ax1,ax2,ax3;
    float *data = new float[from_NumBin[2]*3];
    UInt4 target = 0;
    UInt8 ind = 0;
    float outdata[3];

    for (UInt4 i_block = 0;i_block< from_name_of_blocks.size(); i_block++){
        std::string target_file = from_d4mat_data_dir + from_name_of_blocks[ i_block ];
        if ((fp=fopen(target_file.c_str(),"rb"))==NULL){
            UtsusemiError( MessageTag+"Cannot open file="+target_file);
            if(data) delete [] data;
            return;
        }
        UtsusemiMessage(MessageTag+"Now converting : file = "+target_file);

        for (UInt4 i3=from_index_of_blocks[i_block];i3<from_index_of_blocks[i_block+1];i3++){
            ax3 = from_range_list[3][0] + from_range_list[3][2]*((Double)(i3)+0.5);
            for (UInt4 i0=0;i0<from_NumBin[0];i0++){
                ax0 = from_range_list[0][0] + from_range_list[0][2]*((Double)(i0)+0.5);
                for (UInt4 i1=0;i1<from_NumBin[1];i1++){
                    ax1 = from_range_list[1][0] + from_range_list[1][2]*((Double)(i1)+0.5);
                    //fread( data, sizeof(data), 1, fp );
                    //if (fread( data, sizeof(float), from_NumBin[2]*3, fp)!=from_NumBin[2]*3){
                    if (fread( data, sizeof(data), 1, fp)!=1){
                        UtsusemiError( MessageTag+"Failed to read:i0,i1,i3="+stools->UInt4ToString(i0)+","+stools->UInt4ToString(i1)+","+stools->UInt4ToString(i3) );
                    }else{
                        for (UInt4 i=0;i<from_NumBin[2];i++){
                            if (data[ i*3 ]<UTSUSEMIMASKVALUE32){
                                ax2 = from_range_list[2][0] + from_range_list[2][2]*((Double)(i)+0.5);
                                if (_CalcIndex( ax0, ax1, ax2, ax3, &target, &ind )!=-1){
                                    if (fseek( fs_list[ target ], (long)ind, SEEK_SET )!=0){
                                        std::string msg = MessageTag+"Failed to SEEK:ax0,ax1,ax2,ax3=";
                                        msg += stools->DoubleToString(ax0)+","+stools->DoubleToString(ax1)+",";
                                        msg += stools->DoubleToString(ax2)+","+stools->DoubleToString(ax3);
                                        UtsusemiError( msg );
                                        continue;
                                    }
                                    if (fread( outdata, sizeof(outdata), 1, fs_list[ target ] )!=1){
                                        std::string msg = MessageTag+"Failed to READ:ax0,ax1,ax2,ax3=";
                                        msg += stools->DoubleToString(ax0)+","+stools->DoubleToString(ax1)+",";
                                        msg += stools->DoubleToString(ax2)+","+stools->DoubleToString(ax3);
                                        UtsusemiError( msg );
                                    }else{
                                        if (outdata[0]<UTSUSEMIMASKVALUE32){
                                            outdata[0] += data[ i*3 + 0 ];
                                        }else{
                                            outdata[0] = data[ i*3 + 0 ];
                                        }
                                        outdata[1] += data[ i*3 + 1 ];
                                        outdata[2] += data[ i*3 + 2 ];
                                        fseek( fs_list[ target ], -1*(Int4)sizeof(outdata), SEEK_CUR );
                                        //std::fwrite( outdata, sizeof(outdata), 1, fs_list[ target ] );
                                        if ((int)std::fwrite( outdata, sizeof(outdata), 1, fs_list[ target ] ) !=1){
                                            //usleep(50000);
                                            std::this_thread::sleep_for(std::chrono::milliseconds(50));
                                            if ((int)std::fwrite( outdata, sizeof(outdata), 1, fs_list[ target ] ) !=1){
                                                UtsusemiError( MessageTag+"Failed to write");
                                                fclose(fp);
                                                if(data) delete [] data;
                                                return;
                                            }
                                        }
                                    }

                                }
                            }
                        }
                    }

                }
            }
        }

        fclose(fp);
    }

    UtsusemiMessage( MessageTag+"file_components.size()="+stools->UInt4ToString((UInt4)(file_components.size())));
    for (UInt4 i=0;i<from_file_components.size();i++){
        UtsusemiMessage( MessageTag+"from_file_components =" + from_file_components[i]);
        file_components.push_back( from_file_components[i] );
    }

    if( (r1 = SaveParamXml( d4mat_data_dir, d4mat_param_file ))!=0 ){
        UtsusemiError( MessageTag+"Cannot write XML file." );
    }

    CloseMat();
    _ClearAllParams();

    UtsusemiMessage( MessageTag+"Converting completed." );
    _isGoodResult = true;
}


//////////////////////////////////////////////////////////////////////
std::vector<std::string> UtsusemiD4Matrix::
PutOpenedDataPath(){
    std::vector<std::string> ret;
    ret.clear();

    if (isFilesOpened){
        ret.push_back( d4mat_data_dir );
        ret.push_back( d4mat_param_file );
    }else{
        ret.push_back("Not opened");
    }

    return ret;
}

//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
GetPartOfD4Mat( UInt4 fs_index, float data[], UInt4 top_posi, UInt4 num_to_get){
    //std::cout << "@@@ GetPartOfD4Mat start fs_index="<<fs_index << std::endl;
    if (fs_index>(fs_list.size()-1)){
        UtsusemiError( MessageTag + " fs_index is too large." );
        return -1;
    }

    if (isFilesOpened){
        UInt4 ind = top_posi*sizeof(float)*3;
        if (fseek( fs_list[ fs_index ], ind , SEEK_SET )!=0){
            UtsusemiError( MessageTag + "Top_posi is over size of data" );
            return -2;
        }

        Int4 ret = (Int4)( fread( data, sizeof(float)*3, num_to_get, fs_list[ fs_index ] ) );

        return ret;
    }else{
        UtsusemiError( MessageTag + " Files are not opened. " );
        return -3;
    }
}
//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
    SliceMat3D( ElementContainerMatrix* _ecm, std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings, std::vector<std::string> key_axes ){
    _isGoodResult = _SliceMat(_ecm, 3, a1range, a2range, a3range, a4range, def_axes, foldings, key_axes);

    if (_isGoodResult) return 0;
    else return -1;
}
//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
OutputText3D( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings, std::string filename, bool isIgnoreMaskVal, std::string maskValStr){
    ElementContainerMatrix* _ecm = new ElementContainerMatrix();
    std::vector<std::string> key_axes(3);
    key_axes[0] = "XX";
    key_axes[1] = "YY";
    key_axes[2] = "ZZ";
    _isGoodResult = _SliceMat(_ecm, 3, a1range, a2range, a3range, a4range, def_axes, foldings, key_axes);
    if (!_isGoodResult) return -1;

    std::vector< std::vector<Double> > ArList;
    std::vector<UInt4> def_ind,NumList;
    if (_CalcRangeInfo( 3, a1range, a2range, a3range, a4range, def_axes, def_ind, ArList, NumList )){
    }else{
        return -2;
    }

    UInt4 indX = def_ind[0];
    UInt4 indY = def_ind[1];
    UInt4 indZ = def_ind[2];
    UInt4 n_X = NumList[0];
    UInt4 n_Y = NumList[1];
    UInt4 n_Z = NumList[2];

    std::vector<Double> oxArray(n_X,0.0);
    std::vector<Double> oyArray(n_Y,0.0);
    std::vector<Double> ozArray(n_Z,0.0);

    for (UInt4 i=0; i<n_X; i++)
        oxArray[i] = ArList[indX][0] + ArList[indX][2]*(double(i)+0.5);

    for (UInt4 i=0; i<n_Y; i++)
        oyArray[i] = ArList[indY][0] + ArList[indY][2]*(double(i)+0.5);

    for (UInt4 i=0; i<n_Z; i++)
        ozArray[i] = ArList[indZ][0] + ArList[indZ][2]*(double(i)+0.5);

    Double outMaskVal = UTSUSEMIMASKVALUE64;
    if (isIgnoreMaskVal){
    }else{
        if (maskValStr.find("MASK")==std::string::npos)
            outMaskVal = stools->StringToDouble( maskValStr );
    }

    FILE *fp;
    fp = fopen( filename.c_str(), "w" );
    if (fp == NULL){
        UtsusemiError( MessageTag+"OutputText3D : Failed to open "+filename );
        return -3;
    }
   std::fprintf( fp, "# XRANGE=%f, %f, %f, %f\n", oxArray[0], oxArray[ n_X-1 ], ArList[indX][2], (Double)(n_X) );
   std::fprintf( fp, "# YRANGE=%f, %f, %f, %f\n", oyArray[0], oyArray[ n_Y-1 ], ArList[indY][2], (Double)(n_Y) );
   std::fprintf( fp, "# ZRANGE=%f, %f, %f, %f\n", ozArray[0], ozArray[ n_Z-1 ], ArList[indZ][2], (Double)(n_Z) );
    for (UInt4 ix=0;ix<n_X;ix++){
        for (UInt4 iy=0;iy<n_Y;iy++){
            ElementContainer* ec = _ecm->PutPointer(ix)->PutPointer(iy);
            std::vector<Double>* ii = (*ec)( ec->PutYKey() );
            std::vector<Double>* ee = (*ec)( ec->PutEKey() );
            for (UInt4 iz=0;iz<n_Z;iz++){
                if (ee->at(iz)>=0.0){
                   std::fprintf( fp, "%f, %f, %f, %g, %g\n", oxArray[ix], oyArray[iy], ozArray[iz], ii->at(iz), ee->at(iz) );
                }else if (isIgnoreMaskVal){
                }else{
                   std::fprintf( fp, "%f, %f, %f, %g, %g\n", oxArray[ix], oyArray[iy], ozArray[iz],outMaskVal, 0.0 );
                }
            }
        }
    }
    fclose(fp);

    delete _ecm;

    return 0;
}
//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
DumpD4MatToFile( std::vector<Double> a1range, std::vector<Double> a2range, std::vector<Double> a3range, std::vector<Double> a4range, std::vector<std::string> def_axes, std::vector<Double> foldings, std::string filename, bool isText, bool isAve ){
    // a1range has 2 double min and max
    if (!isFilesOpened) _OpenFiles();

    std::vector< std::vector<Double> > ArList;
    std::vector<UInt4> def_ind,NumList;
    if (_CalcRangeInfo( 4, a1range, a2range, a3range, a4range, def_axes, def_ind, ArList, NumList )){
    }else{
        return -1;
    }

    UInt4 indX = def_ind[0];
    UInt4 indY = def_ind[1];
    UInt4 indZ = def_ind[2];
    UInt4 indT = def_ind[3];
    UInt4 n_X = NumList[0];
    UInt4 n_Y = NumList[1];
    UInt4 n_Z = NumList[2];
    UInt4 n_T = NumList[3];

    if (foldings.empty()) foldings.resize(4,-1.0);
    std::vector<Double> oxArray, oyArray, ozArray, otArray;
    oxArray.resize(n_X);
    oyArray.resize(n_Y);
    ozArray.resize(n_Z);
    otArray.resize(n_T);

    for (UInt4 i=0; i<n_X; i++)
        oxArray[i] = ArList[indX][0] + ArList[indX][2]*(double(i)+0.5);

    for (UInt4 i=0; i<n_Y; i++)
        oyArray[i] = ArList[indY][0] + ArList[indY][2]*(double(i)+0.5);

    for (UInt4 i=0; i<n_Z; i++)
        ozArray[i] = ArList[indZ][0] + ArList[indZ][2]*(double(i)+0.5);

    for (UInt4 i=0; i<n_T; i++)
        otArray[i] = ArList[indT][0] + ArList[indT][2]*(double(i)+0.5);

    FILE *fp;
    if (isText){
        fp = fopen( filename.c_str(), "w" );
       std::fprintf( fp, "# XRANGE=%f, %f, %f, %f\n", oxArray[0], oxArray[ n_X-1 ], ArList[indX][2], (Double)(n_X) );
       std::fprintf( fp, "# YRANGE=%f, %f, %f, %f\n", oyArray[0], oyArray[ n_Y-1 ], ArList[indY][2], (Double)(n_Y) );
       std::fprintf( fp, "# ZRANGE=%f, %f, %f, %f\n", ozArray[0], ozArray[ n_Z-1 ], ArList[indZ][2], (Double)(n_Z) );
       std::fprintf( fp, "# TRANGE=%f, %f, %f, %f\n", otArray[0], otArray[ n_T-1 ], ArList[indT][2], (Double)(n_T) );
    }else{
        fp = fopen( filename.c_str(), "wb" );
    }

    std::vector<UInt4> iXs(4,0);

    // scan all range in axis AX4
    for (UInt4 iX3=0; iX3<NumBin[3]; iX3++){
        Double x3 = range_list[3][0] + range_list[3][2]*(double(iX3)+0.5);
        Double x3f = 0.0;
        if (foldings[3]==0.0) x3f = fabs(x3);
        else if (foldings[3]>0.0){
            if ( (foldings[3]<=fabs(x3))&&(fabs(x3)<=(2.0*foldings[3])) ) x3f = 2.0*foldings[3] - fabs(x3);
            else if ( ((-1.0*foldings[3])<x3)&&(x3<foldings[3]) ) x3f = fabs(x3);
        }else x3f = x3;

        if ( (x3f<ArList[3][0])||(x3f>=ArList[3][1]) ) continue;

        UInt4 ind3 = iX3 * size_of_Ax[3];
        UInt4 file_target = 0;
        for (UInt4 j=0;j<(index_of_blocks.size()-1);j++){
            if ( (iX3>=index_of_blocks[j])&&(iX3<index_of_blocks[j+1]) ) {
                file_target = j;
                ind3 = (iX3 - index_of_blocks[j])*size_of_Ax[3];
                break;
            }
        }

        iXs[3] = (UInt4)((x3f - ArList[3][0])/ArList[3][2]);

        // scan all range in axis AX0
        for (UInt4 iX0=0; iX0<NumBin[0]; iX0++){
            Double x0 = range_list[0][0] + range_list[0][2]*(double(iX0)+0.5);
            Double x0f = 0.0;
            if (foldings[0]==0.0) x0f = fabs(x0);
            else if (foldings[0]>0.0){
                if ( (foldings[0]<=fabs(x0))&&(fabs(x0)<=(2.0*foldings[0])) ) x0f = 2.0*foldings[0] - fabs(x0);
                else if ( ((-1.0*foldings[0])<x0)&&(x0<foldings[0]) ) x0f = fabs(x0);
            }else x0f = x0;

            if ( (x0f<ArList[0][0])||(x0f>=ArList[0][1]) ) continue;

            UInt4 ind0 = iX0 * size_of_Ax[0];

            iXs[0] = (UInt4)((x0f - ArList[0][0])/ArList[0][2]);

            // scan all range in axis AX1
            for (UInt4 iX1=0; iX1<NumBin[1]; iX1++){
                Double x1 = range_list[1][0] + range_list[1][2]*(double(iX1)+0.5);
                Double x1f = 0.0;
                if (foldings[1]==0.0) x1f = fabs(x1);
                else if (foldings[1]>0.0){
                    if ( (foldings[1]<=fabs(x1))&&(fabs(x1)<=(2.0*foldings[1])) ) x1f = 2.0*foldings[1] - fabs(x1);
                    else if ( ((-1.0*foldings[1])<x1)&&(x1<foldings[1]) ) x1f = fabs(x1);
                }else x1f = x1;

                if ( (x1f<ArList[1][0])||(x1f>=ArList[1][1]) ) continue;

                UInt4 ind1 = iX1 * size_of_Ax[1];

                iXs[1] = (UInt4)((x1f - ArList[1][0])/ArList[1][2]);


                // scan all range in axis AX2
                for (UInt4 iX2=0; iX2<NumBin[2]; iX2++){
                    Double x2 = range_list[2][0] + range_list[2][2]*(double(iX2)+0.5);
                    Double x2f = 0.0;
                    if (foldings[2]==0.0) x2f = fabs(x2);
                    else if (foldings[2]>0.0){
                        if ( (foldings[2]<=fabs(x2))&&(fabs(x2)<=(2.0*foldings[2])) ) x2f = 2.0*foldings[2] - fabs(x2);
                        else if ( ((-1.0*foldings[2])<x2)&&(x2<foldings[2]) ) x2f = fabs(x2);
                    }else x2f = x2;

                    if ( (x2f<ArList[2][0])||(x2f>=ArList[2][1]) ) continue;
                    UInt4 ind2 = iX2 * size_of_Ax[2];

                    iXs[2] = (UInt4)((x2f - ArList[2][0])/ArList[2][2]);

                    UInt4 ind = ind0 + ind1 + ind2 + ind3;
                    float dat[3];
                    fseek( fs_list[ file_target ], ind, SEEK_SET );
                    if ((int)fread( dat, sizeof(dat), 1, fs_list[ file_target ] )!=1){
                        UtsusemiError(MessageTag + "SliceMat failed to read data");
                    }else{
                        float xx = (float)oxArray[ iXs[indX] ];
                        float yy = (float)oyArray[ iXs[indY] ];
                        float zz = (float)ozArray[ iXs[indZ] ];
                        float tt = (float)otArray[ iXs[indT] ];
                        float ii = 0.0;
                        float ee = 0.0;
                        if ((dat[2]!=0.0)&&(isAve)){
                            ii=dat[0]/dat[2];
                            ee=sqrt( dat[1] )/dat[2];
                        }else{
                            ii=dat[0];
                            ee=sqrt( dat[1] );
                        }
                        if (isText)
                           std::fprintf( fp, "%f, %f, %f, %f, %g, %g\n", xx, yy, zz, tt, ii, ee );
                        else{
                            std::fwrite( &xx, sizeof(xx), 1, fp );
                            std::fwrite( &yy, sizeof(yy), 1, fp );
                            std::fwrite( &zz, sizeof(zz), 1, fp );
                            std::fwrite( &tt, sizeof(tt), 1, fp );
                            std::fwrite( &ii, sizeof(ii), 1, fp );
                            std::fwrite( &ee, sizeof(ee), 1, fp );
                        }
                    }
                } // Loop NumBin[2]
            }// Loop NumBin[1]
        }// Loop NumBin[0]
    }// Loop NumBin[3]

    fclose(fp);

    return 0;
}
//////////////////////////////////////////////////////////////////////
Int4 UtsusemiD4Matrix::
DumpD4MatIntoVect( std::vector<Double> a1r, std::vector<Double> a2r, std::vector<Double> a3r, std::vector<Double> a4r, std::vector<std::string> def_axes, std::vector<Double> foldings, bool isAve,
                   std::vector<Double> *ax1, std::vector<Double> *ax2, std::vector<Double> *ax3, std::vector<Double> *hws, std::vector<Double> *intensity, std::vector<Double> *error){
    // a1range has 2 double min and max
    if (!isFilesOpened) _OpenFiles();

    std::vector< std::vector<Double> > ArList;
    std::vector<UInt4> def_ind,NumList;
    if (_CalcRangeInfo( 4, a1r, a2r, a3r, a4r, def_axes, def_ind, ArList, NumList )){
    }else{
        return -1;
    }

    UInt4 indX = def_ind[0];
    UInt4 indY = def_ind[1];
    UInt4 indZ = def_ind[2];
    UInt4 indT = def_ind[3];
    UInt4 n_X = NumList[0];
    UInt4 n_Y = NumList[1];
    UInt4 n_Z = NumList[2];
    UInt4 n_T = NumList[3];

    if (foldings.empty()) foldings.resize(4,-1.0);
    //std::vector<Double> oxArray, oyArray, ozArray, otArray;
    ax1->resize(n_X);
    ax2->resize(n_Y);
    ax3->resize(n_Z);
    hws->resize(n_T);
    intensity->resize(n_X * n_Y * n_Z * n_T);
    error->resize(n_X * n_Y * n_Z * n_T);

    for (UInt4 i=0; i<n_X; i++)
        ax1->at(i) = ArList[indX][0] + ArList[indX][2]*(double(i)+0.5);

    for (UInt4 i=0; i<n_Y; i++)
        ax2->at(i) = ArList[indY][0] + ArList[indY][2]*(double(i)+0.5);

    for (UInt4 i=0; i<n_Z; i++)
        ax3->at(i) = ArList[indZ][0] + ArList[indZ][2]*(double(i)+0.5);

    for (UInt4 i=0; i<n_T; i++)
        hws->at(i) = ArList[indT][0] + ArList[indT][2]*(double(i)+0.5);

    std::vector<UInt4> iXs(4,0);

    // scan all range in axis AX4
    UInt4 index_of_intensity = 0.0;
    for (UInt4 iX3=0; iX3<NumBin[3]; iX3++){
        Double x3 = range_list[3][0] + range_list[3][2]*(double(iX3)+0.5);
        Double x3f = 0.0;
        if (foldings[3]==0.0) x3f = fabs(x3);
        else if (foldings[3]>0.0){
            if ( (foldings[3]<=fabs(x3))&&(fabs(x3)<=(2.0*foldings[3])) ) x3f = 2.0*foldings[3] - fabs(x3);
            else if ( ((-1.0*foldings[3])<x3)&&(x3<foldings[3]) ) x3f = fabs(x3);
        }else x3f = x3;

        if ( (x3f<ArList[3][0])||(x3f>=ArList[3][1]) ) continue;

        UInt4 ind3 = iX3 * size_of_Ax[3];
        UInt4 file_target = 0;
        for (UInt4 j=0;j<(index_of_blocks.size()-1);j++){
            if ( (iX3>=index_of_blocks[j])&&(iX3<index_of_blocks[j+1]) ) {
                file_target = j;
                ind3 = (iX3 - index_of_blocks[j])*size_of_Ax[3];
                break;
            }
        }

        iXs[3] = (UInt4)((x3f - ArList[3][0])/ArList[3][2]);

        // scan all range in axis AX0
        for (UInt4 iX0=0; iX0<NumBin[0]; iX0++){
            Double x0 = range_list[0][0] + range_list[0][2]*(double(iX0)+0.5);
            Double x0f = 0.0;
            if (foldings[0]==0.0) x0f = fabs(x0);
            else if (foldings[0]>0.0){
                if ( (foldings[0]<=fabs(x0))&&(fabs(x0)<=(2.0*foldings[0])) ) x0f = 2.0*foldings[0] - fabs(x0);
                else if ( ((-1.0*foldings[0])<x0)&&(x0<foldings[0]) ) x0f = fabs(x0);
            }else x0f = x0;

            if ( (x0f<ArList[0][0])||(x0f>=ArList[0][1]) ) continue;

            UInt4 ind0 = iX0 * size_of_Ax[0];

            iXs[0] = (UInt4)((x0f - ArList[0][0])/ArList[0][2]);

            // scan all range in axis AX1
            for (UInt4 iX1=0; iX1<NumBin[1]; iX1++){
                Double x1 = range_list[1][0] + range_list[1][2]*(double(iX1)+0.5);
                Double x1f = 0.0;
                if (foldings[1]==0.0) x1f = fabs(x1);
                else if (foldings[1]>0.0){
                    if ( (foldings[1]<=fabs(x1))&&(fabs(x1)<=(2.0*foldings[1])) ) x1f = 2.0*foldings[1] - fabs(x1);
                    else if ( ((-1.0*foldings[1])<x1)&&(x1<foldings[1]) ) x1f = fabs(x1);
                }else x1f = x1;

                if ( (x1f<ArList[1][0])||(x1f>=ArList[1][1]) ) continue;

                UInt4 ind1 = iX1 * size_of_Ax[1];

                iXs[1] = (UInt4)((x1f - ArList[1][0])/ArList[1][2]);


                // scan all range in axis AX2
                for (UInt4 iX2=0; iX2<NumBin[2]; iX2++){
                    Double x2 = range_list[2][0] + range_list[2][2]*(double(iX2)+0.5);
                    Double x2f = 0.0;
                    if (foldings[2]==0.0) x2f = fabs(x2);
                    else if (foldings[2]>0.0){
                        if ( (foldings[2]<=fabs(x2))&&(fabs(x2)<=(2.0*foldings[2])) ) x2f = 2.0*foldings[2] - fabs(x2);
                        else if ( ((-1.0*foldings[2])<x2)&&(x2<foldings[2]) ) x2f = fabs(x2);
                    }else x2f = x2;

                    if ( (x2f<ArList[2][0])||(x2f>=ArList[2][1]) ) continue;
                    UInt4 ind2 = iX2 * size_of_Ax[2];

                    iXs[2] = (UInt4)((x2f - ArList[2][0])/ArList[2][2]);

                    UInt4 ind = ind0 + ind1 + ind2 + ind3;
                    float dat[3];
                    fseek( fs_list[ file_target ], ind, SEEK_SET );
                    if ((int)fread( dat, sizeof(dat), 1, fs_list[ file_target ] )!=1){
                        UtsusemiError(MessageTag + "SliceMat failed to read data");
                    }else{
                        Double ii = 0.0;
                        Double ee = 0.0;
                        if ((dat[2]!=0.0)&&(isAve)){
                            ii=dat[0]/dat[2];
                            ee=sqrt( dat[1] )/dat[2];
                        }else{
                            ii=dat[0];
                            ee=sqrt( dat[1] );
                        }
                        index_of_intensity = iXs[indT] + n_T * (iXs[indZ] + n_Z * (iXs[indY] + (n_Y * iXs[indX])));
                        if (index_of_intensity < (intensity -> size())){
                            intensity -> at(index_of_intensity) = ii;
                            error -> at(index_of_intensity) = ee;
                        }else{
                            UtsusemiError(MessageTag + "index_of_intensity is too large :" + stools->UInt4ToString(index_of_intensity));
                        }
                        /*
                        intensity -> at(index_of_intensity) = ii;
                        error -> at(index_of_intensity) = ee;
                        index_of_intensity++;
                        */
                    }
                } // Loop NumBin[2]
            }// Loop NumBin[1]
        }// Loop NumBin[0]
    }// Loop NumBin[3]

    return 0;
}
//////////////////////////////////////////////////////////////////////
const Int4 UtsusemiD4Matrix::ROTATE_AXIS_X = UtsusemiSqeCalc2::ROTATE_AXIS_X;
const Int4 UtsusemiD4Matrix::ROTATE_AXIS_Y = UtsusemiSqeCalc2::ROTATE_AXIS_Y;
const Int4 UtsusemiD4Matrix::ROTATE_AXIS_Z = UtsusemiSqeCalc2::ROTATE_AXIS_Z;
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
AllocateNewMat( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range,
                PyObject* titles, PyObject* units, std::string data_dir, std::string paramfile ){
    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    std::vector< std::string > TTS = __gCppToPython.ListToStringVector( titles );
    std::vector< std::string > UNT = __gCppToPython.ListToStringVector( units );
    AllocateNewMat(AX1,AX2,AX3,AX4,TTS,UNT,data_dir,paramfile);
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
Slice2d( ElementContainerArray* _eca, PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings ){
    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    std::vector< std::string > DEF = __gCppToPython.ListToStringVector( def_axes );
    std::vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    SliceMat( AX1, AX2, AX3, AX4, DEF, FLD );

    if ( (_isGoodResult)&&(_eca!=NULL) ){
        _eca->AddToHeader(UTSUSEMI_KEY_HEAD_ISHISTOGRAM,0);
        _eca->AddToHeader(MLF_KEY_HEAD_XUNIT,ax_units[_AxisDefIndex[0]]);
        _eca->Allocate( (UInt4)(XArray.size())-1 );
        for (UInt4 i=0;i<(XArray.size()-1);i++){
            std::vector<Double> v_int = PutSliceResults(0,i);
            std::vector<Double> v_err = PutSliceResults(1,i);
            ElementContainer* ec = new ElementContainer();
            std::vector<Double> xrange;
            xrange.push_back(XArray[i]);
            xrange.push_back(XArray[i+1]);
            ec->AddToHeader(UTSUSEMI_KEY_HEAD_XRANGE,xrange);
            ec->AddToHeader(MLF_KEY_HEAD_XUNIT,ax_units[_AxisDefIndex[0]]);
            ec->Add("Y",YArray,ax_units[_AxisDefIndex[1]]);
            ec->Add(UTSUSEMI_KEY_INTENSITY,v_int,UTSUSEMI_KEY_ARB_UNIT);
            ec->Add(UTSUSEMI_KEY_ERROR,v_err,UTSUSEMI_KEY_ARB_UNIT);
            ec->SetKeys("Y",UTSUSEMI_KEY_INTENSITY,UTSUSEMI_KEY_ERROR);
            _eca->Set(i,ec);
        }
    }
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
ElementContainerArray UtsusemiD4Matrix::
Slice2d( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings ){
    ElementContainerArray* _eca = new ElementContainerArray();
    if ( Slice2d( _eca, a1range, a2range, a3range, a4range, def_axes, foldings ) ) return *_eca;
    else{
        UtsusemiError( MessageTag+"Slice2d >> Failed. return empty ElementContainerArray." );
        return *_eca;
    }
}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SetAxTitles(PyObject* titles, bool isSaved ){
    std::vector< std::string > TTS = __gCppToPython.ListToStringVector( titles );
    SetAxTitles( TTS, isSaved );
}
//////////////////////////////////////////////////////////////////////
void UtsusemiD4Matrix::
SetAxUnits(PyObject* units, bool isSaved ){
    std::vector< std::string > UTS = __gCppToPython.ListToStringVector( units );
    SetAxUnits( UTS, isSaved );
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
Slice3d( ElementContainerMatrix* _ecm, PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, PyObject* key_axes ){
    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    std::vector< std::string > DEF = __gCppToPython.ListToStringVector( def_axes );
    std::vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    std::vector< std::string > KYS = __gCppToPython.ListToStringVector( key_axes );
    if (0==SliceMat3D( _ecm, AX1, AX2, AX3, AX4, DEF, FLD, KYS )) return true;
    else return false;
}
//////////////////////////////////////////////////////////////////////
ElementContainerMatrix UtsusemiD4Matrix::
Slice3d( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, PyObject* key_axes ){
    ElementContainerMatrix* _ecm = new ElementContainerMatrix();
    if ( Slice3d( _ecm, a1range, a2range, a3range, a4range, def_axes, foldings, key_axes ) ) return *_ecm;
    else{
        UtsusemiError( MessageTag+"Slice3d >> Failed. return empty ElementContainerMatrix." );
        return *_ecm;
    }
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
OutputText3D( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, std::string filename, bool isIgnoreMaskVal, std::string maskValStr  ){
    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    std::vector< std::string > DEF = __gCppToPython.ListToStringVector( def_axes );
    std::vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    if (0==OutputText3D( AX1, AX2, AX3, AX4, DEF, FLD, filename, isIgnoreMaskVal, maskValStr )) return true;
    else return false;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
DumpD4MatToFile( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, std::string filename, bool isText, bool isAve ){
    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    std::vector< std::string > DEF = __gCppToPython.ListToStringVector( def_axes );
    std::vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    if (0== DumpD4MatToFile( AX1, AX2, AX3, AX4, DEF, FLD, filename, isText, isAve )) return true;
    else return false;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
DumpD4MatIntoVect( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, bool isAve,
                   std::vector<Double> *ax1, std::vector<Double> *ax2, std::vector<Double> *ax3, std::vector<Double> *ax4, std::vector<Double> *intensity, std::vector<Double> *error){
    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    std::vector< std::string > DEF = __gCppToPython.ListToStringVector( def_axes );
    std::vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    if (0 == DumpD4MatIntoVect( AX1, AX2, AX3, AX4, DEF, FLD, isAve, ax1, ax2, ax3, ax4, intensity, error )) return true;
    else return false;
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
AllocateVirtualMat( PyObject* latticeConst, PyObject* Uvec, PyObject* Vvec,
                    PyObject* rotateSteps, PyObject* viewAxes, PyObject* phiSteps,
                    PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* titles, PyObject* units ){
    _isGoodResult = false;
    if (_hwInfoForVirtualMatrix.empty()){
        UtsusemiError(MessageTag+"AllocateVirtualMat >> Not executed SetRunNoForVirtualMatrix ");
        return false;
    }
    std::vector< Double > LC = __gCppToPython.ListToDoubleVector( latticeConst );
    std::vector< Double > UV = __gCppToPython.ListToDoubleVector( Uvec );
    std::vector< Double > VV = __gCppToPython.ListToDoubleVector( Vvec );
    std::vector< Double > RS = __gCppToPython.ListToDoubleVector( rotateSteps );
    std::vector< Double > VA = __gCppToPython.ListToDoubleVector( viewAxes );
    std::vector< Double > PHV = __gCppToPython.ListToDoubleVector( phiSteps );

    std::vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    std::vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    std::vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    std::vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    std::vector< std::string > TTS = __gCppToPython.ListToStringVector( titles );
    std::vector< std::string > UNT = __gCppToPython.ListToStringVector( units );

    AllocateVirtualMat( LC, UV, VV, RS, VA, _hwInfoForVirtualMatrix, PHV, AX1, AX2, AX3, AX4, TTS, UNT );

    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
PyObject* UtsusemiD4Matrix::
EstimateRangeOfVirtualMat(PyObject* latticeConst, PyObject* Uvec, PyObject* Vvec,
                         PyObject* rotateSteps, PyObject* viewAxes, PyObject* phiSteps ){
    if (_hwInfoForVirtualMatrix.empty()){
        UtsusemiError(MessageTag+"AllocateVirtualMat >> Not executed SetRunNoForVirtualMatrix ");
        std::vector<Double> ret_empty;
        return __gCppToPython.VectorDoubleToList(ret_empty);
    }
    std::vector< Double > LC = __gCppToPython.ListToDoubleVector( latticeConst );
    std::vector< Double > UV = __gCppToPython.ListToDoubleVector( Uvec );
    std::vector< Double > VV = __gCppToPython.ListToDoubleVector( Vvec );
    std::vector< Double > RS = __gCppToPython.ListToDoubleVector( rotateSteps );
    std::vector< Double > VA = __gCppToPython.ListToDoubleVector( viewAxes );
    std::vector< Double > PHV = __gCppToPython.ListToDoubleVector( phiSteps );
    return __gCppToPython.VectorDoubleToList( EstimateRangeOfVirtualMat( LC, UV, VV, RS, VA, _hwInfoForVirtualMatrix, PHV ) );
}
//////////////////////////////////////////////////////////////////////
bool UtsusemiD4Matrix::
SetRunNoForVirtualMatrix( UInt4 runNo, PyObject* hwInfo ){
    std::vector< Double > HWI = __gCppToPython.ListToDoubleVector( hwInfo );
    if (HWI.size()!=4){
        UtsusemiError( MessageTag+"SetRunNoForVirtualMatrix >> Invalid arguments for inelastic scattering " );
        return false;
    }
    UtsusemiGetNeunetHistogram UGH;
    if (UGH.SetRunNo(runNo)){
        UGH.SetDetParam("psd");
        char hist_param_c[100];
        std::snprintf( hist_param_c, sizeof(hist_param_c), "hw,%f,%f,%f,%f", HWI[0], HWI[2],HWI[3],HWI[1] ); // "hw, Ei, hw_min, hw_max, hw_delta"
        std::string hist_param(hist_param_c);
        if (UGH.SetConversionParameter( hist_param )){
            std::vector<std::string> pfiles = UGH.MakeTempInfoFiles();
            _CalcVirtualAngleInfo( pfiles[0], pfiles[1] );
        }else{
            UtsusemiError( MessageTag+"SetRunNoForVirtualMatrix >> Invalid arguments for inelastic scattering " );
            return false;
        }
    }else{
        UtsusemiError( MessageTag+"SetRunNoForVirtualMatrix >> Invalid RunNo argument " );
        return false;
    }

    _hwInfoForVirtualMatrix.clear();
    for (UInt4 i=0; i<HWI.size(); i++) _hwInfoForVirtualMatrix.push_back( HWI[i] );

    return true;
}
