#include "D4Matrix.hh"

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

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

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

//////////////////////////////////////////////////////////////////////
void D4Matrix::
_Initialize(){
    MessageTag = "D4Matrix >> ";
    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;
    
    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);

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

//////////////////////////////////////////////////////////////////////
void D4Matrix::
SetMaxSizeOfBlock( Double _size ){
    if (_size<0.0) return;
    if (_size>2000.0) _size = 2000.0;
    MAX_SIZE_OF_ONE_BLOCK = _size;
}
//////////////////////////////////////////////////////////////////////
void D4Matrix::
AllocateNewMat( vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> titles, string data_dir, 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] );
    }
    
    
    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{
            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){
        cout << MessageTag << "one_plane_size=" << one_plane_size << "MB" << endl;
        cout << MessageTag << "MAX_SIZE_ONE_BLOCK=" << MAX_SIZE_OF_ONE_BLOCK << endl;
        cout << MessageTag << "MAX_SIZE_OF_ONE_BLOCK/one_plane_size = ";
        cout << MessageTag << (MAX_SIZE_OF_ONE_BLOCK/one_plane_size) << endl;
        cout << MessageTag << "num_of_blocks=" << num_of_blocks << endl;
    }

    string data_name_base( paramfile );

    string::size_type ind = paramfile.find_last_of(".xml");
    if (ind == 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 )!=string("/")){
        d4mat_data_dir = data_dir+"/";
    }else{
        d4mat_data_dir = string( data_dir );
    }
    
    for (UInt4 i=0;i<NumBin[3];i+=num_of_blocks){
        index_of_blocks.push_back(i);
        char ff[10];
        sprintf( ff,"%05d", i );
        string fst = ff;
        string fname = data_name_base+"_"+fst+".bin";
        if (isDebugMode) cout << MessageTag << "fname=" << fname<< 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++){
        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)fwrite( data, sizeof(data), 1, fp ) !=1){
                            usleep(50000);
                            if ((int)fwrite( data, sizeof(data), 1, fp ) !=1){
                                UtsusemiError( MessageTag+"AllocateNewMat > Failed to write");
                                return;
                            }        
                        }
                    }
                }
            }
        }
        fclose( fp );
    }
    _isGoodResult = true;
    return;
}


//////////////////////////////////////////////////////////////////////
void D4Matrix::
AllocateVirtualMat( vector<Double> latticeConst, vector<Double> Uvec, vector<Double> Vvec, vector<Double> rotateSteps, 
                    vector<Double> viewAxes, vector<Double> hwInfo, vector<Double> phiSteps,
                    vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> titles ){
    _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] );
    }

    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{
            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){
        cout << MessageTag << "NumBin = " << NumBin[0] << "," << NumBin[1] << "," << NumBin[2] << "," << NumBin[3] << endl;
        cout << MessageTag << "size_of_Ax=" << size_of_Ax[0] <<","<< size_of_Ax[1] << ","<< size_of_Ax[2] <<","<< size_of_Ax[3] << endl;
    }

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

    for (UInt4 i=0; i<NumBin[3]; i++) _VirtualD4Mat->at(i)=new vector<float>( size_of_Ax[3],0.0 );
    bool isDirectGeometry = true;
    
    Double Ei = hwInfo[0];
    Double delta_hw = hwInfo[1];
    
    vector<Double> hw_range= CalcRangeAsBinCenterZero( hwInfo[2], hwInfo[3], delta_hw );
    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){
        cout << "-----------------------" << endl;
        cout << "Ei="<<Ei<<", dhw="<<delta_hw<<endl;
        for (UInt4 i=0; i<hw_list.size(); i++)
            cout << hw_list[i]<<",";
        cout << endl;
        
        for (UInt4 i=0;i<latticeConst.size();i++) cout << latticeConst[i] << ",";
        cout << endl;
        for (UInt4 i=0;i<Uvec.size();i++) cout << Uvec[i] << ",";
        cout << endl;
        for (UInt4 i=0;i<Vvec.size();i++) cout << Vvec[i] << ",";
        cout << endl;
        for (UInt4 i=0;i<viewAxes.size();i++) cout << viewAxes[i] << ",";
        cout << 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]);
        }
        //cout << "i_phi="<<i_phi<<", phi="<<phiSteps[i_phi]<<endl;
        UtsusemiSqeCalc* VCS = new UtsusemiSqeCalc();
        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!!
        vector<Double> Efs( _VirtualAngleInfo.size(), 0.0 );


#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];
            }
            
            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];
                
                UInt4 i_Vw = (UInt4)( float( (Vw - range_list[3][0])/range_list[3][2] ) );
                if (i_Vw>=NumBin[3]) {
                    //cout << "i_Vw is over, Vw="<<Vw<<", i_Vw="<<i_Vw<<endl;
                    continue;
                }
                UInt8 ind;
                if (_CalcIndexVirtual( Vx, Vy, Vz, &ind )==-1) continue;
                if (ind>=(_VirtualD4Mat->at(i_Vw)->size())){
                    //cout << "ind is over, ind="<<ind<<",size="<<_VirtualD4Mat->at(i_Vw)->size()<<endl;
                    //cout << "Vx="<<Vx<<", Vy="<<Vy<<",Vz="<<Vz<<",Vw="<<Vw<<endl;
                    //cout << "hw="<<hw<<",phi="<<phiSteps[i_phi]<<endl;
                }else{
                    _VirtualD4Mat->at(i_Vw)->at(ind) ++;
                }
            }
        }
    }
    delete UCC;
    _isGoodResult = true;
    _isVirtual=true;
    return;
}
//////////////////////////////////////////////////////////////////////
vector<Double> D4Matrix::
EstimateRangeOfVirtualMat( vector<Double> latticeConst, vector<Double> Uvec, vector<Double> Vvec, vector<Double> rotateSteps, 
                          vector<Double> viewAxes, vector<Double> hwInfo, vector<Double> phiSteps ){
    _isGoodResult = false;
    bool isDirectGeometry = true;
    
    UtsusemiUnitConverter* UCC = new UtsusemiUnitConverter();
    Double Ei = hwInfo[0];
    Double delta_hw = hwInfo[1];
    
    vector<Double> hw_range= CalcRangeAsBinCenterZero( hwInfo[2], hwInfo[3], delta_hw );
    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

    vector< vector<Double>* > _Ranges( NumOfMulTh );
    for (UInt4 i=0; i<NumOfMulTh; i++){
        _Ranges[i] = new 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]);
        }
        //cout << "i_phi="<<i_phi<<", phi="<<phiSteps[i_phi]<<endl;
        UtsusemiSqeCalc* VCS = new UtsusemiSqeCalc();
        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!!
        vector<Double> Efs( _VirtualAngleInfo.size(), 0.0 );


#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];
            }
            
            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];
                
                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;
    
    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 D4Matrix::
_CalcVirtualAngleInfo( string wfile, string dfile ){
    _isGoodResult = false;
    UtsusemiNeunetEventDecoderBase *ED = new UtsusemiNeunetEventDecoderBase();
    if (ED->SetParametersFromFiles( wfile, dfile)!=0){
        string msg = MessageTag+"_CalcVirtualAngleInfo : param files are invalid."+wfile+","+dfile;
        UtsusemiError( msg );
        delete ED;
        return;
    }
    
    ED->CalcPixelPosition();
    UInt4 psize = ED->_pixelPositionVect.size();
    if (psize<=0){
        string msg = MessageTag+"_CalcVirtualAngleInfo : param files are invalid."+wfile+","+dfile;
        UtsusemiError( msg );
        delete ED;
        return;
    }
    
    _VirtualAngleInfo.clear();
    _VirtualAngleInfo.resize( psize, NULL );
    for (UInt4 i=0; i<psize; i++){
        vector<Double>* p = ED->_pixelPositionVect[i];
        if (p!=NULL){
            Double L2 = sqrt( (*p)[0]*(*p)[0] + (*p)[1]*(*p)[1] + (*p)[2]*(*p)[2] );
            if (_VirtualAngleInfo[i]==NULL) _VirtualAngleInfo[i]=new 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)[2]/L2 );
            _VirtualAngleInfo[i]->second= acos( (*p)[0]/sqrt( (*p)[0]*(*p)[0]+(*p)[1]*(*p)[1] ) )*(*p)[1]/sqrt( (*p)[1]*(*p)[1] );
        }
    }
    
    delete ED;
    return;
}
//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
_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 D4Matrix::
_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;
        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 D4Matrix::
