def sparse_laplacian(nx, ny): # Neumann BC Laplacian Ix = sp.eye(nx, format='csc') Iy = sp.eye(ny, format='csc') Ix[0, 0] = 0.5 Ix[-1, -1] = 0.5 Iy[0, 0] = 0.5 Iy[-1, -1] = 0.5 Dxx = sp.diags([1, -2, 1], [-1, 0, 1], shape=(nx, nx)).toarray() Dxx[0, 1] = 2 Dxx[-1, -2] = 2 Dyy = sp.diags([1, -2, 1], [-1, 0, 1], shape=(ny, ny)).toarray() Dyy[0, 1] = 2 Dyy[-1, -2] = 2 # L = sp.kronsum(Dyy,Dxx,format='csc') L = sp.kronsum(Dxx, Dyy, format='csc') Q = sp.kron(Ix, Iy, format='csc') # Q = sp.kron(Ix,Iy,format='csc') return L, Q
def matrices(shape, operators, combine): def parts(): for i, o in enumerate(operators): diagonals = [] for j, p in enumerate(o): index = -(len(o) // 2 - j) diagonals.append((p * np.ones(shape[i] - abs(index)), index)) matrix = sp.diags(*zip(*diagonals)) if combine: yield matrix else: # The sum of these kronecker product folds is equivalent to the kronecker sum of all the matrices. # This identity can be derived from the properties of the kronecker product. # This is useful when you need to apply each operator on a different axis, # like in the case of finding the divergence of a velocity field using the gradient. yield reduce( sp.kron, tuple(matrix if k == i else sp.identity(d) for k, d in enumerate(shape))) # Credit to Philip Zucker for figuring out that kronsum's argument order is reversed. # Without that bit of wisdom I'd have lost it. return reduce(lambda a, b: sp.kronsum(b, a), parts()) if combine else tuple(parts())
def operator(shape, *differences): # Credit to Philip Zucker for figuring out # that kronsum's argument order is reversed. # Without that bit of wisdom I'd have lost it. differences = zip(shape, cycle(differences)) factors = (sp.diags(*diff, shape=(dim, ) * 2) for dim, diff in differences) return reduce(lambda a, f: sp.kronsum(f, a, format='csc'), factors)
def _get_elem(self): a = self.A._get_elem() b = self.B._get_elem() A = sp.coo_matrix((a[2], (a[0], a[1]))) B = sp.coo_matrix((b[2], (b[0], b[1]))) C = sp.kronsum(A, B, format='coo') return (C.row, C.col, C.data)
def lapl(shape, mul=1, h=1): diags = [1, -2, 1] # Values on diagonals for 1d laplacian ks = [mul, 0, -mul] # which diagonals to set for above values # Store 1d laplacians T_j in array Ts Ts = [sparse.diags(diags, ks, shape=(j, j), format='csr') for j in shape] # Calculate kronsum (sum of tensor product of T_a, I_b and tensor product of I_a, T_b) of 1d laplacian matrices return reduce(lambda a, b: sparse.kronsum(a, b, format='csr'), Ts[::-1]) / h
def __init__(self, m, n, dx, wn, ws, we, ww, id, neumann=None): """ :param m: int, shape[0] of the room :param n: int, shape[1] of the room :param dx: float, dicretization distance :param wn: float, temperature of north wall :param ws: float, temperature of south wall :param we: float, temperature of east wall :param ww: float, temperature of west wall :param id: int, rank of the calling thread """ self.M = m self.N = n # create the whole array self.u = np.zeros((m, n)) self.dx = dx # create references to the walls self.wn = self.u[-1, :] self.ws = self.u[0, :] self.we = self.u[:, -1] self.ww = self.u[:, 0] # setup a dictionary for shared items self.shared = dict() # assign values to the walls self.wn += wn self.ws += ws self.we += we self.ww += ww ub = self.u.copy() nan = np.empty((m, n)) nan[:, :] = np.NaN self.ub = np.where(ub != 0, ub, nan) # set the id self.id = id # try using some form of broadcast with a class variable? # deal with any boundary conditions when we create the A matrix Dn = sparse.diags([1, -2, 1], [-1, 0, 1], shape=(n, n)) Dm = sparse.diags([1, -2, 1], [-1, 0, 1], shape=(m, m)) if neumann == 'east': Dn = Dn.copy().tolil() Dn[-1, -1] += 1 self.ub[1:-1, -1] = np.NaN elif neumann == 'west': Dn = Dn.copy().tolil() Dn[0, 0] += 1 self.ub[1:-1, 0] = np.NaN self.A = sparse.kronsum(Dn, Dm)
def kronsum(gen): """ Kronnecker sum example: """ res = next(gen) for each in gen: res = sp.kronsum(res, each) return res
def define_laplacian(self): """Define the laplacian.""" L = self.get_1D_laplacian() if self.ndim == 2: L = sp.kronsum(L, L, format='lil') L[0, -1] = 1. L[-1, 0] = 1. self.L = L / (self.steps**2).prod() self.L = sp.block_diag([self.L] * self.nstates)
def L_form(h, Nx, Ny): Dx = np.zeros((Nx, Nx - 1)) np.fill_diagonal(Dx, 1) np.fill_diagonal(Dx[1:, :], -1) Dy = np.zeros((Ny, Ny - 1)) np.fill_diagonal(Dy, 1) np.fill_diagonal(Dy[1:, :], -1) Lxx = Dx.T @ Dx Lyy = Dy.T @ Dy L = sp.kronsum(Lxx, Lyy) / h**2 return -L
def build_laplacian_matrix(nx, ny, g=g,d=d): Lx = ss.diags([-2*np.ones(nx), np.ones(nx-1), np.ones(nx-1), 1.0, 1.0], [0, -1, 1, nx-1, -(nx-1)])/d/d Ly = ss.diags([-2*np.ones(ny), np.ones(ny-1), np.ones(ny-1), 1.0, 1.0], [0, -1, 1, ny-1, -(ny-1)])/d/d L = ss.kronsum(Ly, Lx).tocsr() I = ss.eye(nx*ny).tocsr() L[0] = I[0] return L
def generate_A(ijklevels): numLevels = ijklevels.shape[1] A = [] for i in range(numLevels): Nx = ijklevels[0][i] Ny = ijklevels[1][i] Nz = ijklevels[2][i] nx = Nx - 2 ny = Ny - 2 nz = Nz - 2 hx = Lx / (Nx - 1) hy = Ly / (Ny - 1) hz = Lz / (Nz - 1) diagonalsx = [(hz**2/hx**2)*np.ones(nx-1), (-2*hz**2/hx**2)*np.ones(nx), \ (hz**2/hx**2)*np.ones(nx-1)] diagonalsy = [(hz**2/hy**2)*np.ones(ny-1), (-2*hz**2/hy**2)*np.ones(ny), \ (hz**2/hy**2)*np.ones(ny-1)] diagonalsz = [np.ones(nz - 1), -2 * np.ones(nz), np.ones(nz - 1)] Ax = sp.diags(diagonalsx, [-1, 0, 1]) Ay = sp.diags(diagonalsy, [-1, 0, 1]) Az = sp.diags(diagonalsz, [-1, 0, 1]) A.append(sp.kronsum(sp.kronsum(Ax, Ay), Az, format='coo')) return A
def make_L(Nx, Ny): Dx = sp.diags((Nx - 1) * [1.]) Dx += sp.diags((Nx - 2) * [-1.], -1) rowx = sp.csr_matrix((1, Nx - 1)) rowx[0, -1] = -1 Dx = sp.vstack((Dx, rowx)) Lx = Dx.transpose().dot(Dx) Dy = sp.diags((Ny - 1) * [1]) Dy += sp.diags((Ny - 2) * [-1], -1) rowy = sp.csr_matrix((1, Ny - 1)) rowy[0, -1] = -1 Dy = sp.vstack((Dy, rowy)) Ly = Dy.transpose().dot(Dy) return sp.kronsum(Lx, Ly)
def make_L(Nx, Ny): Dx = sp.diags((Nx - 1) * [1]) Dx += sp.diags((Nx - 2) * [-1], -1) rowx = sp.csr_matrix((1, Nx - 1)) rowx[0, -1] = -1 Dx = sp.vstack((Dx, rowx)) Lx = Dx.transpose().dot(Dx) Dy = sp.diags((Ny - 1) * [1]) Dy += sp.diags((Ny - 2) * [-1], -1) rowy = sp.csr_matrix((1, Ny - 1)) rowy[0, -1] = -1 Dy = sp.vstack((Dy, rowy)) Ly = Dy.transpose().dot(Dy) #Kronsum is jsut a cleaner way than creating Identity matrices and stuff return sp.kronsum(Lx, Ly)
def discrete_hamiltonian(V: np.ndarray): """ Given the potential V, return the discretized Hamiltonian. Reference to discretize the Hamiltonian: https://wiki.physics.udel.edu/phys824/ Discretization_of_1D_continuous_Hamiltonian Discretizing the Laplacian: https://en.wikipedia.org/wiki/Discrete_Laplace_operator# Implementation_via_operator_discretization Kronecker sum of discrete Laplacians: https://en.wikipedia.org/wiki/Kronecker_sum_of_discrete_Laplacians """ diag = HBAR**2 / (2 * M_E * DX**2) * np.ones([N]) diags = np.array([-diag, 2.0 * diag, -diag]) kinetic_1d = sparse.spdiags(diags, np.array([1.0, 0.0, -1.0]), N, N) T = sparse.kronsum(kinetic_1d, kinetic_1d) U = sparse.diags((V.reshape(N * N)), (0)) return T + U
def __init__(self): # list of tuples (solver, symmetric, positive_definite ) solvers = [cg, cgs, bicg, bicgstab, gmres, qmr, minres, lgmres, gcrotmk, tfqmr] sym_solvers = [minres, cg] posdef_solvers = [cg] real_solvers = [minres] self.solvers = solvers # list of tuples (A, symmetric, positive_definite ) self.cases = [] # Symmetric and Positive Definite N = 40 data = ones((3,N)) data[0,:] = 2 data[1,:] = -1 data[2,:] = -1 Poisson1D = spdiags(data, [0,-1,1], N, N, format='csr') self.Poisson1D = Case("poisson1d", Poisson1D) self.cases.append(Case("poisson1d", Poisson1D)) # note: minres fails for single precision self.cases.append(Case("poisson1d", Poisson1D.astype('f'), skip=[minres])) # Symmetric and Negative Definite self.cases.append(Case("neg-poisson1d", -Poisson1D, skip=posdef_solvers)) # note: minres fails for single precision self.cases.append(Case("neg-poisson1d", (-Poisson1D).astype('f'), skip=posdef_solvers + [minres])) # 2-dimensional Poisson equations Poisson2D = kronsum(Poisson1D, Poisson1D) self.Poisson2D = Case("poisson2d", Poisson2D) # note: minres fails for 2-d poisson problem, it will be fixed in the future PR self.cases.append(Case("poisson2d", Poisson2D, skip=[minres])) # note: minres fails for single precision self.cases.append(Case("poisson2d", Poisson2D.astype('f'), skip=[minres])) # Symmetric and Indefinite data = array([[6, -5, 2, 7, -1, 10, 4, -3, -8, 9]],dtype='d') RandDiag = spdiags(data, [0], 10, 10, format='csr') self.cases.append(Case("rand-diag", RandDiag, skip=posdef_solvers)) self.cases.append(Case("rand-diag", RandDiag.astype('f'), skip=posdef_solvers)) # Random real-valued np.random.seed(1234) data = np.random.rand(4, 4) self.cases.append(Case("rand", data, skip=posdef_solvers+sym_solvers)) self.cases.append(Case("rand", data.astype('f'), skip=posdef_solvers+sym_solvers)) # Random symmetric real-valued np.random.seed(1234) data = np.random.rand(4, 4) data = data + data.T self.cases.append(Case("rand-sym", data, skip=posdef_solvers)) self.cases.append(Case("rand-sym", data.astype('f'), skip=posdef_solvers)) # Random pos-def symmetric real np.random.seed(1234) data = np.random.rand(9, 9) data = np.dot(data.conj(), data.T) self.cases.append(Case("rand-sym-pd", data)) # note: minres fails for single precision self.cases.append(Case("rand-sym-pd", data.astype('f'), skip=[minres])) # Random complex-valued np.random.seed(1234) data = np.random.rand(4, 4) + 1j*np.random.rand(4, 4) self.cases.append(Case("rand-cmplx", data, skip=posdef_solvers+sym_solvers+real_solvers)) self.cases.append(Case("rand-cmplx", data.astype('F'), skip=posdef_solvers+sym_solvers+real_solvers)) # Random hermitian complex-valued np.random.seed(1234) data = np.random.rand(4, 4) + 1j*np.random.rand(4, 4) data = data + data.T.conj() self.cases.append(Case("rand-cmplx-herm", data, skip=posdef_solvers+real_solvers)) self.cases.append(Case("rand-cmplx-herm", data.astype('F'), skip=posdef_solvers+real_solvers)) # Random pos-def hermitian complex-valued np.random.seed(1234) data = np.random.rand(9, 9) + 1j*np.random.rand(9, 9) data = np.dot(data.conj(), data.T) self.cases.append(Case("rand-cmplx-sym-pd", data, skip=real_solvers)) self.cases.append(Case("rand-cmplx-sym-pd", data.astype('F'), skip=real_solvers)) # Non-symmetric and Positive Definite # # cgs, qmr, bicg and tfqmr fail to converge on this one # -- algorithmic limitation apparently data = ones((2,10)) data[0,:] = 2 data[1,:] = -1 A = spdiags(data, [0,-1], 10, 10, format='csr') self.cases.append(Case("nonsymposdef", A, skip=sym_solvers+[cgs, qmr, bicg, tfqmr])) self.cases.append(Case("nonsymposdef", A.astype('F'), skip=sym_solvers+[cgs, qmr, bicg, tfqmr])) # Symmetric, non-pd, hitting cgs/bicg/bicgstab/qmr/tfqmr breakdown A = np.array([[0, 0, 0, 0, 0, 1, -1, -0, -0, -0, -0], [0, 0, 0, 0, 0, 2, -0, -1, -0, -0, -0], [0, 0, 0, 0, 0, 2, -0, -0, -1, -0, -0], [0, 0, 0, 0, 0, 2, -0, -0, -0, -1, -0], [0, 0, 0, 0, 0, 1, -0, -0, -0, -0, -1], [1, 2, 2, 2, 1, 0, -0, -0, -0, -0, -0], [-1, 0, 0, 0, 0, 0, -1, -0, -0, -0, -0], [0, -1, 0, 0, 0, 0, -0, -1, -0, -0, -0], [0, 0, -1, 0, 0, 0, -0, -0, -1, -0, -0], [0, 0, 0, -1, 0, 0, -0, -0, -0, -1, -0], [0, 0, 0, 0, -1, 0, -0, -0, -0, -0, -1]], dtype=float) b = np.array([0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0], dtype=float) assert (A == A.T).all() self.cases.append(Case("sym-nonpd", A, b, skip=posdef_solvers, nonconvergence=[cgs,bicg,bicgstab,qmr,tfqmr]))
def _build_derivative_matrix_structured_cartesian(mesh, derivative, order_accuracy, dimension='all', use_shifted_differences=False, return_1D_matrix=False, **kwargs): dims = list() if type(dimension) is str: dimension = [dimension] if 'all' in dimension: if mesh.dim > 1: dims.append('x') if mesh.dim > 2: dims.append('y') dims.append('z') else: for d in dimension: dims.append(d) # sh[-1] is always 'z' # sh[0] is always 'x' if in 2 or 3d # sh[1] is always 'y' if dim > 2 sh = mesh.shape(include_bc = True, as_grid = True) if mesh.dim > 1: if 'x' in dims: lbc = _set_bc(mesh.x.lbc) rbc = _set_bc(mesh.x.rbc) delta = mesh.x.delta Dx = _build_derivative_matrix_part(sh[0], derivative, order_accuracy, h=delta, lbc=lbc, rbc=rbc, use_shifted_differences=use_shifted_differences) else: Dx = spsp.csr_matrix((sh[0],sh[0])) if mesh.dim > 2: if 'y' in dims: lbc = _set_bc(mesh.y.lbc) rbc = _set_bc(mesh.y.rbc) delta = mesh.y.delta Dy = _build_derivative_matrix_part(sh[1], derivative, order_accuracy, h=delta, lbc=lbc, rbc=rbc, use_shifted_differences=use_shifted_differences) else: Dy = spsp.csr_matrix((sh[1],sh[1])) if 'z' in dims: lbc = _set_bc(mesh.z.lbc) rbc = _set_bc(mesh.z.rbc) delta = mesh.z.delta Dz = _build_derivative_matrix_part(sh[-1], derivative, order_accuracy, h=delta, lbc=lbc, rbc=rbc, use_shifted_differences=use_shifted_differences) else: Dz = spsp.csr_matrix((sh[-1],sh[-1])) if return_1D_matrix and 'all' not in dims: if 'z' in dims: mtx = Dz elif 'y' in dims: mtx = Dy elif 'x' in dims: mtx = Dx else: if mesh.dim == 1: mtx = Dz.tocsr() if mesh.dim == 2: # kronsum in this order because wavefields are stored with 'z' in row # and 'x' in columns, then vectorized in 'C' order mtx = spsp.kronsum(Dz, Dx, format='csr') if mesh.dim == 3: mtx = spsp.kronsum(Dz, spsp.kronsum(Dy,Dx, format='csr'), format='csr') return mtx
Ix = sp.eye(nx, format='csc') Iy = sp.eye(ny, format='csc') Ix[0, 0] = 0.5 Ix[-1, -1] = 0.5 Iy[0, 0] = 0.5 Iy[-1, -1] = 0.5 Dxx = sp.diags([1, -2, 1], [-1, 0, 1], shape=(nx, nx)).toarray() Dxx[0, 1] = 2 Dxx[-1, -2] = 2 #Riemann boundary condition Dyy = sp.diags([1, -2, 1], [-1, 0, 1], shape=(ny, ny)).toarray() Dyy[0, 1] = 2 Dyy[-1, -2] = 2 L = sp.kronsum(Dyy, Dxx, format='csc') Q = sp.kron(Ix, Iy, format='csc') A0 = Q @ (I - C / 2.0 * L) #Aarr = A.toarray() #pd =is_pos_def(A.toarray()) #check if A matrix is positive definite # LU decomposition Pr*A*Pc = LU #lu = la.splu(A0) #factor = cholesky(A0) #LU_x = lambda x: factor(x) #pvec = la.LinearOperator((nv, nv), LU_x) ##====================Initial condition=========================
# converting in CSR format A1 = A1.tocsr() # Construct anther matrix B1 = lil_matrix((1000, 1000)) B1[0, :100] = rand(100) B1[1, 100:200] = B1[0, :100] B1.setdiag(rand(1000)) # converting in CSR forma B1 = B1.tocsr() # Sparse kronecker product C1 = sparse.kron(A1, B1).toarray() #sparse kronecker sum C2 = sparse.kronsum(A1,B1).toarray() # Sparse Kronecker product diagonal matrix def populatematrix1(dim): return dia_matrix( (np.array( [np.array([2]*5),np.array([1]*5), np.array([1]*5)] ),np.array([0,1,-1]) ),shape=(5,5)) def populatematrix2(dim): return dia_matrix( (np.array( [np.array([2]*5),np.array([1]*5), np.array([1]*5)] ),np.array([0,1,-1]) ),shape=(5,5)) dx = np.linspace(0,1,5) x = populatematrix1(len(dx)) print (x.shape, type(x)) y = populatematrix2(len(dx)) print (y.shape, type(y)) z = kron(x,y) print (z.shape)
h = 0.002 Nx = int(2 / h) Ny = int(1 / h) Dx = np.zeros((Nx, Nx - 1)) np.fill_diagonal(Dx, 1) np.fill_diagonal(Dx[1:, :], -1) Dy = np.zeros((Ny, Ny - 1)) np.fill_diagonal(Dy, 1) np.fill_diagonal(Dy[1:, :], -1) Lxx = Dx.T @ Dx Lyy = Dy.T @ Dy L = sp.kronsum(Lxx, Lyy) L = L / h**2 print(L) plt.figure() plt.spy(L, marker='o', markersize=6, color='green') gridy = np.arange(0 + h, 1, h) gridx = np.arange(0 + h, 2, h) grid = np.mgrid[0 + h:2:h, 0 + h:1:h] x = grid[0] y = grid[1] f = 20 * np.multiply(np.sin(np.pi * y), np.sin(1.5 * np.pi * x + np.pi)) f = np.transpose(f)
''' $$\left[-\frac{1}{2}(D \oplus D) + m\Delta x^2 V \right] \psi = \left(m \Delta x^2 E\right) \psi$$ ''' # V = np.exp(-(X-0.3)**2/(2*0.1**2))*np.exp(-(Y-0.3)**2/(2*0.1**2)) # V = 1./(1+np.exp(-(X-0.3)**2/(2*0.1**2))*np.exp(-(Y-0.3)**2/(2*0.1**2))) # V = 1./(1+(X-0.3)**2 + (Y-0.3)**2) V = (X-0.3)**2 + (Y-0.3)**2 V = 0*V ones = np.ones(N) data = np.array([ones, -2*ones, ones]) diags = np.array([-1, 0, 1]) D = sparse.spdiags(data, diags, N, N) T = -1/2 * sparse.kronsum(D, D) U = sparse.diags(V.reshape(N**2), (0)) H = T+U print(data.shape) print(D.toarray().shape) print(T.toarray().shape) print(U.toarray().shape) print(H.toarray().shape) E, Psi = eigsh(H, k=10, which='SM') print(E.shape, Psi.shape) def Psi_n(n): return Psi.T[n].reshape((N, N))
def test_kronsum(self): test = kronsum(sigmax, sigmax, iden) exact = sp.kronsum(sp.kronsum(sigmax, sigmax), iden) self.assertEqual((test != exact).nnz, 0)
import numpy as np from scipy.sparse import kronsum dim = 2 a = np.zeros((dim, dim)) b = np.zeros((dim, dim)) for i in range(dim): for ip in range(dim): if i == ip + 1: a[i, ip] = -1 b[i, ip] = -1 if i == ip - 1: a[i, ip] = +1 b[i, ip] = +1 if i == ip: a[i, ip] = 1.1 b[i, ip] = 1.1 full2 = kronsum(a, a).todense() full3 = kronsum(full2, a).todense() print(full2) print(full3)
def predict(self, tspan, ic): """Given initial condition as ``ic``, predicting the trajectory given ``tspan`` as time. We direct evaluate time that is far away, not using recursive for each delta t since it is linear system. Args: tspan (:obj:`numpy.ndarray`): time array ic (:obj:`numpy.ndarray`): initial condition :math:`x_0 = x(t=0)`. Returns: :obj:`numpy.ndarray` : ensemble of trajectory from Monte Carlo sampling, representing a distribution of posteriori. """ # let's share the same IC state = ic # read in (1,M) state -> to generate (Q,K) Phi_0, but evaluate at many different states # duffing: [[0.00673038, 0.03789839, 0.0423713 ]] init_phi_state_mc_array = self.model.computePhi(state) # x -> phi # get Q realization of K self.K = self.model.get_K() # get linear lambda self.lambda_lin = self.model.get_lambda_lin() # get reconstruction noise self.noise_rec = self.model.get_noise_rec() RANDOM_SAMPLE = np.random.normal(size=(self.model.n_mc_samples, tspan.size, self.model.n_mc_diff_samples, self.K[0].shape[0])) state_total_mc_list = [] if self.LRAN_T == 1: # diff form # for each phi state in Q realization, let's evolve the dynamics for i in xrange(self.model.n_mc_samples): # LAMBDA, P = np.linalg.eig(self.K[i]) # PINV = np.linalg.inv(P) # LAMBDA = np.diag(LAMBDA) Q = np.linalg.inv(kronsum(self.K[i].astype('float64'), self.K[i].astype('float64')).toarray()) # Q = 0.5*np.matmul(np.matmul(P, np.diag(self.lambda_lin[i])), -np.linalg.inv(LAMBDA)) # for each sample print 'monte carlo run index = ', i, ': ', self.model.n_mc_samples # *self.model.n_mc_diff_samples state_list = [[state]*self.model.n_mc_diff_samples] for index_time in xrange(1, tspan.size): delta_time = tspan[index_time] - tspan[0] # linearly evolving phi to future - for i-th realization # convert to double precision time_evolution_with_K = delta_time * self.K[i] time_evolution_with_K = time_evolution_with_K.astype('float64') phi_state_at_t_mc_array = np.matmul(init_phi_state_mc_array[i].astype('float64'), expm(time_evolution_with_K)) # phi with noise Q_true = -1.0 * np.matmul(Q.astype('float64'), np.eye(self.K[i].shape[0]**2) - expm( kronsum(self.K[i].astype('float64'), self.K[i].astype('float64')) * delta_time) ) Q_true = np.matmul(Q_true, np.diag(self.lambda_lin[i].astype('float64')).reshape(-1,1, order='F')) Q_true = Q_true.reshape(self.K[i].shape[0],-1, order='F') try: L = np.linalg.cholesky(Q_true) except: print 'L is not positive definite...' print('Q_true = ', Q_true) print("") print('K = ', self.K[i]) print('K = ', np.linalg.eig(self.K[i])[0]) print('lin = ', self.lambda_lin[i]) print('') print(np.linalg.eig(Q_true)[0]) L = np.zeros(self.K[i].shape) # the noise is involved via MOU process. # Q_true = np.matmul(np.matmul(Q, np.eye(LAMBDA.shape[0]) - expm(2*LAMBDA*delta_time)), PINV) ## need to modify a bit to make sure the round off error is removed... # Q_true_real = np.real(Q_true) # Q_true_symm = 0.5*(Q_true + np.conj(Q_true)) # try: # L = np.linalg.cholesky(Q_true_symm) # it is important to make it real.. #except: # print np.linalg.eigh(L) # L = np.zeros(LAMBDA.shape) state_for_current_time_list = [] for i_mc_diff in xrange(self.model.n_mc_diff_samples): NOISE_MOU = np.matmul(RANDOM_SAMPLE[i, index_time-1, i_mc_diff,:].reshape(1,-1), L).astype('float64') phi_state_at_t_mc_array_noise_mou = phi_state_at_t_mc_array + NOISE_MOU # np.matmul(self.noise_lin[i], integrate_exp_tK) # reconstruct x from phi state at feature state_future_mc_array_noise_mou = self.model.reconstruct_with_i_realization(phi=phi_state_at_t_mc_array_noise_mou, i=i) # here we will introduce reconstriction error # add reconstruction noise -> it is like the white noise in ARMA model, not interacting with the flow. not a # subscale turublence problem.. state_future_mc_array = state_future_mc_array_noise_mou + self.noise_rec[i][:state_future_mc_array_noise_mou.shape[1]] # transform normalized state: eta, to original state state_future_mc_array = self.model.transform_eta_to_x(state_future_mc_array) # state_list.append(state_future_mc_array) state_for_current_time_list.append(state_future_mc_array) state_list.append(state_for_current_time_list) # append for each time's the whole realization state_total_mc_list.append(np.array(state_list)) # (800, 4, 10, 1, 2) QM_state_array = np.stack(state_total_mc_list, axis=1) # (800, 4, 10, 2) QM_state_array = np.squeeze(QM_state_array) QM_state_array = np.swapaxes(QM_state_array, 0, 1) QM_state_array = np.swapaxes(QM_state_array, 1, 2) QM_state_future_array = QM_state_array.reshape(-1, tspan.size, state.size) # QM_state_future_array = np.squeeze(np.stack(state_total_mc_list, axis=0), axis=2) elif self.LRAN_T > 1: # recurrent form # for each phi state, let's evolve the dynamics. for i in xrange(self.model.n_mc_samples): # stability test eigv,_ = np.linalg.eig(self.K[i].astype('float64')) if np.max(np.real(eigv)) > 0: print('=====================') print('unstable!') print(self.K[i]) print(eigv) # for each sample print 'monte carlo run index = ', i, ': ', self.model.n_mc_samples state_list = [state] # loop over time for index_time in xrange(1, tspan.size): # compute ``delta time`` delta_time = tspan[index_time] - tspan[0] # linearly evolving phi to future ``delta time`` - for i-th realization time_evolution_with_K = delta_time * self.K[i].astype('float64') # convert to double precision, because sometimes single precision overfloat time_evolution_with_K = time_evolution_with_K.astype('float64') phi_state_at_t_mc_array = np.matmul(init_phi_state_mc_array[i].astype('float64'), expm(time_evolution_with_K)) # phi_0 -> phi_t # reconstruct x from phi state at feature state_future_mc_array = self.model.reconstruct_with_i_realization(phi=phi_state_at_t_mc_array, i=i) # phi_t -> eta_rec_t # here we will introduce reconstriction error # add reconstruction noise -> it is like the white noise in ARMA model, not interacting with the flow. not a # subscale turublence problem.. state_future_mc_array = state_future_mc_array + self.noise_rec[i][:state_future_mc_array.shape[1]] # transform normalized state: eta, to original state state_future_mc_array = self.model.transform_eta_to_x(state_future_mc_array) # eta_rec_t -> x_rec_t state_list.append(state_future_mc_array) # append for each time's the whole realization state_total_mc_list.append(state_list) # if self.mode == 'MAP': # QM_state_future_array = np.stack(state_total_mc_list, axis=0) # else: QM_state_future_array = np.squeeze(np.stack(state_total_mc_list, axis=0), axis=2) else: raise NotImplementedError('not yet..') return QM_state_future_array
from scipy import sparse from scipy.sparse import linalg dx = 1 / 20 nbr_points = int(1 / dx + 1) n = nbr_points m = 2 * n # Big room has twice as many rows. Dn = sparse.diags([1, -2, 1], [-1, 0, 1], shape=(n, n)) Dm = sparse.diags([1, -2, 1], [-1, 0, 1], shape=(m, m)) Dn_east = Dn.copy().tolil() Dn_east[-1, -1] += 1 A0 = sparse.kronsum(Dn_east, Dn) A1 = sparse.kronsum(Dn, Dm) Dn_west = Dn.copy().tolil() Dn_west[0, 0] += 1 A2 = sparse.kronsum(Dn_west, Dn) # first room u0 = np.zeros((n, n)) u0[0, :] += 15 u0[-1, :] += 15 u0[:, 0] += 40 u0[:, -1] += -1
def _build_derivative_matrix_structured_cartesian( mesh, derivative, order_accuracy, dimension='all', use_shifted_differences=False, return_1D_matrix=False, **kwargs): dims = list() if type(dimension) is str: dimension = [dimension] if 'all' in dimension: if mesh.dim > 1: dims.append('x') if mesh.dim > 2: dims.append('y') dims.append('z') else: for d in dimension: dims.append(d) # sh[-1] is always 'z' # sh[0] is always 'x' if in 2 or 3d # sh[1] is always 'y' if dim > 2 sh = mesh.shape(include_bc=True, as_grid=True) if mesh.dim > 1: if 'x' in dims: lbc = _set_bc(mesh.x.lbc) rbc = _set_bc(mesh.x.rbc) delta = mesh.x.delta Dx = _build_derivative_matrix_part( sh[0], derivative, order_accuracy, h=delta, lbc=lbc, rbc=rbc, use_shifted_differences=use_shifted_differences) else: Dx = spsp.csr_matrix((sh[0], sh[0])) if mesh.dim > 2: if 'y' in dims: lbc = _set_bc(mesh.y.lbc) rbc = _set_bc(mesh.y.rbc) delta = mesh.y.delta Dy = _build_derivative_matrix_part( sh[1], derivative, order_accuracy, h=delta, lbc=lbc, rbc=rbc, use_shifted_differences=use_shifted_differences) else: Dy = spsp.csr_matrix((sh[1], sh[1])) if 'z' in dims: lbc = _set_bc(mesh.z.lbc) rbc = _set_bc(mesh.z.rbc) delta = mesh.z.delta Dz = _build_derivative_matrix_part( sh[-1], derivative, order_accuracy, h=delta, lbc=lbc, rbc=rbc, use_shifted_differences=use_shifted_differences) else: Dz = spsp.csr_matrix((sh[-1], sh[-1])) if return_1D_matrix and 'all' not in dims: if 'z' in dims: mtx = Dz elif 'y' in dims: mtx = Dy elif 'x' in dims: mtx = Dx else: if mesh.dim == 1: mtx = Dz.tocsr() if mesh.dim == 2: # kronsum in this order because wavefields are stored with 'z' in row # and 'x' in columns, then vectorized in 'C' order mtx = spsp.kronsum(Dz, Dx, format='csr') if mesh.dim == 3: mtx = spsp.kronsum(Dz, spsp.kronsum(Dy, Dx, format='csr'), format='csr') return mtx
# gradient operators gradx = sparse.kron(build_grad(Nx), sparse.identity(Ny - 1)) grady = sparse.kron(sparse.identity(Nx - 1), build_grad(Ny)) def build_K(N): # builds N-1 x N - 1 K second defivative matrix data = np.array([-np.ones(N - 2), 2 * np.ones(N - 1), -np.ones(N - 2)]) diags = np.array([-1, 0, 1]) return sparse.diags(data, diags) # Laplacian operator . Zero dirichlet boundary conditions # why the hell is this reversed? Sigh. K = sparse.kronsum(build_K(Ny), build_K(Nx)) Ksolve = linalg.factorized(K) def build_interp(N): data = np.array([np.ones(N) / 2., np.ones(N - 1) / 2.]) diags = np.array([0, 1]) return sparse.diags(data, diags, shape=(N - 1, N)) interpy = sparse.kron(sparse.identity(Nx), build_interp(Ny)) interpx = sparse.kron(build_interp(Nx), sparse.identity(Ny)) def projection_pass(vx, vy): # alternating projection? Not necessary. In fact stupid. but easy.
# sys.exit() ## A3 D3 = np.copy(D) D3[n-1, n-1] = -3 A3 = ut.sp_bmat_tridiag(I, D3, I, n) """ Dn = sparse.diags([1, -2, 1], [-1, 0, 1], shape=(n, n)) Dm = sparse.diags([1, -2, 1], [-1, 0, 1], shape=(m, m)) Dn_east = Dn.copy().tolil() Dn_east[-1, -1] += 1 A1 = sparse.kronsum(Dn, Dn) A2 = sparse.kronsum(Dm, Dn) Dn_west = Dn.copy().tolil() Dn_west[0, 0] += 1 A3 = sparse.kronsum(Dn, Dn) # print(A1.toarray()) # print(A2.toarray()) # print(A3.toarray()) # sys.exit() # Boundaries gammaH = 40 normal = 15
Nx = int(4 / h) Ny = int(4 / h) Dx = np.zeros((Nx, Nx - 1)) np.fill_diagonal(Dx, 1) np.fill_diagonal(Dx[1:, :], -1) Dy = np.zeros((Ny, Ny - 1)) np.fill_diagonal(Dy, 1) np.fill_diagonal(Dy[1:, :], -1) Lxx = Dx.T @ Dx Lyy = Dy.T @ Dy A = -1 * sp.kronsum(Lxx, Lyy) / h**2 grid = np.mgrid[h:4:h, h:4:h] x = grid[0] y = grid[1] u = u(x, y) u = np.reshape(u, ((Nx - 1) * (Ny - 1)), order='F') def forward(u0, A, dt): return (sp.identity(A.shape[0]) + dt * A) @ u0 def backward(u0, A, dt): return la.spsolve(sp.identity(A.shape[0]) - dt * A, u0)
def _create_sparse_poisson2d(n): P1d = _create_sparse_poisson1d(n) P2d = sparse.kronsum(P1d, P1d) assert_equal(P2d.shape, (n * n, n * n)) return P2d
def _create_sparse_poisson2d(n): P1d = _create_sparse_poisson1d(n) P2d = sparse.kronsum(P1d, P1d) assert_equal(P2d.shape, (n*n, n*n)) return P2d.tocsr()
def __init__(self, config): self.config = config self.w = config['width'] self.h = config['height'] self.dt = config['delta_t'] self.viscosity_k = config['viscosity_k'] self.diffusion_k = config['diffusion_k'] self.dissipation = config['dissipation'] self.vorticity = config['vorticity'] self.solver_iters = config['solver_iters'] self.fast_advect = config['fast_advect'] self.out_folder = config['out_folder'] if not os.path.exists(self.out_folder): os.makedirs(self.out_folder) self.write_vel = config['write_vel'] self.out_vel_folder = os.path.join(self.out_folder, 'vel') if self.write_vel and not os.path.exists(self.out_vel_folder): os.makedirs(self.out_vel_folder) color_keys = ('color_r', 'color_g', 'color_b') self.color = [config[k] for k in color_keys] self.color = np.array(self.color)[np.newaxis, np.newaxis, :] # Initialize scalar field(s) init_s = config.get('init_s', None) if os.path.exists(init_s): if init_s.endswith('npy'): self.s = np.load(init_s) while len(self.s.shape) < 3: self.s = np.expand_dims(self.s, -1) else: self.s = imageio.imread(init_s) / 255.0 print('Loaded scalar field from `%s`.' % init_s) else: self.s = np.zeros((self.h, self.w, 1)) self.ns = self.s.shape[-1] # number of scalar fields # Initialize velocity field init_v = config.get('init_v', None) if os.path.exists(init_v): self.v = np.load(init_v) print('Loaded velocity field from `%s`.' % init_v) else: self.v = np.zeros((self.h, self.w, 2)) # order: (vx, vy) # For warping if self.fast_advect: xx, yy = np.meshgrid(np.arange(self.w), np.arange(self.h)) self.base_coords = np.stack((xx, yy), axis=-1) # (h, w, 2) # Set guiding attributes self.target_v = None self.guiding = config['guiding'] target_v_path = config['target_v'] if os.path.exists(target_v_path): self.target_v = np.load(target_v_path) print('Loaded target velocity field from `%s`.' % target_v_path) gauss = utils.gaussian2d(self.config['blur_size']) self.blur_kernel = 2.0 * gauss @ gauss self.blur_kernel = self.blur_kernel[:, :, np.newaxis] self.blur = lambda field: convolve(field, self.blur_kernel, 'same') # Blur target self.target_v = self.blur(self.target_v) # Algorithm-specific guiding setup self.guiding_alg = config['guiding_alg'] self.pd_params = config.get('pd_params', {}) self.pd_x, self.pd_y, self.pd_z = None, None, None self.cw, self.tw, self.lsqr_A = None, None, None if self.guiding_alg == 'pd': self.pd_params = config['pd_params'] self.pd_x = np.zeros_like(self.v) self.pd_y = np.zeros_like(self.v) self.pd_z = np.zeros_like(self.v) elif self.guiding_alg == 'lsqr': # Current/target weights lsqr_params = config.get('lsqr_params', {}) self.cw = lsqr_params.get('current_w', 0.5) self.tw = lsqr_params.get('target_w', 0.5) weight_sum = self.cw + self.tw self.cw = float(self.cw) / weight_sum self.tw = float(self.tw) / weight_sum # Define A self.define_lsqr_A() # Ref: Philip Zucker (https://bit.ly/2Tx2LuE) def lapl(N): diagonals = np.array( [-np.ones(N - 1), 2 * np.ones(N), -np.ones(N - 1)]) return sparse.diags(diagonals, [-1, 0, 1]) lapl2 = sparse.kronsum(lapl(self.w), lapl(self.h)) self.project_solve = sparse.linalg.factorized(lapl2) self.frame_no = 0
def calc_Ekin(dim_basis, n_part, basis_specs, eigensys_coord): """Calculates the kinetic energy matrix. 1) fill 1-particle matrix for 1 Cartesian dimension 2) fill the N-particle, D-cart-dim matrix via a double Kronecker sum :dim_basis: dvr basis dimension '=' nbr of grid points (for ONE dimension) :n_part: nbr of particles :basis_specs: type and parameters of the variation basis (includes spatial dimensionality) :eigensys_coord: eigenvectors and transformation matrix from variational to discrete basis :return: Kinetic energy matrix """ tmp = np.zeros((dim_basis, dim_basis)) tmp2 = np.zeros((dim_basis, dim_basis)) # analytic DVR of the kinetic-energy operator from # The Journal of Chemical Physics 96, 1982 (1992), Eq. A6a/b if basis_specs[0] == 'SINE': # infer the constant grid spacing (dx) and the box length (L) from # the eigenvalues; as the eigenvalues do not include the edges, 2*dx # has to be added; if sum( np.isclose(np.diff(eigensys_coord[0]), np.roll(np.diff(eigensys_coord[0]), 1))) != len(eigensys_coord[0]) - 1: print( 'Grid points of the SINE basis are not equally spaced! Exiting...' ) exit() dx = abs(eigensys_coord[0][1] - eigensys_coord[0][0]) L = abs(eigensys_coord[0][-1] - eigensys_coord[0][0]) + 2 * dx for i in range(dim_basis): for ip in range(dim_basis): i_idx = i + 1 ip_idx = ip + 1 # to array indices (i,ip) add 1 if i == ip: tmp[i, i] = (((2. * (dim_basis + 1)**2 + 1) / 3.) - np.sin(i_idx * (np.pi / (dim_basis + 1)))**(-2)) else: tmp[i, ip] = ((-1)**(i_idx - ip_idx)) * ( np.sin(np.pi / (2. * (dim_basis + 1)) * (i_idx - ip_idx))**(-2) - np.sin(np.pi / (2. * (dim_basis + 1)) * (i_idx + ip_idx))**(-2)) tmp[i, ip] *= np.pi**2 / (2. * L**2) tmp = tmp / (2. * basis_specs[1][3]) # this factor has to be verified! if basis_specs[0] == 'HO': for alpha in range(dim_basis): for beta in range(dim_basis): for k in range(dim_basis): tmp[alpha, beta] += basis_specs[1][3] * eigensys_coord[1][ k, alpha] * (k + 0.5) * eigensys_coord[1][k, beta] if alpha == beta: tmp[alpha, beta] -= 0.5 * basis_specs[1][2] * basis_specs[ 1][3]**2 * (eigensys_coord[0][alpha] - basis_specs[1][1])**2 mEkin = csr_matrix(0) # the two loops represent the Kronecker sums which generate the full matrix # for N particles, each in D Cartesian dimensions for particle in range(n_part): for cart_dim in range(basis_specs[1][0]): mEkin = kronsum(mEkin, tmp) return mEkin