Пример #1
0
    def decompose(self, nMode=0, method='snap', subtractMean=False):
        '''
        Compute the Dynamic Mode Decomposition/Koopman Mode Decomposition (DMD)
        
        Arguments:
            *nMode*: python integer.
             Number of modes of theDMD.
            
            *method*: python string. Default='snap'
             Type of DMD algorithm used. For the snapshot method, use DMDmethod='snap' and
             for the direct method, use DMDmethod='direct'. The default value is 'snap'.
             
             How to choose between 'snap' and 'direct': if surfX*surfY > N**2, use the snap
             method, it should increase the coputational speed for only a little loss in 
             precision.
             
            *subtractMean*: python bool. Default=False.
             If True, the DMD reduces to a DFT, see:
             Chen, K., Tu, J., & Rowley, C. (2012). Variants of dynamic mode 
             decomposition: boundary condition, Koopman, and Fourier analyses.
             Journal of Nonlinear Science.
            
        Remarks:
        use the key 'mode_norms' to plot the power spectral density, since:
        myDMD_piv.result['mode_norms'] =  np.linalg.norm(myDMD_piv.result['modes'],axis=0)**2
        
        '''

        nSnap = self.vecs.shape[1]
        nVecs = self.vecs.shape[0]

        if nMode > nSnap - 1 or nMode == 0:
            nMode = nSnap - 1

        if nMode > nVecs:
            nMode = nVecs

        if np.any(self.vecs):
            self.vecs = np.nan_to_num(self.vecs)

        if subtractMean:
            self.vecs = self.vecs - np.mean(self.vecs, axis=1, keepdims=True)
        #print nMode
        if method == 'snap':
            modes, ritz_vals, mode_norms = modred.compute_DMD_matrices_snaps_method(
                self.vecs, range(nMode))
        elif method == 'direct':
            modes, ritz_vals, mode_norms = modred.compute_DMD_matrices_snaps_method(
                self.vecs, range(nMode))
        else:
            print('error: argument ' + str(method) +
                  ' is not valid. Use \'snap\' or \'direct\'')

        self.result['modes'] = modes
        self.result['ritz_vals'] = ritz_vals
        self.result['mode_norms'] = mode_norms
        self.result['ai'] = np.array(
            [self.result['ritz_vals']**t for t in range(self.vecs.shape[1])])
        self.result['m'] = self.result['modes'].shape[1]
        self.addResiduals()
    def decompose(self,nMode=0,method='snap',subtractMean=False):
        '''
        Compute the Dynamic Mode Decomposition/Koopman Mode Decomposition (DMD)
        
        Arguments:
            *nMode*: python integer.
             Number of modes of theDMD.
            
            *method*: python string. Default='snap'
             Type of DMD algorithm used. For the snapshot method, use DMDmethod='snap' and
             for the direct method, use DMDmethod='direct'. The default value is 'snap'.
             
             How to choose between 'snap' and 'direct': if surfX*surfY > N**2, use the snap
             method, it should increase the coputational speed for only a little loss in 
             precision.
             
            *subtractMean*: python bool. Default=False.
             If True, the DMD reduces to a DFT, see:
             Chen, K., Tu, J., & Rowley, C. (2012). Variants of dynamic mode 
             decomposition: boundary condition, Koopman, and Fourier analyses.
             Journal of Nonlinear Science.
            
        Remarks:
        use the key 'mode_norms' to plot the power spectral density, since:
        myDMD_piv.result['mode_norms'] =  np.linalg.norm(myDMD_piv.result['modes'],axis=0)**2
        
        '''

            
        nSnap = self.vecs.shape[1]
        nVecs=self.vecs.shape[0]
        
        if nMode>nSnap-1 or nMode==0:
            nMode=nSnap-1

        if nMode>nVecs:
            nMode=nVecs
        
        if np.any(self.vecs):
            self.vecs = np.nan_to_num(self.vecs)
        
        if subtractMean:
            self.vecs=self.vecs-np.mean(self.vecs,axis=1,keepdims=True)
        #print nMode
        if method=='snap':
            modes, ritz_vals, mode_norms = modred.compute_DMD_matrices_snaps_method(self.vecs, range(nMode))
        elif method=='direct':
            modes, ritz_vals, mode_norms = modred.compute_DMD_matrices_snaps_method(self.vecs, range(nMode))
        else:
            print('error: argument '+str(method)+' is not valid. Use \'snap\' or \'direct\'')
            
        self.result['modes']=modes
        self.result['ritz_vals']=ritz_vals
        self.result['mode_norms']=mode_norms
        self.result['ai']=np.array([self.result['ritz_vals']**t for t in range(self.vecs.shape[1])])
        self.result['m']=self.result['modes'].shape[1]
        self.addResiduals()