OpenMat( string datapath, 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 D4Matrix::
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 D4Matrix::
_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 D4Matrix::
_ClearVirtualMat(){
    if (_VirtualD4Mat!=NULL){
        for(UInt4 i=0; i<(_VirtualD4Mat->size()); i++) delete _VirtualD4Mat->at(i);
        delete _VirtualD4Mat;
        _VirtualD4Mat=NULL;
    }
    _isVirtual=false;
}
//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
_AddToMatFromText( 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{
        vector<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;
    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 ], 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 ], -sizeof(data), SEEK_CUR );
            //fwrite( &data, sizeof(data), 1, fs_list[ target ] );
            //fwrite( data, sizeof(data), 1, fs_list[ target ] );
            if ((int)fwrite( data, sizeof(data), 1, fs_list[ target ] ) !=1){
                usleep(50000);
                if ((int)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 D4Matrix::
AddToMatFromText( string filename ){
    Int4 ret;
    ret = _AddToMatFromText( filename, true );
    if (ret==0){
        _isGoodResult = true;
    }else{
        _isGoodResult = false;
    }
}

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

    vector< Double > AX1 = __gCppToPython.ListToDoubleVector( ax1 );
    vector< Double > AX2 = __gCppToPython.ListToDoubleVector( ax2 );
    vector< Double > AX3 = __gCppToPython.ListToDoubleVector( ax3 );
    vector< Double > AX4 = __gCppToPython.ListToDoubleVector( ax4 );
    vector< Double > II = __gCppToPython.ListToDoubleVector( ii );
    vector< Double > EE = __gCppToPython.ListToDoubleVector( ee );
    
    if ((AX1.size()!=AX2.size())||(AX2.size()!=AX3.size())||(AX3.size()!=AX4.size())){
        string msg = MessageTag + "AddToMatFromPyList > Cannot Add given lists to D4Mat 1";
        msg += stools->UInt4ToString(AX1.size())+","+stools->UInt4ToString(AX2.size())+",";
        msg += stools->UInt4ToString(AX3.size())+","+stools->UInt4ToString(AX4.size());
        UtsusemiError( msg );
        return -1;
    }
    if ((AX1.size()!=II.size())||(II.size()!=EE.size())){
        string msg = MessageTag + "AddToMatFromPyList > Cannot Add given lists to D4Mat 2";
        msg += stools->UInt4ToString(AX1.size())+","+stools->UInt4ToString(II.size())+","+stools->UInt4ToString(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 ], 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] = II[i];
            }else{
                data_out[0] += II[i];
            }
            data_out[1] += EE[i]*EE[i];
            data_out[2] += 1.0;
            fseek( fs_list[ target ], -sizeof(data_out), SEEK_CUR );
            //fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] );
            if ((int)fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] ) !=1){
                usleep(50000);
                if ((int)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 D4Matrix::
SavePyListToBin( string filepath, PyObject *ax1, PyObject *ax2, PyObject *ax3, PyObject *ax4, PyObject *ii, PyObject *ee ){
    _isGoodResult = false;
    
    vector< Double > AX1 = __gCppToPython.ListToDoubleVector( ax1 );
    vector< Double > AX2 = __gCppToPython.ListToDoubleVector( ax2 );
    vector< Double > AX3 = __gCppToPython.ListToDoubleVector( ax3 );
    vector< Double > AX4 = __gCppToPython.ListToDoubleVector( ax4 );
    vector< Double > II = __gCppToPython.ListToDoubleVector( ii );
    vector< Double > EE = __gCppToPython.ListToDoubleVector( ee );
    
    if ((AX1.size()!=AX2.size())||(AX2.size()!=AX3.size())||(AX3.size()!=AX4.size())){
        string msg = MessageTag + "SavePyListToBin > Cannot Add given lists to D4Mat 1";
        msg += stools->UInt4ToString(AX1.size())+","+stools->UInt4ToString(AX2.size())+",";
        msg += stools->UInt4ToString(AX3.size())+","+stools->UInt4ToString(AX4.size());
        UtsusemiError( msg );
        return;
    }
    if ((AX1.size()!=II.size())||(II.size()!=EE.size())){
        string msg = MessageTag + "SavePyListToBin > Cannot Add given lists to D4Mat 2";
        msg += stools->UInt4ToString(AX1.size())+","+stools->UInt4ToString(II.size())+","+stools->UInt4ToString(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] );
            //fwrite( data, sizeof(data), 1, fp );
            if ((int)fwrite( data, sizeof(data), 1, fp ) !=1){
                usleep(50000);
                if ((int)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 D4Matrix::
SubtractFromMatByText( string filename ){
    Int4 ret;
    ret = _AddToMatFromText( filename, false );
    if (ret==0){
        _isGoodResult = true;
    }else{
        _isGoodResult = false;
    }
}

//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
_AddToMatFromBin( 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{
        vector<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];
    vector<float> a1v,a2v,a3v,a4v,iiv,eev;
    a1v.clear();
    a2v.clear();
    a3v.clear();
    a4v.clear();
    iiv.clear();
    eev.clear();
    while((ret=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 = iiv.size();
    UtsusemiMessage( MessageTag + "_AddToMatFromBin > --- Under loading data (size="+stools->UInt4ToString(sum_of_points)+")" );
    UInt4 step_points = float( (sum_of_points-1)/5.0 );
    for (UInt4 i=0;i<iiv.size();i++){
        //if ((i % 100000)==0) cout << i <<"/"<< sum_of_points << endl;
        if (( 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 ], 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 ], -sizeof(data_out), SEEK_CUR );
            //fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] );
            if ((int)fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] ) !=1){
                usleep(50000);
                if ((int)fwrite( data_out, sizeof(data_out), 1, fs_list[ target ] ) !=1){
                    UtsusemiError( MessageTag + "_AddToMatFromBin > Failed to write.");
                    return -1;
                }
            }
        }
    }
    //cout << endl;
    
    if( (ret = SaveParamXml( d4mat_data_dir, d4mat_param_file ))!=0 )        return -1;

    return 0;
}

//////////////////////////////////////////////////////////////////////
bool D4Matrix::
AddToMatFromBin( string filename ){
    Int4 ret = _AddToMatFromBin( filename, true );
    if (ret==0){
        _isGoodResult = true;
    }else{
        _isGoodResult = false;
    }
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
AddToMatFromBinFolder( string folderpath, 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)){
                string a_file( p_a_file.string() );
                if (a_file.find(_ext)!=string::npos){
                    if (_AddToMatFromBin( a_file, true )<0) return false;
                }
            }
        }
    }
    _isGoodResult = true;
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
void D4Matrix::
SubtractFromMatByBin( string filename ){
    Int4 ret;
    ret = _AddToMatFromBin( filename, false );
    if (ret==0){
        _isGoodResult = true;
    }else{
        _isGoodResult = false;
    }
}
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
_CalcRangeInfo( UInt4 dim, vector<Double> &a1r, vector<Double> &a2r, vector<Double> &a3r, vector<Double> &a4r, 
                vector<string> &def_axes, vector<UInt4> &def_ind, vector< vector<Double> > &arlist, 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==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
    vector<Double> xrange = CalcRangeAsBinCenterZero( arlist[indX][0],arlist[indX][1],arlist[indX][2] );
    vector<Double> yrange = CalcRangeAsBinCenterZero( arlist[indY][0],arlist[indY][1],arlist[indY][2] );
    vector<Double> zrange = CalcRangeAsBinCenterZero( arlist[indZ][0],arlist[indZ][1],arlist[indZ][2] );
    vector<Double> trange = CalcRangeAsBinCenterZero( arlist[indT][0],arlist[indT][1],arlist[indT][2] );
    
    arlist[indX][0] = xrange[0];
    arlist[indX][1] = xrange[1];
    arlist[indY][0] = yrange[0];
    arlist[indY][1] = yrange[1];
    if (dim==2){
        arlist[indZ][2] = arlist[indZ][1]-arlist[indZ][0];
        arlist[indT][2] = arlist[indT][1]-arlist[indT][0];
    }else if (dim==3){
        arlist[indZ][0] = zrange[0];
        arlist[indZ][1] = zrange[1];
    }else if (dim==4){
        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) {
        cout << "-----------------------------------"<<endl;
        cout << "xrange="<< xrange[0] <<","<<xrange[1]<<","<<arlist[indX][2]<<endl;
        cout << "yrange="<< yrange[0] <<","<<yrange[1]<<","<<arlist[indY][2]<<endl;
        cout << "zrange="<< arlist[indZ][0] <<","<<arlist[indZ][1]<<","<<arlist[indZ][2]<<endl;
        cout << "trange="<< arlist[indT][0] <<","<<arlist[indT][1]<<","<<arlist[indT][2]<<endl;
        cout << "-----------------------------------"<<endl;
        cout << "range_list[0]="<<range_list[0][0]<<","<<range_list[0][1]<<","<<range_list[0][2]<<endl;
        cout << "range_list[1]="<<range_list[1][0]<<","<<range_list[1][1]<<","<<range_list[1][2]<<endl;
        cout << "range_list[2]="<<range_list[2][0]<<","<<range_list[2][1]<<","<<range_list[2][2]<<endl;
        cout << "range_list[3]="<<range_list[3][0]<<","<<range_list[3][1]<<","<<range_list[3][2]<<endl;
    }
    
    numlist.clear();
    numlist.resize(dim);
    numlist[0] = xrange[2]; 
    numlist[1] = yrange[2]; 
    if (dim==3) numlist[2] = zrange[2];
    if (dim==4){
        numlist[2] = zrange[2];
        numlist[3] = trange[2];
    }
    return true;
}

//////////////////////////////////////////////////////////////////////
void D4Matrix::
SliceMat( vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> def_axes, vector<Double> foldings ){
    _isGoodResult = false;
    if (foldings.empty()) foldings.resize(4,-1.0);
    if ((!isFilesOpened)||(_VirtualD4Mat!=NULL)){
        SliceVirtualMat( a1range, a2range, a3range, a4range, def_axes, foldings );
        return;
    }
    if (!isFilesOpened) _OpenFiles();
    vector< vector<Double> > ArList;
    vector<UInt4> def_ind,NumList;
    if (_CalcRangeInfo( 2, a1range, a2range, a3range, a4range, def_axes, def_ind, ArList, NumList )){
    }else{
        UtsusemiError( MessageTag+"SliceMat >>> Failed calculation of slicing range" );
        return;
    }
    
    UInt4 indX = def_ind[0];
    UInt4 indY = def_ind[1];
    UInt4 n_X = NumList[0];
    UInt4 n_Y = NumList[1];
    
    // 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 i=0;i<n_X;i++){
        for (UInt4 j=0;j<n_Y;j++){
            dArray[i][j]=eArray[i][j]=cArray[i][j]=0.0;
        }
    }
    
    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 x3 = range_list[3][0] + (range_list[3][2]+1.0E-15)*(double(iX3));
        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 x0 = range_list[0][0] + (range_list[0][2]+1.0E-15)*(double(iX0));
            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 x1 = range_list[1][0] + (range_list[1][2]+1.0E-15)*(double(iX1));
                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 x2 = range_list[2][0] + (range_list[2][2]+1.0E-15)*(double(iX2));
                    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]);
                    /*
                    if (iXs[2]==0) {
                        cout << "iX2="<<iX2<<", range_list[2][0]="<<range_list[2][0]<<", range_list[2][2]="<<range_list[2][2]<<endl;;
                        cout <<", (double(iX2)+0.5)="<<(double(iX2)+0.5);
                        cout << ", range_list[2][2]*(double(iX2)+0.5)="<<range_list[2][2]*(double(iX2)+0.5);
                        cout << ", x2f, ix2="<<x2f<<","<<iXs[2]<<endl;
                        cout << "ArList[2][0], ArList[2][2]="<<ArList[2][0]<<","<<ArList[2][2];
                        cout << "    (x2f - ArList[2][0])/ArList[2][2]="<<(x2f - ArList[2][0])/ArList[2][2]<<endl;
                    }
                    */
                    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){
                        UtsusemiMessage(MessageTag + "SliceMat failed to read data");
                    }else{
                        if (dat[2]!=0.0){
                            dArray[ iXs[indX] ][ iXs[indY] ] += dat[0];
                            eArray[ iXs[indX] ][ iXs[indY] ] += dat[1];
                            cArray[ iXs[indX] ][ iXs[indY] ] += dat[2];
                        }
                    }
                } // Loop NumBin[2]
            }// Loop NumBin[1]
        }// Loop NumBin[0]
    }// Loop NumBin[3]
    
    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]*(float(i)-0.5);
        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]*(float(i)-0.5);
        YArray[i] = ArList[indY][0] + ArList[indY][2]*double(i);
    }
    
    for (UInt4 i=0;i<n_X;i++){
        vector<Double> datY(n_Y,0.0);
        vector<Double> datE(n_Y,0.0);
        for (UInt4 j=0;j<n_Y;j++){
            if (cArray[i][j]!=0.){
                datY[j]= dArray[i][j]/cArray[i][j];
                datE[j]= sqrt( eArray[i][j] )/cArray[i][j];
            }else{
                datY[j]= UTSUSEMIMASKVALUE64;
                datE[j]= 0.0;
            }
        }
        datArray.push_back(datY);
        errArray.push_back(datE);
    }

    for (UInt4 i=0;i<n_X;i++){
        delete [] dArray[i];
        delete [] eArray[i];
        delete [] cArray[i];
    }
    delete [] dArray;
    delete [] eArray;
    delete [] cArray;
    
    if (isDebugMode) {
        cout << MessageTag + "XArray size, YArray size="<<XArray.size()<<","<<YArray.size()<<endl;
        cout << MessageTag << "Last value of XArray,YArray = " << XArray[ XArray.size()-1 ];
        cout << "," << YArray[ YArray.size()-1] << endl;
        cout << MessageTag << "n_X=" << n_X << endl;
        cout << MessageTag << "n_Y=" << n_Y << endl;
    }
    _isGoodResult = true;
    return;
}
//////////////////////////////////////////////////////////////////////
void D4Matrix::
SliceVirtualMat( vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> def_axes, vector<Double> foldings ){
    _isGoodResult = false;
    if (_VirtualD4Mat==NULL) return;
    
    vector< vector<Double> > ArList;
    vector<UInt4> def_ind,NumList;
    if (_CalcRangeInfo( 2, a1range, a2range, a3range, a4range, def_axes, def_ind, ArList, NumList )){
    }else{
        return;
    }
    
    UInt4 indX = def_ind[0];
    UInt4 indY = def_ind[1];
    UInt4 n_X = NumList[0];
    UInt4 n_Y = NumList[1];

    // 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 i=0;i<n_X;i++){
        for (UInt4 j=0;j<n_Y;j++){
            dArray[i][j]=eArray[i][j]=cArray[i][j]=0.0;
        }
    }
    
    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 x3 = range_list[3][0] + (range_list[3][2]+1.0E-15)*(double(iX3));
        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;
        
        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 x0 = range_list[0][0] + (range_list[0][2]+1.0E-15)*(double(iX0));
            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 x1 = range_list[1][0] + (range_list[1][2]+1.0E-15)*(double(iX1));
                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 x2 = range_list[2][0] + (range_list[2][2]+1.0E-15)*(double(iX2));
                    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]);
                    /*
                    if (iXs[2]==0) {
                        cout << "iX2="<<iX2<<", range_list[2][0]="<<range_list[2][0]<<", range_list[2][2]="<<range_list[2][2]<<endl;;
                        cout <<", (double(iX2)+0.5)="<<(double(iX2)+0.5);
                        cout << ", range_list[2][2]*(double(iX2)+0.5)="<<range_list[2][2]*(double(iX2)+0.5);
                        cout << ", x2f, ix2="<<x2f<<","<<iXs[2]<<endl;
                        cout << "ArList[2][0], ArList[2][2]="<<ArList[2][0]<<","<<ArList[2][2];
                        cout << "    (x2f - ArList[2][0])/ArList[2][2]="<<(x2f - ArList[2][0])/ArList[2][2]<<endl;
                    }
                    */
                    UInt4 ind = ind0 + ind1 + ind2;
                    float intensity = _VirtualD4Mat->at(ind3)->at(ind);
                    dArray[ iXs[indX] ][ iXs[indY] ] += intensity;
                    eArray[ iXs[indX] ][ iXs[indY] ] += intensity;
                    cArray[ iXs[indX] ][ iXs[indY] ] += intensity;
                } // Loop NumBin[2]
            }// Loop NumBin[1]
        }// Loop NumBin[0]
    }// Loop NumBin[3]
    
    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]*(float(i)-0.5);
        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]*(float(i)-0.5);
        YArray[i] = ArList[indY][0] + ArList[indY][2]*double(i);
    }
    
    for (UInt4 i=0;i<n_X;i++){
        vector<Double> datY(n_Y,0.0);
        vector<Double> datE(n_Y,0.0);
        for (UInt4 j=0;j<n_Y;j++){
            if (cArray[i][j]!=0.){
                datY[j]= dArray[i][j]/cArray[i][j];
                datE[j]= sqrt( eArray[i][j] )/cArray[i][j];
            }else{
                datY[j]= UTSUSEMIMASKVALUE64;
                datE[j]= 0.0;
            }
        }
        datArray.push_back(datY);
        errArray.push_back(datE);
    }

    for (UInt4 i=0;i<n_X;i++){
        delete [] dArray[i];
        delete [] eArray[i];
        delete [] cArray[i];
    }
    delete [] dArray;
    delete [] eArray;
    delete [] cArray;
    
    if (isDebugMode) {
        cout << MessageTag + "XArray size, YArray size="<<XArray.size()<<","<<YArray.size()<<endl;
        cout << MessageTag << "Last value of XArray,YArray = " << XArray[ XArray.size()-1 ];
        cout << "," << YArray[ YArray.size()-1] << endl;
        cout << MessageTag << "n_X=" << n_X << endl;
        cout << MessageTag << "n_Y=" << n_Y << endl;
    }
    _isGoodResult = true;
    return;
}
//////////////////////////////////////////////////////////////////////
void D4Matrix::
SliceMatOld( vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> def_axes, vector<Int4> foldings ){
    if (!isFilesOpened) _OpenFiles();
    
    vector< vector<Double> > ArList;

    ArList.clear();
    ArList.push_back( a1range );
    ArList.push_back( a2range );
    ArList.push_back( a3range );
    ArList.push_back( a4range );
    
    /*
    // params check for folding 
    for (UInt4 i=0; i<ArList.size(); i++){
        isFoldOverZero.push_back(0);
        if (foldings[i]==1){
            if ((ArList[i][0]<0.0)&&(ArList[i][1]>0.0)){
                //ArList[i][0]=0.0;
                isFoldOverZero[i]=1;
            }
            ArList[i][0] = fabs( ArList[i][0] );
            ArList[i][1] = fabs( ArList[i][1] );
            if (ArList[i][0]>ArList[i][1]){
                Double tmp = ArList[i][0];
                ArList[i][0] = ArList[i][1];
                ArList[i][1] = tmp;
            }
        }
    }
    */
                
    vector< Int4 > AxisNo;
    AxisNo.clear();
    for (UInt4 i=0;i<4;i++) AxisNo.push_back(-1);
    
    UInt4 AxisX,AxisY;
    AxisX = AxisY = 0;
    for (UInt4 i=0;i<def_axes.size();i++){
        if (def_axes[i]=="X"){
            AxisNo[i]=0;
            AxisX = i;
        }
        if (def_axes[i]=="Y"){
            AxisNo[i]=1;
            AxisY = i;
        }
        if (def_axes[i]=="T") AxisNo[i]=2;
    }
    
    /*
    vector< vector<UInt4> > i_range;
    i_range.clear();
    for (UInt4 i=0;i<ArList.size();i++){
        UInt4 cnt = 0;
        Double cval = 0.0;
        vector<UInt4> rv;
        rv.clear();
        rv.push_back(0); //minimum index in prepared Matrix
        rv.push_back(0); //maximum index in prepared Matrix

        if (ArList[i][0]>ArList[i][1]){
            Double tmp = ArList[i][0];
            ArList[i][0] = ArList[i][1];
            ArList[i][1] = tmp;
        }
        
        while(true){
            cval = range_list[i][0]+range_list[i][2]*float(cnt);
            if ((rv[0]==0)&&(cval>=ArList[i][0])) rv[0] = cnt;
            if ((rv[1]==0)&&(cval>=ArList[i][1])){
                rv[1]=cnt-1;
                break;
            }
            if (cval>=range_list[i][1]){
                rv[1]=cnt-1;
                break;
            }else{
                cnt++;
            }
        }
        i_range.push_back( rv );
    }
    */
    
    // for Folding
    vector< vector<UInt4> > i_range,if1_range,if2_range;
    i_range.clear();
    if1_range.clear();
    if2_range.clear();
    
    vector<bool> isFoldOverZero(4,true);
    
    for (UInt4 i=0;i<ArList.size();i++){
        UInt4 cnt = 0;
        Double cval = 0.0;
        vector<UInt4> rv(2,0);
        vector<UInt4> rv1(2,0);
        vector<UInt4> rv2(2,0);

        if (ArList[i][0]>ArList[i][1]){
            Double tmp = ArList[i][0];
            ArList[i][0] = ArList[i][1];
            ArList[i][1] = tmp;
        }
        
        if ((foldings[i]==1)&&((ArList[i][0]*ArList[i][1])<0.0)){
            isFoldOverZero[i]=true;
        }else{
            isFoldOverZero[i]=false;
        }
        while(true){
            cval = range_list[i][0]+(range_list[i][2]+1.0E-15)*Double(cnt);
            if ((rv[0]==0)&&(cval>=ArList[i][0])) rv[0] = cnt;
            if ((rv[1]==0)&&(cval>=ArList[i][1])) rv[1] = cnt-1;

            if (foldings[i]==0){
                if ((rv1[0]==0)&&(cval>=ArList[i][0])) rv1[0] = cnt;
                if ((rv1[1]==0)&&(cval>=ArList[i][1])) rv1[1] = cnt-1;
            }else{
                if (isFoldOverZero[i]){
                    if ((rv1[0]==0)&&(cval>=0.0)) rv1[0] = cnt;
                    if ((rv1[1]==0)&&(cval>=ArList[i][1])) rv1[1] = cnt-1;
                    if ((rv2[0]==0)&&(cval>=-fabs(ArList[i][1]))) rv2[0] = cnt;
                    if ((rv2[1]==0)&&(cval>=0.0)) rv2[1] = cnt-1;
                }else{
                    if ((rv1[0]==0)&&(cval>=fabs(ArList[i][0]))) rv1[0] = cnt;
                    if ((rv1[1]==0)&&(cval>=fabs(ArList[i][1]))) rv1[1] = cnt-1;
                    if ((rv2[0]==0)&&(cval>=-fabs(ArList[i][1]))) rv2[0] = cnt;
                    if ((rv2[1]==0)&&(cval>=-fabs(ArList[i][0]))) rv2[1] = cnt-1;
                }
            }
            if (cval>=range_list[i][1]){
                if (rv[1]==0) rv[1] = cnt-1;
                if (rv1[1]==0) rv1[1] = cnt-1;
                break;
            }else{
                cnt++;
            }
        }
        i_range.push_back(rv);
        if1_range.push_back(rv1);
        if2_range.push_back(rv2);
    }
    
    
    
    UInt4 n_X, n_Y;
    n_X = n_Y = 0;
    Int4 i_shift_x = 0;
    Int4 i_shift_y = 0;
    if (foldings[ AxisX ]==0){
        n_X = i_range[ AxisX ][1] - i_range[ AxisX ][0] + 1;
    }else if (isFoldOverZero[ AxisX ]){
        n_X = i_range[ AxisX ][1] - i_range[ AxisX ][0] + 1;
        i_shift_x = if1_range[ AxisX ][0] - i_range[ AxisX ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisX ][1] - if1_range[ AxisX ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisX ][1] - if2_range[ AxisX ][0] + 1;
        if (tmp1>=tmp2){
            n_X = tmp1;
        }else{
            n_X = tmp2;
        }
    }
    if (foldings[ AxisY ]==0){
        n_Y = i_range[ AxisY ][1] - i_range[ AxisY ][0] + 1;
    }else if (isFoldOverZero[ AxisY ]){
        n_Y = i_range[ AxisY ][1] - i_range[ AxisY ][0] + 1;
        i_shift_y = if1_range[ AxisY ][0] - i_range[ AxisY ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisY ][1] - if1_range[ AxisY ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisY ][1] - if2_range[ AxisY ][0] + 1;
        if (tmp1>=tmp2){
            n_Y = tmp1;
        }else{
            n_Y = tmp2;
        }
    }
    
    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 i=0;i<n_X;i++){
        for (UInt4 j=0;j<n_Y;j++){
            dArray[i][j]=eArray[i][j]=cArray[i][j]=0.0;
        }
    }
    
    //cout <<" AxisNo="<<AxisNo[0]<<AxisNo[1]<<AxisNo[2]<<AxisNo[3]<<endl;
    
    if (isDebugMode) {
        cout << MessageTag << "-------" << endl;
        cout << MessageTag << "index_of_blocks.size=" << index_of_blocks.size() << endl;
        cout << MessageTag << "index_of_blocks[0]and [last]=" << index_of_blocks[0];
        cout << "," << index_of_blocks[ index_of_blocks.size()-1 ] << endl;
        cout << MessageTag << "-------" << endl;
        for (UInt4 i=0;i<4;i++){
            cout << " i_range[" << i <<"]="<<i_range[i][0]<<","<<i_range[i][1]<<endl;
            cout << "if1_range[" << i <<"]="<<if1_range[i][0]<<","<<if1_range[i][1]<<endl;
            cout << "if2_range[" << i <<"]="<<if2_range[i][0]<<","<<if2_range[i][1]<<endl;
        }
        cout << MessageTag << "-------" << endl;
        cout << "n_X = " << n_X << endl;
        cout << "n_Y = " << n_Y << endl;
        cout << "i_shift_x = " << i_shift_x <<endl;
        cout << "i_shift_y = " << i_shift_y <<endl;

    }
    
    
    vector< vector< UInt4 > > fold_ptn;
    fold_ptn.clear();
    vector<UInt4> t_max;
    for (UInt4 i=0; i<4; i++){
        if (foldings[i]==0){
            t_max.push_back(1);
        }else{
            t_max.push_back(2);
        }
    }
    
    for (UInt4 t0=0; t0<t_max[0]; t0++){
        for (UInt4 t1=0; t1<t_max[1]; t1++){
            for (UInt4 t2=0; t2<t_max[2]; t2++){
                for (UInt4 t3=0; t3<t_max[3]; t3++){
                    vector< UInt4 > vv;
                    vv.clear();
                    vv.push_back( t0 );
                    vv.push_back( t1 );
                    vv.push_back( t2 );
                    vv.push_back( t3 );
                    fold_ptn.push_back(vv);
                }
            }
        }
    }

    UInt4 AX[3] = {0,0,0};

    UInt4 ind0,ind1,ind2,ind3;
    ind0 = ind1 = ind2 = ind3 = 0;
    
    vector<UInt4> imin, imax;
    imin.clear();
    imax.clear();
                    
    for (UInt4 i=0; i<fold_ptn.size(); i++){
        string msg =  MessageTag+"fold pattern ="+ stools->UInt4ToString(fold_ptn[i][0]) + ",";
        msg += stools->UInt4ToString(fold_ptn[i][1]) + "," + stools->UInt4ToString(fold_ptn[i][2]) + "," +stools->UInt4ToString(fold_ptn[i][3]);
        UtsusemiMessage( msg );
        imin.clear();
        imax.clear();
        for (UInt4 j=0; j<4; j++){
            imin.push_back( if1_range[j][0] );
            imax.push_back( if1_range[j][1] );
            if (fold_ptn[i][j]==1){
                imin[j] = if2_range[j][0];
                imax[j] = if2_range[j][1];
            }
        }
        if (isDebugMode) {
            cout << "imin=" << imin[0] <<","<< imin[1]<<","<< imin[2] <<","<< imin[3] << endl;
            cout << "imax=" << imax[0] <<","<< imax[1]<<","<< imax[2] <<","<< imax[3] << endl;
        }

        for (UInt4 i3=imin[3]; i3<=imax[3];i3++){
            ind3 = i3 * size_of_Ax[3];
            
            UInt4 target = 0;
            for (UInt4 j=0;j<(index_of_blocks.size()-1);j++){
                if ( (i3>=index_of_blocks[j])&&(i3<index_of_blocks[j+1]) ) {
                    target = j;
                    ind3 = (i3 - index_of_blocks[j])*size_of_Ax[3];
                    break;
                }
            }
            if (fold_ptn[i][3]==0) {
                AX[ AxisNo[3] ] = i3 - imin[3];
            }else{
                AX[ AxisNo[3] ] = imax[3] - i3;
            }
            for (UInt4 i0=imin[0]; i0<=imax[0]; i0++){
                if (fold_ptn[i][0]==0) {
                    AX[ AxisNo[0] ] = i0 - imin[0];
                }else{
                    AX[ AxisNo[0] ] = imax[0] - i0;
                }
                ind0 = i0*size_of_Ax[0];
                for (UInt4 i1=imin[1]; i1<=imax[1]; i1++){
                    if (fold_ptn[i][1]==0) {
                        AX[ AxisNo[1] ] = i1 - imin[1];
                    }else{
                        AX[ AxisNo[1] ] = imax[1] - i1;
                    }
                    ind1 = i1*size_of_Ax[1];
                    for (UInt4 i2=imin[2]; i2<=imax[2]; i2++){
                        if (fold_ptn[i][2]==0) {
                            AX[ AxisNo[2] ] = i2 - imin[2];
                        }else{
                            AX[ AxisNo[2] ] = imax[2] - i2;
                        }
                        ind2 = i2*size_of_Ax[2];
                        UInt4 ind = ind0 + ind1 + ind2 + ind3;
                        float dat[3];
                        fseek( fs_list[ target ], ind, SEEK_SET );
                        if ((int)fread( dat, sizeof(dat), 1, fs_list[ target ] )!=1){
                            UtsusemiError( MessageTag + "SliceMat failed to read data");
                        }else{
                            if (dat[2]!=0.0){
                                dArray[ AX[0] + i_shift_x ][ AX[1] + i_shift_y ] += dat[0];
                                eArray[ AX[0] + i_shift_x ][ AX[1] + i_shift_y ] += dat[1];
                                cArray[ AX[0] + i_shift_x ][ AX[1] + i_shift_y ] += dat[2];
                            }
                        }
                    }
                }
            }
        }
    }
    
    datArray.clear();
    errArray.clear();
    XArray.clear();
    YArray.clear();
    
    for (UInt4 i=i_range[AxisX][0];i<(i_range[AxisX][1]+1);i++){
        XArray.push_back( range_list[AxisX][0] + range_list[AxisX][2]*(float(i)-0.5));
    }
    XArray.push_back( range_list[AxisX][0] + range_list[AxisX][2]*(float(i_range[AxisX][1])+0.5 ));
    
    for (UInt4 i=i_range[AxisY][0];i<(i_range[AxisY][1]+1);i++){
        YArray.push_back( range_list[AxisY][0] + range_list[AxisY][2]*(float(i)-0.5));
    }
    YArray.push_back( range_list[AxisY][0] + range_list[AxisY][2]*(float(i_range[AxisY][1])+0.5));
    
    for (UInt4 i=0;i<n_X;i++){
        vector<Double> datY,datE;
        datY.clear();
        datE.clear();
        for (UInt4 j=0;j<n_Y;j++){
            if (cArray[i][j]!=0.){
                datY.push_back( dArray[i][j]/cArray[i][j] );
                //datY.push_back( dArray[i][j] );
                datE.push_back( sqrt( eArray[i][j] )/cArray[i][j] );
            }else{
                datY.push_back( UTSUSEMIMASKVALUE64 );
                datE.push_back( 0.0 );
            }
        }
        datArray.push_back(datY);
        errArray.push_back(datE);
    }

    for (UInt4 i=0;i<n_X;i++){
        delete [] dArray[i];
        delete [] eArray[i];
        delete [] cArray[i];
    }
    delete [] dArray;
    delete [] eArray;
    delete [] cArray;
    
    if (isDebugMode) {
        cout << MessageTag << "Last value of XArray,YArray" << XArray[ XArray.size()-1 ];
        cout << "," << YArray[ YArray.size()-1] << endl;
        cout << MessageTag << "n_X=" << n_X << endl;
        cout << MessageTag << "n_Y=" << n_Y << endl;
    }
}

//////////////////////////////////////////////////////////////////////
vector<Double> D4Matrix::
PutSliceResults( UInt4 type, UInt4 index ){
    vector<Double> ret;
    ret.push_back(-1.0);
    if (index>datArray.size()){
        UtsusemiError(MessageTag + "Arguments is too large < " + stools->UInt4ToString(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 D4Matrix::
_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;
}
//////////////////////////////////////////////////////////////////////
vector<Double> D4Matrix::
PickUpInten( Double a1, Double a2, Double a3, Double a4 ){
    if (!isFilesOpened) _OpenFiles();
    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 ], 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) {
            cout << MessageTag << "target file=" << name_of_blocks[ target ] << endl;
            cout << MessageTag << "ind = " << ind << endl;
            cout << MessageTag << "Intensity = " << data[0] << endl;
            cout << MessageTag << "Error = " << data[1] << endl;
            cout << MessageTag << "Counts = " << data[2] << 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 D4Matrix::
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 ], ind, SEEK_SET );
        //fwrite( &data, sizeof(data), 1, fs_list[ target ] );
        if ((int)fwrite( data, sizeof(data), 1, fs_list[ target ] )!=1){
            UtsusemiError( MessageTag + "Failed to replace data" );
        }
    }
}

//////////////////////////////////////////////////////////////////////
ElementContainerArray D4Matrix::
PutSlicedECA(){
    ElementContainerArray eca;
    if (datArray.size()==0){
        return eca;
    }
    
    eca.AddToHeader("isHistogram",0);
    for (UInt4 i=0;i<(XArray.size()-1);i++){
        vector<Double> v_int = PutSliceResults(0,i);
        vector<Double> v_err = PutSliceResults(1,i);
        
        ElementContainer ec;
        
        vector<Double> xrange;
        xrange.push_back(XArray[i]);
        xrange.push_back(XArray[i+1]);
        ec.AddToHeader(UTSUSEMI_KEY_HEAD_XRANBE,xrange);
        ec.AddToHeader("X",((XArray[i]+XArray[i+1])/2.0));
        
        ec.Add("Y",YArray);
        ec.Add(UTSUSEMI_KEY_INTENSITY,v_int);
        ec.Add(UTSUSEMI_KEY_ERROR,v_err);
        ec.SetKeys("Y",UTSUSEMI_KEY_INTENSITY,UTSUSEMI_KEY_ERROR);
        eca.Add(ec);
    }
    
    return eca;
}