Пример #3
0
    def calculate_dmd(data, n_modes=5):
        """Dynamic mode decomposition, using Uf as the series of vectors."""
        # create the matrix of snapshots by flattening the non
        # decomp axes so we have a 2d array where we index the
        # decomp axis like snapshots[:,i]
        # the decomposition axis is the x dimension of the front
        # relative data
        iz, ix, it = data.shape
        snapshots = data.transpose((0, 2, 1)).reshape((-1, ix))

        # remove nans
        # TODO: remove nans by interpolation earlier on
        # snapshots[np.where(np.isnan(snapshots))] = 0

        modes, ritz_values, norms \
            = mr.compute_DMD_matrices_snaps_method(snapshots, range(n_modes))

        # as array, reshape to data dims with mode number as first index
        reshaped_modes = modes.A.reshape((iz, it, -1)).transpose((2, 0, 1))
        return reshaped_modes
Пример #4
0
def compare_modred_sparse():
    """Compare output from modred with our sparse method."""
    import modred as mr
    import gc_turbulence as g

    run = g.ProcessedRun(g.default_processed + 'r13_12_16a.hdf5')
    # slice with no nans
    # ( or use # complement(find_nan_slice(run.Uf_[:])) )
    good_slice = (slice(None), slice(None), slice(46L, None))
    data = run.Uf_[good_slice]

    snapshots = sparse_dmd.SparseDMD.to_snaps(data, decomp_axis=1)

    modes, ritz_values, norms \
        = mr.compute_DMD_matrices_snaps_method(snapshots, slice(None))

    pmodes, pnorms \
        = mr.compute_POD_matrices_snaps_method(snapshots, slice(None))

    dmd = sparse_dmd.SparseDMD(snapshots)
Пример #5
0
def compare_modred_sparse():
    """Compare output from modred with our sparse method."""
    import modred as mr
    import gc_turbulence as g

    run = g.ProcessedRun(g.default_processed + 'r13_12_16a.hdf5')
    # slice with no nans
    # ( or use # complement(find_nan_slice(run.Uf_[:])) )
    good_slice = (slice(None), slice(None), slice(46L, None))
    data = run.Uf_[good_slice]

    snapshots = sparse_dmd.SparseDMD.to_snaps(data, decomp_axis=1)

    modes, ritz_values, norms \
        = mr.compute_DMD_matrices_snaps_method(snapshots, slice(None))

    pmodes, pnorms \
        = mr.compute_POD_matrices_snaps_method(snapshots, slice(None))

    dmd = sparse_dmd.SparseDMD(snapshots)
Пример #6
0
    def calculate_dmd(data, n_modes=5):
        """Dynamic mode decomposition, using Uf as the series of vectors."""
        # create the matrix of snapshots by flattening the non
        # decomp axes so we have a 2d array where we index the
        # decomp axis like snapshots[:,i]
        # the decomposition axis is the x dimension of the front
        # relative data
        iz, ix, it = data.shape
        snapshots = data.transpose((0, 2, 1)).reshape((-1, ix))

        # remove nans
        # TODO: remove nans by interpolation earlier on
        # snapshots[np.where(np.isnan(snapshots))] = 0

        modes, ritz_values, norms \
            = mr.compute_DMD_matrices_snaps_method(snapshots, range(n_modes))

        # as array, reshape to data dims with mode number as first index
        reshaped_modes = modes.A.reshape((iz, it, -1)).transpose((2, 0, 1))
        return reshaped_modes