//////////////////////////////////////////////////////////////////////
vector<Double> D4Matrix::
PutAxRange( UInt4 i_ax ){
    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;
}

//////////////////////////////////////////////////////////////////////
string D4Matrix::
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 D4Matrix::
SetAxTitle( UInt4 i_ax, 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 D4Matrix::
SetAxTitles( vector<string> titles, bool isSaved ){
    if ((titles.size()==0)||(titles.size()>4)){
        UtsusemiError( MessageTag + "Vector size of argument is out of range. (" + stools->UInt4ToString(titles.size())+ ")" );
    }else{
        for (UInt4 i=0;i<titles.size();i++){
            SetAxTitle( i, titles[i] );
        }
    }
    if (isSaved) SaveParamXml( d4mat_data_dir, d4mat_param_file );
}

//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
SaveParamXml( string datapath, string filename ){
    BoostXmlParser *bxmlp = new BoostXmlParser();
    //mxml_node_t *tree,*node1,*node2,*node3,*node4;
    
    vector<string> att_v, val_v;
    string _KEY = "d4mat_key";
    bxmlp->CreateNewTree(_KEY);
    
    bxmlp->AddElement(_KEY,"D4Matrix/numOfFileBlocks", stools->Int4ToString( 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);
        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++){
            string st_ax = "ax"+stools->Int4ToString(j+1);
            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 );
        }
        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++){
        string st = "ax"+stools->Int4ToString(i+1);
        bxmlp->AddElement(_KEY, ("D4Matrix/axisTitle/"+st), ax_titles[i] );
    }
    
    // D4Matrix/numOfFileComponents
    bxmlp->AddElement(_KEY, "D4Matrix/numOfFileComponents", stools->Int4ToString( 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 )!=string("/")){
        datapath = datapath+"/";
    }
    string filepath = datapath + filename;
    bxmlp->Save( filepath );
    
    delete bxmlp;
    
    return 0;

    /*
    tree = mxmlp->CreateNewTree();
    node1 = mxmlp->NewElement( tree, "D4Matrix" );

    node2 = mxmlp->NewElement( node1, "numOfFileBlocks" );
    mxmlp->NewText( node2, stools->Int4ToString( name_of_blocks.size() ) );

    node2 = mxmlp->NewElement( node1, "blocks" );
    
    for (UInt4 i=0;i<name_of_blocks.size();i++){
        node3 = mxmlp->NewElement( node2, "block" );
        mxmlp->SetAttr( node3, "i", stools->Int4ToString( i ) );
        
        node4 = mxmlp->NewElement( node3, "filename" );
        mxmlp->NewText( node4, name_of_blocks[i] );
        
        for (Int4 j=0;j<3;j++){
            string st_ax = "ax"+stools->Int4ToString(j+1);
            node4 = mxmlp->NewElement( node3, st_ax );
            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] ) );
            mxmlp->NewText( node4, st_range );
        }
        
        node4 = mxmlp->NewElement( node3, "ax4" );
        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] ) );
        mxmlp->NewText( node4, st_range );
    }
    
    node2 = mxmlp->NewElement( node1, "axisTitle" );
    for (Int4 i=0;i<4;i++){
        string st = "ax"+stools->Int4ToString(i+1);
        node3 = mxmlp->NewElement( node2, st );
        mxmlp->NewText( node3, ax_titles[i] );
    }
    
    node2 = mxmlp->NewElement( node1, "numOfFileComponents" );
    mxmlp->NewText( node2, stools->Int4ToString( file_components.size() ) );
    
    node2 = mxmlp->NewElement( node1, "fileComponents" );
    if (file_components.size()!=0){
        for (UInt4 i=0;i<file_components.size();i++){
            node3 = mxmlp->NewElement( node2, "filepath" );
            mxmlp->SetAttr( node3, "i", stools->Int4ToString( i ) );
            mxmlp->NewText( node3, file_components[i] );
        }
    }
    
    if (datapath.substr( datapath.size()-1 )!=string("/")){
        datapath = datapath+"/";
    }
    string filepath = datapath + filename;
    mxmlp->SaveXmlTree( filepath );
    
    delete mxmlp;
    
    return 0;
    */
}
//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
_ReadParamXml( string datapath, string filename ){

    _ClearAllParams();
    
    for (UInt4 i=0;i<4;i++){
        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();
    if (datapath.substr( datapath.size()-1 )!=string("/")){
        datapath = datapath+"/";
    }
    string filepath = datapath + filename;
    string _KEY = "loaded_xml";
    bxmlp->Load(_KEY, filepath );
    
    UInt4 num_of_file_blocks = 0;
    if (bxmlp->hasPath(_KEY, "D4Matrix/numOfFileBlocks")){
        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")){
        string tmp = bxmlp->PutContent(_KEY, "D4Matrix/numOfFileComponents","");
        num_of_file_compos = stools->StringToUInt4( tmp );
    }
    for (UInt4 i=0; i<num_of_file_blocks; i++){
        string ind = stools->UInt4ToString( i );
        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++){
                string target = "ax" + stools->UInt4ToString( j+1 );
                if (bxmlp->hasPath(_KEY,path+"/"+target)){
                    vector<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")){
                vector<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( 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) {
        cout << MessageTag << "size_of_Ax=" << size_of_Ax[0] <<","<< size_of_Ax[1] << ",";
        cout << size_of_Ax[2] <<","<< size_of_Ax[3] << endl;
    }

    string path = "D4Matrix/axisTitle";
    ax_titles.clear();
    ax_titles.resize(4,"");
    if (bxmlp->hasPath(_KEY,path)){
        for (UInt4 i=0; i<4; i++){
            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/fileComponents";
    file_components.clear();
    file_components.resize( num_of_file_compos,"");
    for (UInt4 i=0;i<num_of_file_compos;i++){
        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++){
            cout << MessageTag << "range_list["<< i << "]=" << range_list[i][0];
            cout << "," << range_list[i][1] << "," << range_list[i][2] << endl;
        }
        cout << MessageTag << "index of blocks = ";
        cout << MessageTag << index_of_blocks[ 0 ] << endl;
        for (UInt4 i=0;i<name_of_blocks.size();i++){
            cout << MessageTag << "File=" << name_of_blocks[i] << endl;
            cout << MessageTag << index_of_blocks[i+1] <<endl;
        }
        cout << MessageTag << "File components " << endl;
        for (UInt4 i=0;i<file_components.size();i++){
            cout << MessageTag << file_components[i] << endl;
        }
        cout << MessageTag << "d4mat_data_dir=" << d4mat_data_dir << endl;
        cout << MessageTag << "d4mat_param_file=" << d4mat_param_file << endl;
    }
    
    delete bxmlp;
    d4mat_data_dir = datapath;
    d4mat_param_file = filename;
    return 0;
    
    /*
    mxml_node_t *tree,*root,*node1,*node2,*node3,*node4;
    MiniXmlParser *mxmlp = new MiniXmlParser();
    
    if (datapath.substr( datapath.size()-1 )!=string("/")){
        datapath = datapath+"/";
    }
    string filepath = datapath + filename;
    
    tree = mxmlp->ReadXmlTree( filepath );
    root = mxmlp->FindElement( tree, tree, "D4Matrix", "NULL", "NULL", MXML_DESCEND );
    if (root==NULL){
        cout << MessageTag << "Cannot read xml file." << endl;
        delete mxmlp;
        return -1;
    }
    node1 = mxmlp->FindElement( root, tree, "numOfFileBlocks","NULL", "NULL", MXML_DESCEND );
    node2 = mxmlp->FindElement( root, tree, "numOfFileComponents","NULL", "NULL", MXML_DESCEND );
    if ((node1==NULL)||(node2==NULL)){
        cout << MessageTag << "Invalid xml file.(1st)" << endl;
        delete mxmlp;
        return -1;
    }
    
    node3 = mxmlp->WalkNext(node1,tree);
    node4 = mxmlp->WalkNext(node2,tree);
    if ((node3==NULL)||(node4==NULL)){
        cout << MessageTag << "Invalid xml file.(1st)" << endl;
        delete mxmlp;
        return -1;
    }
    UInt4 num_of_file_blocks = stools->StringToUInt4( mxmlp->PutString( node3 ) );
    UInt4 num_of_file_compos = stools->StringToUInt4( mxmlp->PutString( node4 ) );
    node1 = mxmlp->FindElement( root, tree, "blocks","NULL", "NULL", MXML_DESCEND );
    if (node1==NULL){
        cout << MessageTag << "Invalid xml file.(missing blocks)" << endl;
        delete mxmlp;
        return -1;
    }
    
    if (isDebugMode) {
        cout << MessageTag << "num_of_file_blocks = " << num_of_file_blocks << endl;
        cout << MessageTag << "num_of_file_compos = " << num_of_file_compos << endl;
    }
    
    for (UInt4 i=0;i<num_of_file_blocks;i++){
        string ind = stools->UInt4ToString( i );
        node2 = mxmlp->FindElement( node1, tree, "block", "i", ind, MXML_DESCEND );
        if (node2==NULL){
            cout << MessageTag << "Invalid xml file.(missing block) attr=" << ind << endl;
            delete mxmlp;
            return -1;
        }
        node3 = mxmlp->FindElement( node2, tree, "filename", "NULL", "NULL", MXML_DESCEND );
        if (node3==NULL){
            cout << MessageTag << "Invalid xml file.(missing filepath)" << endl;
            delete mxmlp;
            return -1;
        }
        node4 = mxmlp->WalkNext(node3,tree);
        if (isDebugMode) cout << MessageTag << "read Block file name=" << mxmlp->PutString(node4) << endl;
        name_of_blocks.push_back( mxmlp->PutString( node4 ) );
        
        if (i==0){
            for (UInt4 j=0;j<4;j++){
                string target = "ax" + stools->UInt4ToString( j+1 );
                node3 = mxmlp->FindElement( node2, tree, target, "NULL", "NULL", MXML_DESCEND );
                if (node3==NULL){
                    cout << MessageTag << "Invalid xml file.(missing ax)" << endl;
                    delete mxmlp;
                    return -1;
                }
                node4 = mxmlp->WalkNext(node3,tree);
                vector<Double> arv = mxmlp->PutDoubleVector( node4, 128 );
                range_list[j][0] = arv[0];
                range_list[j][1] = arv[1];
                range_list[j][2] = arv[2];
            }
            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{
            node3 = mxmlp->FindElement( node2, tree, "ax4", "NULL", "NULL", MXML_DESCEND );
            if (node3==NULL){
                cout << MessageTag << "Invalid xml file.(missing ax4)" << endl;
                delete mxmlp;
                return -1;
            }
            node4 = mxmlp->WalkNext(node3,tree);
            vector<Double> arv = mxmlp->PutDoubleVector( node4, 128 );
            index_of_blocks.push_back( UInt4( round( (arv[0]-range_list[3][0])/range_list[3][2] ) ) );
            if (i==(num_of_file_blocks-1)){
                range_list[3][1] = arv[1];
                index_of_blocks.push_back( UInt4( round( ( arv[1]-range_list[3][0] )/range_list[3][2] ) ) );
            }            
        }
    }
    for (UInt4 i=0;i<4;i++){
        NumBin.push_back( 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) {
        cout << MessageTag << "size_of_Ax=" << size_of_Ax[0] <<","<< size_of_Ax[1] << ",";
        cout << size_of_Ax[2] <<","<< size_of_Ax[3] << endl;
    }
    

    node1 = mxmlp->FindElement( root, tree, "axisTitle","NULL","NULL",MXML_DESCEND);
    if (node1==NULL){
        cout << MessageTag << "Invalid xml file.(missing axisTitle)" << endl;
        delete mxmlp;
        return -1;
    }
    for (UInt4 i=0;i<4;i++){
        string st = "ax" + stools->UInt4ToString( i+1 );
        node2 = mxmlp->FindElement( node1, tree, st, "NULL", "NULL", MXML_DESCEND );
        if (node2==NULL){
            cout << MessageTag << "Invalid xml file.(missing axisTitle/ax)" << endl;
            delete mxmlp;
            return -1;
        }
        node3 = mxmlp->WalkNext( node2,tree);
        ax_titles.push_back( mxmlp->PutString( node3 ) );
    }
    
    node1 = mxmlp->FindElement( root, tree, "fileComponents","NULL", "NULL", MXML_DESCEND );
    if (node1==NULL){
        cout << MessageTag << "Invalid xml file.(missing fileComponents)" << endl;
        delete mxmlp;
        return -1;
    }
    
    for (UInt4 i=0;i<num_of_file_compos;i++){
        string ind = stools->UInt4ToString( i );
        node2 = mxmlp->FindElement( node1, tree, "filepath","i", ind, MXML_DESCEND );
        if (node2==NULL){
            cout << MessageTag << "Invalid xml file.(missing file)" << endl;
            delete mxmlp;
            return -1;
        }
        node3 = mxmlp->WalkNext(node2,tree);
        file_components.push_back( mxmlp->PutString( node3 ) );
    }
    
    if (isDebugMode){
        for (UInt4 i=0;i<4;i++){
            cout << MessageTag << "range_list["<< i << "]=" << range_list[i][0];
            cout << MessageTag << "," << range_list[i][1] << "," << range_list[i][0] << endl;
        }
        cout << MessageTag << "index of blocks = ";
        cout << MessageTag << index_of_blocks[ 0 ] << endl;
        for (UInt4 i=0;i<name_of_blocks.size();i++){
            cout << MessageTag << "File=" << name_of_blocks[i] << endl;
            cout << MessageTag << index_of_blocks[i+1] <<endl;
        }
        cout << MessageTag << "File components " << endl;
        for (UInt4 i=0;i<file_components.size();i++){
            cout << MessageTag << file_components[i] << endl;
        }
        cout << MessageTag << "d4mat_data_dir=" << d4mat_data_dir << endl;
        cout << MessageTag << "d4mat_param_file=" << d4mat_param_file << endl;
    }
    
    delete mxmlp;

    d4mat_data_dir = datapath;
    d4mat_param_file = filename;
    return 0;
    */
}


//////////////////////////////////////////////////////////////////////
void D4Matrix::
AddMatToMat( string dir_from, string file_from, string dir_to, 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;
    
    string from_d4mat_data_dir(d4mat_data_dir);
    string from_d4mat_param_file(d4mat_param_file);
    vector< vector<Double> > from_range_list;
    from_range_list.clear();
    for (UInt4 i=0;i<range_list.size();i++){
        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);
    }

    vector<UInt4> from_NumBin;
    from_NumBin.clear();
    for (UInt4 i=0;i<NumBin.size();i++) from_NumBin.push_back( NumBin[i] );
    
    vector<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] );
    
    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] );

    vector<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] );

    vector<UInt4> from_size_of_Ax;
    vector<string> from_ax_titles;
    from_size_of_Ax.clear();
    from_ax_titles.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] );
    }
    
    CloseMat();
    _ClearAllParams();
    
    if (isDebugMode){    
        cout << "from_d4mat_data_dir=" << from_d4mat_data_dir << endl;
        cout << "from_d4mat_param_file=" << from_d4mat_param_file << endl;
        for (UInt4 i=0;i<from_range_list.size();i++){
            for (UInt4 j=0;j<from_range_list[i].size();j++){
                cout << "from_range_list=" << from_range_list[i][j];
                cout << " at " << i << "," << j << endl;
            }
        }
        for (UInt4 i=0;i<from_ax_titles.size();i++){
            cout << "title(AX" << i << ")" << from_ax_titles[i] << 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++){
        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 ], ind, SEEK_SET )!=0){
                                        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){
                                        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 ], -sizeof(outdata), SEEK_CUR );
                                        //fwrite( outdata, sizeof(outdata), 1, fs_list[ target ] );
                                        if ((int)fwrite( outdata, sizeof(outdata), 1, fs_list[ target ] ) !=1){
                                            usleep(50000);
                                            if ((int)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(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;
}


//////////////////////////////////////////////////////////////////////
vector<string> D4Matrix::
PutOpenedDataPath(){
    vector<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 D4Matrix::
GetPartOfD4Mat( UInt4 fs_index, float data[], UInt4 top_posi, UInt4 num_to_get){
    //cout << "@@@ GetPartOfD4Mat start fs_index="<<fs_index << 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 = fread( data, sizeof(float)*3, num_to_get, fs_list[ fs_index ] );

        return ret;
    }else{
        UtsusemiError( MessageTag + " Files are not opened. " );
        return -3;
    }
}
//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
    SliceMat3D( ElementContainerMatrix* _ecm, vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> def_axes, vector<Double> foldings, vector<string> key_axes ){
    // a1range has 2 double min and max
    if (!isFilesOpened) _OpenFiles();
    
    vector< vector<Double> > ArList;
    vector<UInt4> def_ind,NumList;
    if (_CalcRangeInfo( 3, a1range, a2range, a3range, a4range, def_axes, def_ind, ArList, NumList )){
    }else{
        return -1;
    }
    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];

    if (key_axes.size()!=3){
        UtsusemiError( MessageTag+"SliceMat3D > key_axes is invalid." );
        return -1;
    }
    string keyX = key_axes[0];
    string keyY = key_axes[1];
    string keyZ = key_axes[2];
    
    // 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;
            }
        }
    }
    
    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{
                        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];
                        }
                    }
                } // Loop NumBin[2]
            }// Loop NumBin[1]
        }// Loop NumBin[0]
    }// Loop NumBin[3]
    
    vector< vector< vector<Double> > > outDArray, outEArray;
    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);


    
    _ecm->Allocate( n_X );
    
    Double xval=0.0;
    Double yval=0.0;
    Double zval=0.0;
    string xtitle = "X";
    string ytitle = "Y";
    string ztitle = "Z";
    
    for (UInt4 i=0; i<n_X; i++){
        ElementContainerArray *eca = new ElementContainerArray();
        HeaderBase* eca_hh = eca->PutHeaderPointer();
        vector<Double> xr(2);
        xr[0]=oxArray[i];
        xr[1]=oxArray[i+1];
        eca_hh->Add(UTSUSEMI_KEY_HEAD_XRANBE, 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();
            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;
            
            vector<Double> Int( n_Z, 0.0 );
            vector<Double> Err( n_Z, 0.0 );
            vector<Double> vx( n_Z, xval );
            vector<Double> vy( n_Z, yval );
            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);
    
    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 0;
    
}
//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
OutputText3D( vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> def_axes, vector<Double> foldings, string filename, bool isIgnoreMaskVal, string maskValStr){
    // a1range has 2 double min and max
    if (!isFilesOpened) _OpenFiles();
    
    vector< vector<Double> > ArList;
    vector<UInt4> def_ind,NumList;
    if (_CalcRangeInfo( 3, 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 n_X = NumList[0];
    UInt4 n_Y = NumList[1];
    UInt4 n_Z = NumList[2];

    if (foldings.empty()) foldings.resize(4,-1.0);
    // 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;
            }
        }
    }
    
    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]);
        if (iX3<10) UtsusemiMessage( MessageTag+"x3, ix3="+stools->DoubleToString(x3)+","+stools->UInt4ToString(iXs[3]) );
        // 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){
                        UtsusemiMessage( 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];
                        }
                    }
                } // Loop NumBin[2]
            }// Loop NumBin[1]
        }// Loop NumBin[0]
    }// Loop NumBin[3]
    
    vector< vector< vector<Double> > > outDArray, outEArray;
    vector<Double> oxArray, oyArray, ozArray;
    
    oxArray.resize(n_X);
    oyArray.resize(n_Y);
    ozArray.resize(n_Z);
    
    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);
    
    outDArray.resize( n_X );
    outEArray.resize( n_X );
    for (UInt4 xx=0;xx<n_X;xx++){
        outDArray[xx].resize( n_Y );
        outEArray[xx].resize( n_Y );
        for (UInt4 yy=0;yy<n_Y;yy++){
            outDArray[xx][yy].resize( n_Z,0.0 );
            outEArray[xx][yy].resize( n_Z,0.0 );
            for (UInt4 zz=0;zz<n_Z;zz++){
                if (cArray[xx][yy][zz]!=0.0){
                    outDArray[xx][yy][zz] = dArray[xx][yy][zz]/cArray[xx][yy][zz];
                    outEArray[xx][yy][zz] = sqrt( eArray[xx][yy][zz] )/cArray[xx][yy][zz];
                }else{
                    outDArray[xx][yy][zz] = UTSUSEMIMASKVALUE64;
                    outEArray[xx][yy][zz] = 0.0;
                }
            }
        }
    }
    
    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;
    
    Double outMaskVal = UTSUSEMIMASKVALUE64;
    if (isIgnoreMaskVal){
    }else{
        if (maskValStr.find("MASK")==string::npos)
            outMaskVal = stools->StringToDouble( maskValStr );
    }

    FILE *fp;
    fp = fopen( filename.c_str(), "w" );
    fprintf( fp, "# XRANGE=%f, %f, %f, %f\n", oxArray[0], oxArray[ n_X-1 ], ArList[indX][2], (Double)(n_X) );
    fprintf( fp, "# YRANGE=%f, %f, %f, %f\n", oyArray[0], oyArray[ n_Y-1 ], ArList[indY][2], (Double)(n_Y) );
    fprintf( fp, "# ZRANGE=%f, %f, %f, %f\n", ozArray[0], ozArray[ n_Z-1 ], ArList[indZ][2], (Double)(n_Z) );
    for (UInt4 xx=0;xx<n_X;xx++){
        for (UInt4 yy=0;yy<n_Y;yy++){
            for (UInt4 zz=0;zz<n_Z;zz++){
                if (outDArray[xx][yy][zz]!=UTSUSEMIMASKVALUE64){
                    fprintf( fp, "%f, %f, %f, %g, %g\n", oxArray[xx], oyArray[yy], ozArray[zz], outDArray[xx][yy][zz],outEArray[xx][yy][zz] );
                    //fprintf( fp, "%f, %f, %f, %f\n", (Double)xx, (Double)yy, (Double)zz, outDArray[xx][yy][zz] );
                }else if (isIgnoreMaskVal){
                }else{
                    fprintf( fp, "%f, %f, %f, %g, %g\n", oxArray[xx], oyArray[yy], ozArray[zz],outMaskVal, 0.0 );
                }
            }
        }
    }
    fclose(fp);
    
    return 0;

}
//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
DumpD4MatToFile( vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> def_axes, vector<Double> foldings, string filename, bool isText ){
    // a1range has 2 double min and max
    if (!isFilesOpened) _OpenFiles();
    
    vector< vector<Double> > ArList;
    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);
    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" );
        fprintf( fp, "# XRANGE=%f, %f, %f, %f\n", oxArray[0], oxArray[ n_X-1 ], ArList[indX][2], (Double)(n_X) );
        fprintf( fp, "# YRANGE=%f, %f, %f, %f\n", oyArray[0], oyArray[ n_Y-1 ], ArList[indY][2], (Double)(n_Y) );
        fprintf( fp, "# ZRANGE=%f, %f, %f, %f\n", ozArray[0], ozArray[ n_Z-1 ], ArList[indZ][2], (Double)(n_Z) );
        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" );
    }

    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]);
        if (iX3<10) UtsusemiMessage( MessageTag+"x3, ix3="+stools->DoubleToString(x3)+","+stools->UInt4ToString(iXs[3]) );
        // 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 = oxArray[ iXs[indX] ];
                        float yy = oyArray[ iXs[indY] ];
                        float zz = ozArray[ iXs[indZ] ];
                        float tt = otArray[ iXs[indT] ];
                        float ii = 0.0;
                        float ee = 0.0;
                        if (dat[2]!=0.0){
                            ii=dat[0]/dat[2];
                            ee=sqrt( dat[1] )/dat[2];
                        }
                        if (isText)
                            fprintf( fp, "%f, %f, %f, %f, %g, %g\n", xx, yy, zz, tt, ii, ee );
                        else{
                            fwrite( &xx, sizeof(xx), 1, fp );
                            fwrite( &yy, sizeof(yy), 1, fp );
                            fwrite( &zz, sizeof(zz), 1, fp );
                            fwrite( &tt, sizeof(tt), 1, fp );
                            fwrite( &ii, sizeof(ii), 1, fp );
                            fwrite( &ee, sizeof(ee), 1, fp );
                        }
                    }
                } // Loop NumBin[2]
            }// Loop NumBin[1]
        }// Loop NumBin[0]
    }// Loop NumBin[3]

    fclose(fp);
    
    return 0;
}
//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
OutputText3DOld( vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> def_axes, vector<Int4> foldings, string filename, bool isIgnoreMaskVal, string maskValStr  ){
    if (!isFilesOpened) _OpenFiles();
    
    vector< vector<Double> > ArList;

    ArList.clear();
    ArList.push_back( a1range );
    ArList.push_back( a2range );
    ArList.push_back( a3range );
    ArList.push_back( a4range );
    
    vector< Int4 > AxisNo;
    AxisNo.clear();
    for (UInt4 i=0;i<4;i++) AxisNo.push_back(-1);
    
    UInt4 AxisX,AxisY,AxisZ;
    AxisX = AxisY = AxisZ = 0;
    for (UInt4 i=0;i<def_axes.size();i++){
        if (def_axes[i]=="X"){
            AxisNo[i]=0;
            AxisX = i;
        }
        if (def_axes[i]=="Y"){
            AxisNo[i]=1;
            AxisY = i;
        }
        if (def_axes[i]=="Z"){
            AxisNo[i]=2;
            AxisZ = i;
        }
        if (def_axes[i]=="T") AxisNo[i]=3;
    }
    
    // for Folding
    vector< vector<UInt4> > i_range,if1_range,if2_range;
    i_range.clear();
    if1_range.clear();
    if2_range.clear();
    
    vector<bool> isFoldOverZero(4,true);
    
    for (UInt4 i=0;i<ArList.size();i++){
        UInt4 cnt = 0;
        Double cval = 0.0;
        vector<UInt4> rv(2,0);
        vector<UInt4> rv1(2,0);
        vector<UInt4> rv2(2,0);

        if (ArList[i][0]>ArList[i][1]){
            Double tmp = ArList[i][0];
            ArList[i][0] = ArList[i][1];
            ArList[i][1] = tmp;
        }
        
        if ((foldings[i]==1)&&((ArList[i][0]*ArList[i][1])<0.0)){
            isFoldOverZero[i]=true;
        }else{
            isFoldOverZero[i]=false;
        }
        while(true){
            cval = range_list[i][0]+(range_list[i][2]+1.0E-15)*Double(cnt);
            if ((rv[0]==0)&&(cval>=ArList[i][0])) rv[0] = cnt;
            if ((rv[1]==0)&&(cval>=ArList[i][1])) rv[1] = cnt-1;

            if (foldings[i]==0){
                if ((rv1[0]==0)&&(cval>=ArList[i][0])) rv1[0] = cnt;
                if ((rv1[1]==0)&&(cval>=ArList[i][1])) rv1[1] = cnt-1;
            }else{
                if (isFoldOverZero[i]){
                    if ((rv1[0]==0)&&(cval>=0.0)) rv1[0] = cnt;
                    if ((rv1[1]==0)&&(cval>=ArList[i][1])) rv1[1] = cnt-1;
                    if ((rv2[0]==0)&&(cval>=-fabs(ArList[i][1]))) rv2[0] = cnt;
                    if ((rv2[1]==0)&&(cval>=0.0)) rv2[1] = cnt-1;
                }else{
                    if ((rv1[0]==0)&&(cval>=fabs(ArList[i][0]))) rv1[0] = cnt;
                    if ((rv1[1]==0)&&(cval>=fabs(ArList[i][1]))) rv1[1] = cnt-1;
                    if ((rv2[0]==0)&&(cval>=-fabs(ArList[i][1]))) rv2[0] = cnt;
                    if ((rv2[1]==0)&&(cval>=-fabs(ArList[i][0]))) rv2[1] = cnt-1;
                }
            }
            if (cval>=range_list[i][1]){
                if (rv[1]==0) rv[1] = cnt-1;
                if (rv1[1]==0) rv1[1] = cnt-1;
                break;
            }else{
                cnt++;
            }
        }
        i_range.push_back(rv);
        if1_range.push_back(rv1);
        if2_range.push_back(rv2);
    }
    
    
    
    UInt4 n_X, n_Y, n_Z;
    n_X = n_Y = n_Z = 0;
    Int4 i_shift_x = 0;
    Int4 i_shift_y = 0;
    Int4 i_shift_z = 0;
    if (foldings[ AxisX ]==0){
        n_X = i_range[ AxisX ][1] - i_range[ AxisX ][0] + 1;
    }else if (isFoldOverZero[ AxisX ]){
        n_X = i_range[ AxisX ][1] - i_range[ AxisX ][0] + 1;
        i_shift_x = if1_range[ AxisX ][0] - i_range[ AxisX ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisX ][1] - if1_range[ AxisX ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisX ][1] - if2_range[ AxisX ][0] + 1;
        if (tmp1>=tmp2){
            n_X = tmp1;
        }else{
            n_X = tmp2;
        }
    }
    if (foldings[ AxisY ]==0){
        n_Y = i_range[ AxisY ][1] - i_range[ AxisY ][0] + 1;
    }else if (isFoldOverZero[ AxisY ]){
        n_Y = i_range[ AxisY ][1] - i_range[ AxisY ][0] + 1;
        i_shift_y = if1_range[ AxisY ][0] - i_range[ AxisY ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisY ][1] - if1_range[ AxisY ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisY ][1] - if2_range[ AxisY ][0] + 1;
        if (tmp1>=tmp2){
            n_Y = tmp1;
        }else{
            n_Y = tmp2;
        }
    }
    if (foldings[ AxisZ ]==0){
        n_Z = i_range[ AxisZ ][1] - i_range[ AxisZ ][0] + 1;
    }else if (isFoldOverZero[ AxisZ ]){
        n_Z = i_range[ AxisZ ][1] - i_range[ AxisZ ][0] + 1;
        i_shift_z = if1_range[ AxisZ ][0] - i_range[ AxisZ ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisZ ][1] - if1_range[ AxisZ ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisZ ][1] - if2_range[ AxisZ ][0] + 1;
        if (tmp1>=tmp2){
            n_Z = tmp1;
        }else{
            n_Z = tmp2;
        }
    }

    
    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;
            }
        }
    }

    
    string msg = MessageTag+" AxisNo="+stools->UInt4ToString(AxisNo[0])+stools->UInt4ToString(AxisNo[1]);
    msg += stools->UInt4ToString(AxisNo[2])+stools->UInt4ToString(AxisNo[3]);
    UtsusemiMessage(msg);
    
    if (isDebugMode) {
        cout << MessageTag << "-------" << endl;
        cout << MessageTag << "index_of_blocks.size=" << index_of_blocks.size() << endl;
        cout << MessageTag << "index_of_blocks[0]and [last]=" << index_of_blocks[0];
        cout << "," << index_of_blocks[ index_of_blocks.size()-1 ] << endl;
        cout << MessageTag << "-------" << endl;
        for (UInt4 i=0;i<4;i++){
            cout << " i_range[" << i <<"]="<<i_range[i][0]<<","<<i_range[i][1]<<endl;
            cout << "if1_range[" << i <<"]="<<if1_range[i][0]<<","<<if1_range[i][1]<<endl;
            cout << "if2_range[" << i <<"]="<<if2_range[i][0]<<","<<if2_range[i][1]<<endl;
        }
        cout << MessageTag << "-------" << endl;
        cout << "n_X = " << n_X << endl;
        cout << "n_Y = " << n_Y << endl;
        cout << "i_shift_x = " << i_shift_x <<endl;
        cout << "i_shift_y = " << i_shift_y <<endl;

    }
    
    
    vector< vector< UInt4 > > fold_ptn;
    fold_ptn.clear();
    vector<UInt4> t_max;
    for (UInt4 i=0; i<4; i++){
        if (foldings[i]==0){
            t_max.push_back(1);
        }else{
            t_max.push_back(2);
        }
    }
    
    for (UInt4 t0=0; t0<t_max[0]; t0++){
        for (UInt4 t1=0; t1<t_max[1]; t1++){
            for (UInt4 t2=0; t2<t_max[2]; t2++){
                for (UInt4 t3=0; t3<t_max[3]; t3++){
                    vector< UInt4 > vv;
                    vv.clear();
                    vv.push_back( t0 );
                    vv.push_back( t1 );
                    vv.push_back( t2 );
                    vv.push_back( t3 );
                    fold_ptn.push_back(vv);
                }
            }
        }
    }

    UInt4 AX[4] = {0,0,0,0};

    UInt4 ind0,ind1,ind2,ind3;
    ind0 = ind1 = ind2 = ind3 = 0;
    
    vector<UInt4> imin, imax;
    imin.clear();
    imax.clear();
                    
    for (UInt4 i=0; i<fold_ptn.size(); i++){
        string msg = MessageTag+"fold pattern ="+stools->UInt4ToString(fold_ptn[i][0])+",";
        msg += stools->UInt4ToString(fold_ptn[i][1])+","+stools->UInt4ToString(fold_ptn[i][2])+","+stools->UInt4ToString(fold_ptn[i][3]);
        UtsusemiMessage( msg );
        imin.clear();
        imax.clear();
        for (UInt4 j=0; j<4; j++){
            imin.push_back( if1_range[j][0] );
            imax.push_back( if1_range[j][1] );
            if (fold_ptn[i][j]==1){
                imin[j] = if2_range[j][0];
                imax[j] = if2_range[j][1];
            }
        }
        if (isDebugMode) {
            cout << "imin=" << imin[0] <<","<< imin[1]<<","<< imin[2] <<","<< imin[3] << endl;
            cout << "imax=" << imax[0] <<","<< imax[1]<<","<< imax[2] <<","<< imax[3] << endl;
        }

        for (UInt4 i3=imin[3]; i3<=imax[3];i3++){
            ind3 = i3 * size_of_Ax[3];
            
            UInt4 target = 0;
            for (UInt4 j=0;j<(index_of_blocks.size()-1);j++){
                if ( (i3>=index_of_blocks[j])&&(i3<index_of_blocks[j+1]) ) {
                    target = j;
                    ind3 = (i3 - index_of_blocks[j])*size_of_Ax[3];
                    break;
                }
            }
            if (fold_ptn[i][3]==0) {
                AX[ AxisNo[3] ] = i3 - imin[3];
            }else{
                AX[ AxisNo[3] ] = imax[3] - i3;
            }
            for (UInt4 i0=imin[0]; i0<=imax[0]; i0++){
                if (fold_ptn[i][0]==0) {
                    AX[ AxisNo[0] ] = i0 - imin[0];
                }else{
                    AX[ AxisNo[0] ] = imax[0] - i0;
                }
                ind0 = i0*size_of_Ax[0];
                for (UInt4 i1=imin[1]; i1<=imax[1]; i1++){
                    if (fold_ptn[i][1]==0) {
                        AX[ AxisNo[1] ] = i1 - imin[1];
                    }else{
                        AX[ AxisNo[1] ] = imax[1] - i1;
                    }
                    ind1 = i1*size_of_Ax[1];
                    for (UInt4 i2=imin[2]; i2<=imax[2]; i2++){
                        if (fold_ptn[i][2]==0) {
                            AX[ AxisNo[2] ] = i2 - imin[2];
                        }else{
                            AX[ AxisNo[2] ] = imax[2] - i2;
                        }
                        ind2 = i2*size_of_Ax[2];
                        
                        UInt4 ind = ind0 + ind1 + ind2 + ind3;
                        float dat[3];
                        fseek( fs_list[ target ], ind, SEEK_SET );
                        if ((int)fread( dat, sizeof(dat), 1, fs_list[ target ] )!=1){
                            UtsusemiError( MessageTag + "SliceMat failed to read data");
                        }else{
                            if (dat[2]!=0.0){
                                //cout << "### " << AX[0] + i_shift_x << "," << AX[1] + i_shift_y << ",";
                                //cout << AX[2] + i_shift_z << endl;
                                dArray[ AX[0] + i_shift_x ][ AX[1] + i_shift_y ][ AX[2] + i_shift_z ] += dat[0];
                                eArray[ AX[0] + i_shift_x ][ AX[1] + i_shift_y ][ AX[2] + i_shift_z ] += dat[1];
                                cArray[ AX[0] + i_shift_x ][ AX[1] + i_shift_y ][ AX[2] + i_shift_z ] += dat[2];
                                //cout << "    " << cArray[ AX[0] + i_shift_x ][ AX[1] + i_shift_y ][ AX[2] + i_shift_z ] << endl;
                            }
                        }
                    }
                }
            }
        }
    }
    
    vector< vector< vector<Double> > > outDArray, outEArray;
    vector<Double> oxArray, oyArray, ozArray;
    
    for (UInt4 i=i_range[AxisX][0];i<(i_range[AxisX][1]+1);i++){
        oxArray.push_back( range_list[AxisX][0] + range_list[AxisX][2]*(float(i)-0.5));
    }
    oxArray.push_back( range_list[AxisX][0] + range_list[AxisX][2]*(float(i_range[AxisX][1])+0.5 ));
    
    for (UInt4 i=i_range[AxisY][0];i<(i_range[AxisY][1]+1);i++){
        oyArray.push_back( range_list[AxisY][0] + range_list[AxisY][2]*(float(i)-0.5));
    }
    oyArray.push_back( range_list[AxisY][0] + range_list[AxisY][2]*(float(i_range[AxisY][1])+0.5));

    for (UInt4 i=i_range[AxisZ][0];i<(i_range[AxisZ][1]+1);i++){
        ozArray.push_back( range_list[AxisZ][0] + range_list[AxisZ][2]*(float(i)-0.5));
    }
    ozArray.push_back( range_list[AxisZ][0] + range_list[AxisZ][2]*(float(i_range[AxisZ][1])+0.5));
    
    outDArray.resize( n_X );
    outEArray.resize( n_X );
    for (UInt4 xx=0;xx<n_X;xx++){
        outDArray[xx].resize( n_Y );
        outEArray[xx].resize( n_Y );
        for (UInt4 yy=0;yy<n_Y;yy++){
            outDArray[xx][yy].resize( n_Z,0.0 );
            outEArray[xx][yy].resize( n_Z,0.0 );
            for (UInt4 zz=0;zz<n_Z;zz++){
                if (cArray[xx][yy][zz]!=0.0){
                    outDArray[xx][yy][zz] = dArray[xx][yy][zz]/cArray[xx][yy][zz];
                    outEArray[xx][yy][zz] = sqrt( eArray[xx][yy][zz] )/cArray[xx][yy][zz];
                }else{
                    //cout << "## cArray=0 " << xx << "," << yy << "," << zz << endl;
                    //outDArray[xx][yy][zz] = 0.0;
                    outDArray[xx][yy][zz] = UTSUSEMIMASKVALUE64;
                    outEArray[xx][yy][zz] = 0.0;
                }
            }
        }
    }
    
    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;
    
    Double outMaskVal = UTSUSEMIMASKVALUE64;
    if (isIgnoreMaskVal){
    }else{
        if (maskValStr.find("MASK")==string::npos)
            outMaskVal = stools->StringToDouble( maskValStr );
    }

    FILE *fp;
    fp = fopen( filename.c_str(), "w" );
    fprintf( fp, "# XRANGE=%f, %f, %f, %f\n", oxArray[0], oxArray[ n_X-1 ], range_list[AxisX][2], (Double)(n_X) );
    fprintf( fp, "# YRANGE=%f, %f, %f, %f\n", oyArray[0], oyArray[ n_Y-1 ], range_list[AxisY][2], (Double)(n_Y) );
    fprintf( fp, "# ZRANGE=%f, %f, %f, %f\n", ozArray[0], ozArray[ n_Z-1 ], range_list[AxisZ][2], (Double)(n_Z) );
    for (UInt4 xx=0;xx<n_X;xx++){
        for (UInt4 yy=0;yy<n_Y;yy++){
            for (UInt4 zz=0;zz<n_Z;zz++){
                if (outDArray[xx][yy][zz]!=UTSUSEMIMASKVALUE64){
                    fprintf( fp, "%f, %f, %f, %f, %f\n", oxArray[xx], oyArray[yy], ozArray[zz], outDArray[xx][yy][zz],outEArray[xx][yy][zz] );
                    //fprintf( fp, "%f, %f, %f, %f\n", (Double)xx, (Double)yy, (Double)zz, outDArray[xx][yy][zz] );
                }else if (isIgnoreMaskVal){
                }else{
                    fprintf( fp, "%f, %f, %f, %f, %f\n", oxArray[xx], oyArray[yy], ozArray[zz],outMaskVal, 0.0 );
                }
            }
        }
    }
    fclose(fp);
    
    return 0;
}

//////////////////////////////////////////////////////////////////////
Int4 D4Matrix::
DumpD4MatToFileOld( vector<Double> a1range, vector<Double> a2range, vector<Double> a3range, vector<Double> a4range, vector<string> def_axes, vector<Int4> foldings, string filename, bool isText ){
    if (!isFilesOpened) _OpenFiles();
    
    vector< vector<Double> > ArList;

    ArList.clear();
    ArList.push_back( a1range );
    ArList.push_back( a2range );
    ArList.push_back( a3range );
    ArList.push_back( a4range );
    
    vector< Int4 > AxisNo;
    AxisNo.clear();
    for (UInt4 i=0;i<4;i++) AxisNo.push_back(-1);
    
    UInt4 AxisX,AxisY,AxisZ,AxisT;
    AxisX = AxisY = AxisZ = AxisT = 0;
    for (UInt4 i=0;i<def_axes.size();i++){
        if (def_axes[i]=="X"){
            AxisNo[i]=0;
            AxisX = i;
        }
        if (def_axes[i]=="Y"){
            AxisNo[i]=1;
            AxisY = i;
        }
        if (def_axes[i]=="Z"){
            AxisNo[i]=2;
            AxisZ = i;
        }
        if (def_axes[i]=="T"){
            AxisNo[i]=3;
            AxisT = i;
        }
    }
    
    // for Folding
    vector< vector<UInt4> > i_range,if1_range,if2_range;
    i_range.clear();
    if1_range.clear();
    if2_range.clear();
    
    vector<bool> isFoldOverZero(4,true);
    
    for (UInt4 i=0;i<ArList.size();i++){
        UInt4 cnt = 0;
        Double cval = 0.0;
        vector<UInt4> rv(2,0);
        vector<UInt4> rv1(2,0);
        vector<UInt4> rv2(2,0);

        if (ArList[i][0]>ArList[i][1]){
            Double tmp = ArList[i][0];
            ArList[i][0] = ArList[i][1];
            ArList[i][1] = tmp;
        }
        
        if ((foldings[i]==1)&&((ArList[i][0]*ArList[i][1])<0.0)){
            isFoldOverZero[i]=true;
        }else{
            isFoldOverZero[i]=false;
        }
        while(true){
            cval = range_list[i][0]+(range_list[i][2]+1.0E-15)*Double(cnt);
            if ((rv[0]==0)&&(cval>=ArList[i][0])) rv[0] = cnt;
            if ((rv[1]==0)&&(cval>=ArList[i][1])) rv[1] = cnt-1;

            if (foldings[i]==0){
                if ((rv1[0]==0)&&(cval>=ArList[i][0])) rv1[0] = cnt;
                if ((rv1[1]==0)&&(cval>=ArList[i][1])) rv1[1] = cnt-1;
            }else{
                if (isFoldOverZero[i]){
                    if ((rv1[0]==0)&&(cval>=0.0)) rv1[0] = cnt;
                    if ((rv1[1]==0)&&(cval>=ArList[i][1])) rv1[1] = cnt-1;
                    if ((rv2[0]==0)&&(cval>=-fabs(ArList[i][1]))) rv2[0] = cnt;
                    if ((rv2[1]==0)&&(cval>=0.0)) rv2[1] = cnt-1;
                }else{
                    if ((rv1[0]==0)&&(cval>=fabs(ArList[i][0]))) rv1[0] = cnt;
                    if ((rv1[1]==0)&&(cval>=fabs(ArList[i][1]))) rv1[1] = cnt-1;
                    if ((rv2[0]==0)&&(cval>=-fabs(ArList[i][1]))) rv2[0] = cnt;
                    if ((rv2[1]==0)&&(cval>=-fabs(ArList[i][0]))) rv2[1] = cnt-1;
                }
            }
            if (cval>=range_list[i][1]){
                if (rv[1]==0) rv[1] = cnt-1;
                if (rv1[1]==0) rv1[1] = cnt-1;
                break;
            }else{
                cnt++;
            }
        }
        i_range.push_back(rv);
        if1_range.push_back(rv1);
        if2_range.push_back(rv2);
    }
    
    
    
    UInt4 n_X, n_Y, n_Z, n_T;
    n_X = n_Y = n_Z = n_T = 0;
    Int4 i_shift_x = 0;
    Int4 i_shift_y = 0;
    Int4 i_shift_z = 0;
    Int4 i_shift_t = 0;
    if (foldings[ AxisX ]==0){
        n_X = i_range[ AxisX ][1] - i_range[ AxisX ][0] + 1;
    }else if (isFoldOverZero[ AxisX ]){
        n_X = i_range[ AxisX ][1] - i_range[ AxisX ][0] + 1;
        i_shift_x = if1_range[ AxisX ][0] - i_range[ AxisX ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisX ][1] - if1_range[ AxisX ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisX ][1] - if2_range[ AxisX ][0] + 1;
        if (tmp1>=tmp2){
            n_X = tmp1;
        }else{
            n_X = tmp2;
        }
    }
    if (foldings[ AxisY ]==0){
        n_Y = i_range[ AxisY ][1] - i_range[ AxisY ][0] + 1;
    }else if (isFoldOverZero[ AxisY ]){
        n_Y = i_range[ AxisY ][1] - i_range[ AxisY ][0] + 1;
        i_shift_y = if1_range[ AxisY ][0] - i_range[ AxisY ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisY ][1] - if1_range[ AxisY ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisY ][1] - if2_range[ AxisY ][0] + 1;
        if (tmp1>=tmp2){
            n_Y = tmp1;
        }else{
            n_Y = tmp2;
        }
    }
    if (foldings[ AxisZ ]==0){
        n_Z = i_range[ AxisZ ][1] - i_range[ AxisZ ][0] + 1;
    }else if (isFoldOverZero[ AxisZ ]){
        n_Z = i_range[ AxisZ ][1] - i_range[ AxisZ ][0] + 1;
        i_shift_z = if1_range[ AxisZ ][0] - i_range[ AxisZ ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisZ ][1] - if1_range[ AxisZ ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisZ ][1] - if2_range[ AxisZ ][0] + 1;
        if (tmp1>=tmp2){
            n_Z = tmp1;
        }else{
            n_Z = tmp2;
        }
    }
    if (foldings[ AxisT ]==0){
        n_T = i_range[ AxisT ][1] - i_range[ AxisT ][0] + 1;
    }else if (isFoldOverZero[ AxisT ]){
        n_T = i_range[ AxisT ][1] - i_range[ AxisT ][0] + 1;
        i_shift_t = if1_range[ AxisT ][0] - i_range[ AxisT ][0];
    }else{
        UInt4 tmp1 = if1_range[ AxisT ][1] - if1_range[ AxisT ][0] + 1;
        UInt4 tmp2 = if2_range[ AxisT ][1] - if2_range[ AxisT ][0] + 1;
        if (tmp1>=tmp2){
            n_T = tmp1;
        }else{
            n_T = tmp2;
        }
    }

    vector<Double> oxArray, oyArray, ozArray, otArray;
    
    for (UInt4 i=i_range[AxisX][0];i<(i_range[AxisX][1]+1);i++){
        oxArray.push_back( range_list[AxisX][0] + range_list[AxisX][2]*(float(i)-0.5));
    }
    oxArray.push_back( range_list[AxisX][0] + range_list[AxisX][2]*(float(i_range[AxisX][1])+0.5 ));
    
    for (UInt4 i=i_range[AxisY][0];i<(i_range[AxisY][1]+1);i++){
        oyArray.push_back( range_list[AxisY][0] + range_list[AxisY][2]*(float(i)-0.5));
    }
    oyArray.push_back( range_list[AxisY][0] + range_list[AxisY][2]*(float(i_range[AxisY][1])+0.5));

    for (UInt4 i=i_range[AxisZ][0];i<(i_range[AxisZ][1]+1);i++){
        ozArray.push_back( range_list[AxisZ][0] + range_list[AxisZ][2]*(float(i)-0.5));
    }
    ozArray.push_back( range_list[AxisZ][0] + range_list[AxisZ][2]*(float(i_range[AxisZ][1])+0.5));

    for (UInt4 i=i_range[AxisT][0];i<(i_range[AxisT][1]+1);i++){
        otArray.push_back( range_list[AxisT][0] + range_list[AxisT][2]*(float(i)-0.5));
    }
    otArray.push_back( range_list[AxisT][0] + range_list[AxisZ][2]*(float(i_range[AxisT][1])+0.5));
    
    

    string msg = MessageTag+" AxisNo="+stools->UInt4ToString(AxisNo[0])+stools->UInt4ToString(AxisNo[1]);
    msg += stools->UInt4ToString(AxisNo[2])+stools->UInt4ToString(AxisNo[3]);
    UtsusemiMessage( msg );
    
    if (isDebugMode) {
        cout << MessageTag << "-------" << endl;
        cout << MessageTag << "index_of_blocks.size=" << index_of_blocks.size() << endl;
        cout << MessageTag << "index_of_blocks[0]and [last]=" << index_of_blocks[0];
        cout << "," << index_of_blocks[ index_of_blocks.size()-1 ] << endl;
        cout << MessageTag << "-------" << endl;
        for (UInt4 i=0;i<4;i++){
            cout << " i_range[" << i <<"]="<<i_range[i][0]<<","<<i_range[i][1]<<endl;
            cout << "if1_range[" << i <<"]="<<if1_range[i][0]<<","<<if1_range[i][1]<<endl;
            cout << "if2_range[" << i <<"]="<<if2_range[i][0]<<","<<if2_range[i][1]<<endl;
        }
        cout << MessageTag << "-------" << endl;
        cout << "n_X = " << n_X << endl;
        cout << "n_Y = " << n_Y << endl;
        cout << "i_shift_x = " << i_shift_x <<endl;
        cout << "i_shift_y = " << i_shift_y <<endl;

    }
    
    
    vector< vector< UInt4 > > fold_ptn;
    fold_ptn.clear();
    vector<UInt4> t_max;
    for (UInt4 i=0; i<4; i++){
        if (foldings[i]==0){
            t_max.push_back(1);
        }else{
            t_max.push_back(2);
        }
    }
    
    for (UInt4 t0=0; t0<t_max[0]; t0++){
        for (UInt4 t1=0; t1<t_max[1]; t1++){
            for (UInt4 t2=0; t2<t_max[2]; t2++){
                for (UInt4 t3=0; t3<t_max[3]; t3++){
                    vector< UInt4 > vv;
                    vv.clear();
                    vv.push_back( t0 );
                    vv.push_back( t1 );
                    vv.push_back( t2 );
                    vv.push_back( t3 );
                    fold_ptn.push_back(vv);
                }
            }
        }
    }

    UInt4 AX[4] = {0,0,0,0};

    UInt4 ind0,ind1,ind2,ind3;
    ind0 = ind1 = ind2 = ind3 = 0;
    
    vector<UInt4> imin, imax;
    imin.clear();
    imax.clear();
    
    FILE *fp;
    if (isText){
        fp = fopen( filename.c_str(), "w" );
        fprintf( fp, "# XRANGE=%f, %f, %f, %f\n", oxArray[0], oxArray[ n_X-1 ], range_list[AxisX][2], (Double)(n_X) );
        fprintf( fp, "# YRANGE=%f, %f, %f, %f\n", oyArray[0], oyArray[ n_Y-1 ], range_list[AxisY][2], (Double)(n_Y) );
        fprintf( fp, "# ZRANGE=%f, %f, %f, %f\n", ozArray[0], ozArray[ n_Z-1 ], range_list[AxisZ][2], (Double)(n_Z) );
        fprintf( fp, "# TRANGE=%f, %f, %f, %f\n", otArray[0], otArray[ n_T-1 ], range_list[AxisT][2], (Double)(n_T) );
    }else{
        fp = fopen( filename.c_str(), "wb" );
    }

    for (UInt4 i=0; i<fold_ptn.size(); i++){
        string msg = MessageTag+"fold pattern ="+stools->UInt4ToString(fold_ptn[i][0])+",";
        msg += stools->UInt4ToString(fold_ptn[i][1])+","+stools->UInt4ToString(fold_ptn[i][2])+","+stools->UInt4ToString(fold_ptn[i][3]);
        UtsusemiMessage( msg );
        imin.clear();
        imax.clear();
        for (UInt4 j=0; j<4; j++){
            imin.push_back( if1_range[j][0] );
            imax.push_back( if1_range[j][1] );
            if (fold_ptn[i][j]==1){
                imin[j] = if2_range[j][0];
                imax[j] = if2_range[j][1];
            }
        }
        if (isDebugMode) {
            cout << "imin=" << imin[0] <<","<< imin[1]<<","<< imin[2] <<","<< imin[3] << endl;
            cout << "imax=" << imax[0] <<","<< imax[1]<<","<< imax[2] <<","<< imax[3] << endl;
        }

        for (UInt4 i3=imin[3]; i3<=imax[3];i3++){
            ind3 = i3 * size_of_Ax[3];
            
            UInt4 target = 0;
            for (UInt4 j=0;j<(index_of_blocks.size()-1);j++){
                if ( (i3>=index_of_blocks[j])&&(i3<index_of_blocks[j+1]) ) {
                    target = j;
                    ind3 = (i3 - index_of_blocks[j])*size_of_Ax[3];
                    break;
                }
            }
            if (fold_ptn[i][3]==0) {
                AX[ AxisNo[3] ] = i3 - imin[3];
            }else{
                AX[ AxisNo[3] ] = imax[3] - i3;
            }
            for (UInt4 i0=imin[0]; i0<=imax[0]; i0++){
                if (fold_ptn[i][0]==0) {
                    AX[ AxisNo[0] ] = i0 - imin[0];
                }else{
                    AX[ AxisNo[0] ] = imax[0] - i0;
                }
                ind0 = i0*size_of_Ax[0];
                for (UInt4 i1=imin[1]; i1<=imax[1]; i1++){
                    if (fold_ptn[i][1]==0) {
                        AX[ AxisNo[1] ] = i1 - imin[1];
                    }else{
                        AX[ AxisNo[1] ] = imax[1] - i1;
                    }
                    ind1 = i1*size_of_Ax[1];
                    for (UInt4 i2=imin[2]; i2<=imax[2]; i2++){
                        if (fold_ptn[i][2]==0) {
                            AX[ AxisNo[2] ] = i2 - imin[2];
                        }else{
                            AX[ AxisNo[2] ] = imax[2] - i2;
                        }
                        ind2 = i2*size_of_Ax[2];
                        
                        UInt4 ind = ind0 + ind1 + ind2 + ind3;
                        float dat[3];
                        fseek( fs_list[ target ], ind, SEEK_SET );
                        if ((int)fread( dat, sizeof(dat), 1, fs_list[ target ] )!=1){
                            UtsusemiError( MessageTag+"SliceMat failed to read data");
                        }else{
                            float xx = oxArray[ AX[0] + i_shift_x ];
                            float yy = oyArray[ AX[1] + i_shift_y ];
                            float zz = ozArray[ AX[2] + i_shift_z ];
                            float tt = otArray[ AX[3] + i_shift_t ];
                            float ii = 0.0;
                            float ee = 0.0;
                            if (dat[2]!=0.0){
                                ii=dat[0]/dat[2];
                                ee = sqrt( dat[1] )/dat[2];
                            }
                            if (isText)
                                fprintf( fp, "%f, %f, %f, %f, %f, %f\n", xx, yy, zz, tt, ii, ee );
                            else{
                                fwrite( &xx, sizeof(xx), 1, fp );
                                fwrite( &yy, sizeof(yy), 1, fp );
                                fwrite( &zz, sizeof(zz), 1, fp );
                                fwrite( &tt, sizeof(tt), 1, fp );
                                fwrite( &ii, sizeof(ii), 1, fp );
                                fwrite( &ee, sizeof(ee), 1, fp );
                            }
                        }
                    }
                }
            }
        }
    }
    
    fclose(fp);
    
    return 0;
}
//////////////////////////////////////////////////////////////////////
const Int4 D4Matrix::ROTATE_AXIS_X = UtsusemiSqeCalc::ROTATE_AXIS_X;
const Int4 D4Matrix::ROTATE_AXIS_Y = UtsusemiSqeCalc::ROTATE_AXIS_Y;
const Int4 D4Matrix::ROTATE_AXIS_Z = UtsusemiSqeCalc::ROTATE_AXIS_Z;
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
AllocateNewMat( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range,
                PyObject* titles, string data_dir, string paramfile ){
    vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    vector< string > TTS = __gCppToPython.ListToStringVector( titles );
    AllocateNewMat(AX1,AX2,AX3,AX4,TTS,data_dir,paramfile);
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
SliceMat( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings ){
    vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    vector< string > DEF = __gCppToPython.ListToStringVector( def_axes );
    vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    SliceMat( AX1, AX2, AX3, AX4, DEF, FLD );
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
void D4Matrix::
SetAxTitles(PyObject* titles, bool isSaved ){
    vector< string > TTS = __gCppToPython.ListToStringVector( titles );
    SetAxTitles( TTS, isSaved );
}
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
SliceMat3D( ElementContainerMatrix* _ecm, PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, PyObject* key_axes ){
    vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    vector< string > DEF = __gCppToPython.ListToStringVector( def_axes );
    vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    vector< string > KYS = __gCppToPython.ListToStringVector( key_axes );
    if (0==SliceMat3D( _ecm, AX1, AX2, AX3, AX4, DEF, FLD, KYS )) return true;
    else return false;
}
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
OutputText3D( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, string filename, bool isIgnoreMaskVal, string maskValStr  ){
    vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    vector< string > DEF = __gCppToPython.ListToStringVector( def_axes );
    vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    if (0==OutputText3D( AX1, AX2, AX3, AX4, DEF, FLD, filename, isIgnoreMaskVal, maskValStr )) return true;
    else return false;
}
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
DumpD4MatToFile( PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* def_axes, PyObject* foldings, string filename, bool isText ){
    vector< Double > AX1 = __gCppToPython.ListToDoubleVector( a1range );
    vector< Double > AX2 = __gCppToPython.ListToDoubleVector( a2range );
    vector< Double > AX3 = __gCppToPython.ListToDoubleVector( a3range );
    vector< Double > AX4 = __gCppToPython.ListToDoubleVector( a4range );
    vector< string > DEF = __gCppToPython.ListToStringVector( def_axes );
    vector< Double > FLD = __gCppToPython.ListToDoubleVector( foldings );
    if (0== DumpD4MatToFile( AX1, AX2, AX3, AX4, DEF, FLD, filename, isText )) return true;
    else return false;
}
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
AllocateVirtualMat( PyObject* latticeConst, PyObject* Uvec, PyObject* Vvec,
                    PyObject* rotateSteps, PyObject* viewAxes, PyObject* phiSteps,
                    PyObject* a1range, PyObject* a2range, PyObject* a3range, PyObject* a4range, PyObject* titles ){
    _isGoodResult = false;
    if (_hwInfoForVirtualMatrix.empty()){
        UtsusemiError(MessageTag+"AllocateVirtualMat >> Not executed SetRunNoForVirtualMatrix ");
        return false;
    }
    vector< Double > LC = __gCppToPython.ListToDoubleVector( latticeConst );
    vector< Double > UV = __gCppToPython.ListToDoubleVector( Uvec );
    vector< Double > VV = __gCppToPython.ListToDoubleVector( Vvec );
    vector< Double > RS = __gCppToPython.ListToDoubleVector( rotateSteps );
    vector< Double > VA = __gCppToPython.ListToDoubleVector( viewAxes );
    vector< Double > PHV = __gCppToPython.ListToDoubleVector( phiSteps );

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

    AllocateVirtualMat( LC, UV, VV, RS, VA, _hwInfoForVirtualMatrix, PHV, AX1, AX2, AX3, AX4, TTS );
    
    return _isGoodResult;
}
//////////////////////////////////////////////////////////////////////
PyObject* D4Matrix::
EstimateRangeOfVirtualMat(PyObject* latticeConst, PyObject* Uvec, PyObject* Vvec,
                         PyObject* rotateSteps, PyObject* viewAxes, PyObject* phiSteps ){
    if (_hwInfoForVirtualMatrix.empty()){
        UtsusemiError(MessageTag+"AllocateVirtualMat >> Not executed SetRunNoForVirtualMatrix ");
        vector<Double> ret_empty;
        return __gCppToPython.VectorDoubleToList(ret_empty);
    }
    vector< Double > LC = __gCppToPython.ListToDoubleVector( latticeConst );
    vector< Double > UV = __gCppToPython.ListToDoubleVector( Uvec );
    vector< Double > VV = __gCppToPython.ListToDoubleVector( Vvec );
    vector< Double > RS = __gCppToPython.ListToDoubleVector( rotateSteps );
    vector< Double > VA = __gCppToPython.ListToDoubleVector( viewAxes );
    vector< Double > PHV = __gCppToPython.ListToDoubleVector( phiSteps );
    return __gCppToPython.VectorDoubleToList( EstimateRangeOfVirtualMat( LC, UV, VV, RS, VA, _hwInfoForVirtualMatrix, PHV ) );
}
//////////////////////////////////////////////////////////////////////
bool D4Matrix::
SetRunNoForVirtualMatrix( UInt4 runNo, PyObject* hwInfo ){
    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];
        sprintf( hist_param_c, "hw,%f,%f,%f,%f", HWI[0], HWI[2],HWI[3],HWI[1] ); // "hw, Ei, hw_min, hw_max, hw_delta"
        string hist_param(hist_param_c);
        if (UGH.SetConversionParameter( hist_param )){
            vector<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;
}