Пример #7
0
def main(argv):
    import vtk
    from vtk.numpy_interface import dataset_adapter as dsa
    from vtk.numpy_interface import algorithms as algs 
    import numpy as np
    ### get parameters
    
    import os
    if not os.path.exists(OD):
        os.makedirs(OD)
    print '!!!Output to DIR: ',OD    

    if not read_fields_from_file:    

        ### Readin stage
        # using parallel openfoam reader
        ofr = vtk.vtkPOpenFOAMReader()
        # set reader's options 
        ofr.SetFileName(ID+IF)
	print '!!!open file: ',ID+IF
        ofr.SetDecomposePolyhedra(0)
        ofr.CacheMeshOn()
        ofr.SetCreateCellToPoint(0)
        ofr.DisableAllCellArrays()
        ofr.SetCellArrayStatus(fieldname,1)
        ofr.Update()

        # VTKArray is same as numpy array
        times = dsa.vtkDataArrayToVTKArray( ofr.GetTimeValues() ,ofr)
        # select the timestep between t0 and tf
        times = [t for t in times if t>=t0 and t<=tf]
	print '!!!available time steps: ',times
        N = len(times)
        np.save(times_filename,times)

        # using CellQuality to get cell's volumes as weight
        cq = vtk.vtkCellQuality()
        cq.SetInputConnection(0,ofr.GetOutputPort(0))
        cq.SetQualityMeasureToVolume()
        cq.Update()
        # cq is a composite dataset so I need GetBlock(0)
        geom = cq.GetOutputDataObject(0).GetBlock(0)

        # get volumes of cells V, size = L (number of cells)
        V = np.copy(dsa.WrapDataObject(geom).CellData['CellQuality'])
        # normalize it as weight 
        Vtotal = sum(V)
        V /= Vtotal
        
        # delete all other CellDataArray in geom DataSet, preserve its mesh structure and topology structure
        for i in range(geom.GetCellData().GetNumberOfArrays()):
            geom.GetCellData().RemoveArray(0)
        # add volume weight to it for saving
        geom.GetCellData().AddArray(dsa.numpyTovtkDataArray(V,'vol_weight'))

        # using *.vtu file format to save the vol_weight
        ugw = vtk.vtkXMLUnstructuredGridWriter()
        ugw.SetInputDataObject(geom)
        print '!!!Output vol_weight to file: ',geom_filename
        ugw.SetFileName(geom_filename)
        # using binary format
        ugw.SetDataModeToBinary()
        # enable compression
        ugw.SetCompressorTypeToZLib()
        # write to the file
        ugw.Write()
        # disconnect cq and ofr in order to isolate this dataset object from Update()
        cq.RemoveAllInputConnections(0)

        L = V.size # number of cells
        N = len(times) #number of timesteps
        # vector data is larger in size
        if field_is_vector == True:
            fields = np.zeros([N,L,3])
        else:
            fields = np.zeros([N,L])
        pipepout = ofr
        for i in range(N):
            t = times[i]
            print '!!!reading time:{}'.format(t)
            # set time value
            pipepout.GetOutputInformation(0).Set(vtk.vtkStreamingDemandDrivenPipeline.UPDATE_TIME_STEP(),t)
            # read in field data of new timestep
            pipepout.Update()
            # 
            d = dsa.WrapDataObject(pipepout.GetOutput().GetBlock(0))
            print '!!!reading field:{}'.format(fieldname)
            field = d.CellData[fieldname]
            # get the first component of composite dataset, it is the internalField
            fields[i]=np.copy(field)

        # write data to file
        print '!!!write field data to file:',fields_filename
        np.savez(fields_filename,fields)
    else: #read fields from file
        fields = np.load(fields_filename)['arr_0']
        
        ugr = vtk.vtkXMLUnstructuredGridReader()
        ugr.SetFileName(geom_filename)
        ugr.Update()
        geom = ugr.GetOutputDataObject(0)
        V = np.copy(dsa.WrapDataObject(geom).CellData['vol_weight'])
        
        times = np.load(times_filename)
        assert times.shape[0] == fields.shape[0]
        assert fields.shape[1] == V.shape[0]
        N = times.shape[0] 
        L = fields.shape[1]

        print 'Read in dataset complete'
    ### POD section


    # calculate average
    field_avg = np.average(fields, axis=0)
    if subtractAvg:
        fields = fields - field_avg

    import modred as mr
    
    if do_POD:
        # if field is a vector, reshape the fields and corresponding volument weight
        if field_is_vector:
            shp_vec = fields.shape
            shp_flat = (fields.shape[0],fields.shape[1]*fields.shape[2])
            fields = fields.reshape(shp_flat)
            V = np.tile(V,shp_vec[2])

        # POD
        print '!!!Doing POD analysis'
        modes, eigen_vals, eigen_vecs, correlation_mat = mr.compute_POD_matrices_snaps_method(fields.T,range(M),inner_product_weights=V,return_all=True)

        # if field is a vector, reshape the output matrix
        if field_is_vector:
            fields = fields.reshape(shp_vec)
            modes = np.asarray(modes).T.reshape((modes.shape[1],shp_vec[1],shp_vec[2]))
            V = V[:shp_vec[1]]

        if output_correlation_matrix:
            print "!!!output POD correlation matrix",POD_cm_filename
            np.savetxt(POD_cm_filename,correlation_mat,delimiter=',')

        if output_POD_temporal_modes: 
            print "!!!output POD temporal modes",POD_tm_filename
            # output temporal modes
            singular_vals = eigen_vals**0.5
            POD_mode_energy_normalized = eigen_vals/correlation_mat.trace()[0,0]
            cumsum_POD_mode_energy_normalized = np.cumsum(POD_mode_energy_normalized)
            # generate header string
            header_str = 'temporal modes\n'
            header_str += 'time,eigen value,singular value,normalized eigen value,accumulated normalized eigen value'
            for i in range(N-1):
                header_str += ',Mode{}'.format(i)
            header_str += '\n'
            for i in range(N-1):
                header_str += ',SV ={}'.format(singular_vals[i])
            header_str += '\n'
            for i in range(N-1):
                header_str += ',EV ={}'.format(eigen_vals[i])
            header_str += '\n'
            for i in range(N-1):
                header_str += ',NEnergy ={}'.format(POD_mode_energy_normalized[i])
            header_str += '\n'
            for i in range(N-1):
                header_str += ',CumsumEnergy ={}'.format(cumsum_POD_mode_energy_normalized[i])
            header_str += '\n'

            np.savetxt(POD_tm_filename, \
                        np.c_[times, \
                            eigen_vecs], \
                        delimiter = ',', \
                        header = header_str)
            

        if output_POD_spatial_modes:
            print "!!!output POD spatial Modes to ",POD_sm_filename
            #output to xml vtk unstructured grid file
            ugcd = geom.GetCellData()
            ugcd.Reset()
            ugcd.CopyAllOff()
            for i in range(ugcd.GetNumberOfArrays()):
                ugcd.RemoveArray(0)
            # import POD mode
            for i in range(M):
                ugcd.AddArray(dsa.numpyTovtkDataArray(modes[i],prefix+'_POD_mode_{}_{}'.format(fieldname,i)))
            # add average field
            ugcd.AddArray(dsa.numpyTovtkDataArray(field_avg,'field_{}_avg'.format(fieldname)))

            ugw = vtk.vtkXMLUnstructuredGridWriter()
            ugw.SetInputDataObject(geom)
            ugw.SetFileName(POD_sm_filename)
            ugw.Write()
        if doReconstruction:
            print "!!! do Reconstrution with {} POD modes at time {}".format(MR,ReconTime)
            #get an empty mesh
            ugcd = geom.GetCellData()
            ugcd.Reset()
            ugcd.CopyAllOff()
            for i in range(ugcd.GetNumberOfArrays()):
                ugcd.RemoveArray(0)
            # reconstruct from first MR POD modes
            # 
            ReconN = np.searchsorted(times,ReconTime)
            print "!!!actually, reconstruction is done at time {} rather than time {}".format(times[ReconN],ReconTime)
            recon_field = np.einsum("i...,i,i",modes[:MR],eigen_vals[:MR]**0.5,np.asarray(eigen_vecs)[ReconN,:MR])+field_avg;
            ugcd.AddArray(dsa.numpyTovtkDataArray(recon_field,prefix+'_POD_{}_Reconstructed_{}_{}'.format(MR,fieldname,ReconTime)))

            ugw = vtk.vtkXMLUnstructuredGridWriter()
            ugw.SetInputDataObject(geom)
            ugw.SetFileName(POD_reconstruction_filename)
            ugw.Write()
    if do_DMD:
        print "!!!Begin to calculate DMD modes"
        # if field is a vector, reshape the fields and corresponding volument weight
        if field_is_vector:
            shp_vec = fields.shape
            shp_flat = (fields.shape[0],fields.shape[1]*fields.shape[2])
            fields = fields.reshape(shp_flat)
            V = np.tile(V,shp_vec[2])

        # DMD, I do not know which mode is important, so I have to discard modes_
        modes_, ritz_vals, mode_norms, build_coeffs = mr.compute_DMD_matrices_snaps_method(fields.T,[],inner_product_weights=V,return_all=True)

        # if field is a vector, reshape the fields, V and output matrix
        if field_is_vector:
            fields = fields.reshape(shp_vec)
            V = V[:shp_vec[1]]
        # sorting
        eorder = np.argsort(mode_norms)[::-1]
        # re-order the outputs
        ritz_vals = ritz_vals[eorder]
        mode_norms = mode_norms[eorder]
        build_coeffs = build_coeffs[:,eorder]
        #build the DMD_modes
        DMD_modes = np.einsum('ijk,il->ljk', fields,build_coeffs[:,:M_DMD])
        
        if output_DMD_info:
            print "!!!output DMD info to :",DMD_info_filename
            # output modes info
            header_str = 'DMD modes info\n'
            header_str += 'ritz_vals.real,ritz_vals.imag,growth_rate, frequency, mode_norms\n'
            header_str += r'AU,AU,1/s, Hz, AU'
            dt = np.average(times[1:]-times[:-1]) #time step
            np.savetxt(DMD_info_filename, \
                        np.c_[ np.real(ritz_vals), \
                            np.imag(ritz_vals), \
                            np.log(np.abs(ritz_vals))/dt, \
                            np.angle(ritz_vals)/dt, \
                            mode_norms], \
                        delimiter = ',', \
                        header = header_str) 

        if output_DMD_build_coeffs:
            print "!!!output DMD build coeffs. to :",DMD_build_coeffs_filename
            np.savez(DMD_build_coeffs_filename, build_coeffs)
            
        if output_DMD_spatial_modes:
            print "!!!output DMD info to :",DMD_sm_filename
            #output to xml vtk unstructured grid file
            ugcd = geom.GetCellData()
            ugcd.Reset()
            ugcd.CopyAllOff()
            for i in range(ugcd.GetNumberOfArrays()):
                ugcd.RemoveArray(0)
            #import pi
            from numpy import pi
            
            for i in range(M_DMD):
                ugcd.AddArray(dsa.numpyTovtkDataArray(np.abs(DMD_modes[i]),prefix+'_DMD_mode_abs_{}_{}'.format(fieldname,i)))
                ugcd.AddArray(dsa.numpyTovtkDataArray(np.angle(DMD_modes[i])*180/pi,prefix+'_DMD_mode_angle_{}_{}'.format(fieldname,i)))


            ugw = vtk.vtkXMLUnstructuredGridWriter()
            ugw.SetInputDataObject(geom)
            ugw.SetFileName(DMD_sm_filename)
            ugw.Write()