def _rebuild_operators(self): ConstantDensityAcousticTimeScalar_1D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # Stiffness matrix K doesn't change oc.K = spsp.bmat([[-oc.L, -oc.Dz], [oc.sigmaz*oc.Dz, oc.sigmaz]]) oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1,)) C = spsp.bmat([[oc.sigmaz*oc.m, None], [None, oc.I]]) / self.dt M = spsp.bmat([[oc.m, None], [None, oc.empty]]) / self.dt**2 Stilde_inv = M+C Stilde_inv.data = 1./Stilde_inv.data self.A_k = Stilde_inv*(2*M - oc.K + C) self.A_km1 = -1*Stilde_inv*(M) self.A_f = Stilde_inv
def _rebuild_operators(self): ConstantDensityAcousticTimeScalar_1D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # Stiffness matrix K doesn't change oc.K = spsp.bmat([[ -oc.L, -oc.Dz], [oc.sigmaz*oc.Dz, oc.sigmaz]]) oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1,)) C = spsp.bmat([[oc.sigmaz*oc.m, None], [ None, oc.I]]) / self.dt M = spsp.bmat([[oc.m, None], [None, oc.empty]]) / self.dt**2 Stilde_inv = M+C Stilde_inv.data = 1./Stilde_inv.data self.A_k = Stilde_inv*(2*M - oc.K + C) self.A_km1 = -1*Stilde_inv*(M) self.A_f = Stilde_inv
def _build_helmholtz_operator(self, nu): omega = 2 * np.pi * nu # we build the right helmholtz operator compact or not if self._local_support_spec['spatial_dimension'] == 1: # 1D the compact is not implemented so we raise a warming and use the auxiliary field PML return (-(omega**2) * self.M + omega * 1j * self.C + self.K).tocsc() elif self.mesh.x.lbc.type == 'pml': if self.mesh.x.lbc.domain_bc.compact: # building the compact operator oc = self.operator_components if self._local_support_spec['spatial_dimension'] == 2: dx, dz = self.mesh.deltas length_pml_x = dx * (self.mesh.x.lbc.n - 1) length_pml_z = dz * (self.mesh.z.lbc.n - 1) H1 = -(omega**2) * oc.M H2 = make_diag_mtx(-1j / (omega * length_pml_x) * oc.sxp / (1 - 1j / omega * oc.sx)**3).dot(oc.Dx) H3 = make_diag_mtx(-1j / (omega * length_pml_z) * oc.szp / (1 - 1j / omega * oc.sz)**3).dot(oc.Dz) H4 = -make_diag_mtx(1.0 / (1 - 1j / omega * oc.sx)**2).dot( oc.Dxx) H5 = -make_diag_mtx(1.0 / (1 - 1j / omega * oc.sz)**2).dot( oc.Dzz) return (H1 + H2 + H3 + H4 + H5).tocsc( ) # csc is used for the sparse solvers right now if self._local_support_spec['spatial_dimension'] == 3: dx, dy, dz = self.mesh.deltas length_pml_x = dx * (self.mesh.x.lbc.n - 1) length_pml_y = dy * (self.mesh.y.lbc.n - 1) length_pml_z = dz * (self.mesh.z.lbc.n - 1) H1 = -(omega**2) * oc.M H2 = make_diag_mtx(-1j / (omega * length_pml_x) * oc.sxp / (1 - 1j / omega * oc.sx)**3).dot(oc.Dx) H3 = make_diag_mtx(-1j / (omega * length_pml_y) * oc.syp / (1 - 1j / omega * oc.sy)**3).dot(oc.Dy) H4 = make_diag_mtx(-1j / (omega * length_pml_z) * oc.szp / (1 - 1j / omega * oc.sz)**3).dot(oc.Dz) H5 = -make_diag_mtx(1.0 / (1 - 1j / omega * oc.sx)**2).dot( oc.Dxx) H6 = -make_diag_mtx(1.0 / (1 - 1j / omega * oc.sy)**2).dot( oc.Dyy) H7 = -make_diag_mtx(1.0 / (1 - 1j / omega * oc.sz)**2).dot( oc.Dzz) return (H1 + H2 + H3 + H4 + H5 + H6 + H7).tocsc() else: return (-(omega**2) * self.M + omega * 1j * self.C + self.K).tocsc() else: return ( -(omega**2) * self.M + omega * 1j * self.C + self.K).tocsc() # csc is used for the sparse solvers right now
def _rebuild_operators(self): dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) oc.I = spsp.eye(dof, dof) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, use_shifted_differences=self.spatial_shifted_differences) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build other useful things oc.empty = spsp.csr_matrix((dof, dof)) # Stiffness matrix K doesn't change self.K = spsp.bmat([[-oc.L, -oc.Dz], [oc.sigmaz*oc.Dz, oc.sigmaz]]) oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1,)) self.C = spsp.bmat([[oc.sigmaz*oc.m, None], [None, oc.I]]) self.M = spsp.bmat([[oc.m, None], [None, oc.empty]]) self.dM = oc.I self.dC = oc.sigmaz self.dK = 0
def _rebuild_operators(self): ConstantDensityAcousticTimeScalar_2D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: nx = self.mesh.x.n nz = self.mesh.z.n #We actually don't need to correct the operators for the boundary nodes. But it will make the final matrix a little more sparse and therefore faster. Also, it makes is more clear that something needs to happen to the boundary. Any failure to do so can easily be seen by eye. self.left_boundary_nodes = np.arange( 0, nz) #includes left corner dirichlet nodes self.right_boundary_nodes = np.arange( (nx - 1) * nz, nx * nz) #uncludes right corner dirichlet nodes self.top_boundary_nodes = np.arange( nz, (nx - 1) * nz, nx) #does not include corner dirichlet nodes self.bot_boundary_nodes = np.arange( 2 * nz - 1, nx * nz - 1, nx) #does not include corner dirichlet nodes self.all_boundary_nodes = np.concatenate([ self.left_boundary_nodes, self.right_boundary_nodes, self.top_boundary_nodes, self.bot_boundary_nodes ]) # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) #Set the rows corresponding to the boundary nodes in oc.L to zero (could be any junk value). This is not necessary, but will indicate that I will have to correct the boundary values at the end of the time increment. oc.L = self._zero_mat_rows(oc.L, self.all_boundary_nodes) # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) oc._numpy_components_built = True C = self.model_parameters.C #just wavespeed. Don't confuse with the matrix C that used to be here for a while oc.m = make_diag_mtx((C**-2).reshape(-1, )) K = -oc.L M = oc.m / self.dt**2 M_bc_zero = self._zero_mat_rows( M, self.all_boundary_nodes ) #put boundary values to zero, not really necessary because boundary values will be overwritten anyway. But easier to see that something must happen when the algorithm will default them to zero so you know you need to correct them. Stilde_inv = M Stilde_inv.data = 1. / Stilde_inv.data self.A_k = Stilde_inv * (2 * M_bc_zero - K) self.A_km1 = -1 * Stilde_inv * (M_bc_zero) self.A_f = Stilde_inv
def _turn_sparse_rows_to_identity(A, rows_to_keep, rows_to_change): #Convenience function for removing some rows from the sparse laplacian #Had some major performance problems by simply slicing in all the matrix formats I tried. nr, nc = A.shape if nr != nc: raise Exception('assuming square matrix') #Create diagonal matrix. When we multiply A by this matrix we can remove rows rows_to_keep_diag = np.zeros(nr, dtype='int32') rows_to_keep_diag[rows_to_keep] = 1 diag_mat_remove_rows = make_diag_mtx(rows_to_keep_diag) #The matrix below has the rows we want to turn into identity turned to 0 A_with_rows_removed = diag_mat_remove_rows * A #Make diag matrix that has diagonal entries in the rows we want to be identity rows_to_change_diag = np.zeros(nr, dtype='int32') rows_to_change_diag[rows_to_change] = 1 A_with_identity_rows = make_diag_mtx(rows_to_change_diag) A_modified = A_with_rows_removed + A_with_identity_rows return A_modified
def _turn_sparse_rows_to_identity(A, rows_to_keep, rows_to_change): #Convenience function for removing some rows from the sparse laplacian #Had some major performance problems by simply slicing in all the matrix formats I tried. nr,nc = A.shape if nr != nc: raise Exception('assuming square matrix') #Create diagonal matrix. When we multiply A by this matrix we can remove rows rows_to_keep_diag = np.zeros(nr, dtype='int32') rows_to_keep_diag[rows_to_keep] = 1 diag_mat_remove_rows = make_diag_mtx(rows_to_keep_diag) #The matrix below has the rows we want to turn into identity turned to 0 A_with_rows_removed = diag_mat_remove_rows*A #Make diag matrix that has diagonal entries in the rows we want to be identity rows_to_change_diag = np.zeros(nr, dtype='int32') rows_to_change_diag[rows_to_change] = 1 A_with_identity_rows = make_diag_mtx(rows_to_change_diag) A_modified = A_with_rows_removed + A_with_identity_rows return A_modified
def _rebuild_operators(self): dof = self.mesh.dof(include_bc=True) # a more readable reference oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.minus_sigmax = make_diag_mtx(-sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.minus_sigmaz = make_diag_mtx(-sz) # build Dx oc.Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x') # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx * sz) oc.minus_sigma_xPz = oc.minus_sigmax + oc.minus_sigmaz oc.sigma_zMx_Dx = make_diag_mtx(sz - sx) * oc.Dx oc.sigma_xMz_Dz = make_diag_mtx(sx - sz) * oc.Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m_inv = make_diag_mtx((C**2).reshape(-1, )) self.A = spsp.bmat( [[oc.empty, oc.I, oc.empty, oc.empty], [ oc.m_inv * oc.L - oc.sigma_xz, oc.minus_sigma_xPz, oc.m_inv * oc.Dx, oc.m_inv * oc.Dz ], [oc.sigma_zMx_Dx, oc.empty, oc.minus_sigmax, oc.empty], [oc.sigma_xMz_Dz, oc.empty, oc.empty, oc.minus_sigmaz]])
def _rebuild_operators(self): dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) # build sigmaz (stored as -1*sigmaz) sz = build_sigma(self.mesh, self.mesh.z) oc.minus_sigmaz = make_diag_mtx(-sz) # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) oc._numpy_components_built = True C = self.model_parameters.C oc.m_inv = make_diag_mtx((C**2).reshape(-1,)) self.A = spsp.bmat([[oc.empty, oc.I, oc.empty ], [oc.m_inv*oc.L, oc.minus_sigmaz, oc.m_inv*oc.Dz ], [oc.minus_sigmaz*oc.Dz, oc.empty, oc.minus_sigmaz]])
def _build_helmholtz_operator(self, nu): omega = 2*np.pi*nu # we build the right helmholtz operator compact or not if self._local_support_spec['spatial_dimension']==1: # 1D the compact is not implemented so we raise a warming and use the auxiliary field PML return (-(omega**2)*self.M + omega*1j*self.C + self.K).tocsc() elif self.mesh.x.lbc.type == 'pml': if self.mesh.x.lbc.domain_bc.compact: # building the compact operator oc = self.operator_components if self._local_support_spec['spatial_dimension']==2: dx, dz = self.mesh.deltas length_pml_x = dx * (self.mesh.x.lbc.n -1 ) length_pml_z = dz * (self.mesh.z.lbc.n -1 ) H1 = -(omega**2)*oc.M H2 = make_diag_mtx(-1j/(omega*length_pml_x) * oc.sxp / (1 - 1j/omega * oc.sx)**3).dot(oc.Dx) H3 = make_diag_mtx(-1j/(omega*length_pml_z) * oc.szp / (1 - 1j/omega * oc.sz)**3).dot(oc.Dz) H4 = - make_diag_mtx(1.0/(1 - 1j/omega * oc.sx)**2).dot(oc.Dxx) H5 = - make_diag_mtx(1.0/(1 - 1j/omega * oc.sz)**2).dot(oc.Dzz) return (H1 + H2 + H3 + H4 + H5).tocsc() # csc is used for the sparse solvers right now if self._local_support_spec['spatial_dimension']==3: dx, dy, dz = self.mesh.deltas length_pml_x = dx * (self.mesh.x.lbc.n -1 ) length_pml_y = dy * (self.mesh.y.lbc.n -1 ) length_pml_z = dz * (self.mesh.z.lbc.n -1 ) H1 = -(omega**2)*oc.M H2 = make_diag_mtx(-1j/(omega*length_pml_x) * oc.sxp / (1 - 1j/omega * oc.sx)**3).dot(oc.Dx) H3 = make_diag_mtx(-1j/(omega*length_pml_y) * oc.syp / (1 - 1j/omega * oc.sy)**3).dot(oc.Dy) H4 = make_diag_mtx(-1j/(omega*length_pml_z) * oc.szp / (1 - 1j/omega * oc.sz)**3).dot(oc.Dz) H5 = - make_diag_mtx(1.0/(1 - 1j/omega * oc.sx)**2).dot(oc.Dxx) H6 = - make_diag_mtx(1.0/(1 - 1j/omega * oc.sy)**2).dot(oc.Dyy) H7 = - make_diag_mtx(1.0/(1 - 1j/omega * oc.sz)**2).dot(oc.Dzz) return (H1 + H2 + H3 + H4 + H5 + H6 + H7).tocsc() else: return (-(omega**2)*self.M + omega*1j*self.C + self.K).tocsc() else: return (-(omega**2)*self.M + omega*1j*self.C + self.K).tocsc() # csc is used for the sparse solvers right now
def _rebuild_operators(self): dof = self.mesh.dof(include_bc=True) # a more readable reference oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.minus_sigmax = make_diag_mtx(-sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.minus_sigmaz = make_diag_mtx(-sz) # build Dx oc.Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x') # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx*sz) oc.minus_sigma_xPz = oc.minus_sigmax + oc.minus_sigmaz oc.sigma_zMx_Dx = make_diag_mtx(sz-sx)*oc.Dx oc.sigma_xMz_Dz = make_diag_mtx(sx-sz)*oc.Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m_inv = make_diag_mtx((C**2).reshape(-1,)) self.A = spsp.bmat([[oc.empty, oc.I, oc.empty, oc.empty ], [oc.m_inv*oc.L-oc.sigma_xz, oc.minus_sigma_xPz, oc.m_inv*oc.Dx, oc.m_inv*oc.Dz ], [oc.sigma_zMx_Dx, oc.empty, oc.minus_sigmax, oc.empty ], [oc.sigma_xMz_Dz, oc.empty, oc.empty, oc.minus_sigmaz ]])
def _rebuild_operators(self): if self.mesh.x.lbc.type == 'pml' and self.compact: # build intermediates for the compact operator dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2) oc.I = spsp.eye(dof, dof) # build the static components if not built: # build Dxx oc.Dxx = build_derivative_matrix( self.mesh, 2, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dzz oc.Dzz = build_derivative_matrix( self.mesh, 2, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build Dx oc.Dx = build_derivative_matrix( self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dz oc.Dz = build_derivative_matrix( self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build sigma oc.sx, oc.sz, oc.sxp, oc.szp = self._sigma_PML(self.mesh) oc._numpy_components_built = True self.dK = 0 self.dC = 0 self.dM = oc.I else: # build intermediates for operator with auxiliary fields dof = self.mesh.dof(include_bc=True) oc = self.operator_components oc.I = spsp.eye(dof, dof) built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix( self.mesh, 2, self.spatial_accuracy_order, use_shifted_differences=self.spatial_shifted_differences) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix( self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix( self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx * sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz - sx)) * oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx - sz)) * oc.minus_Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1, )) self.K = spsp.bmat( [[oc.m * oc.sigma_xz - oc.L, oc.minus_Dx, oc.minus_Dz], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz]]) self.C = spsp.bmat([[oc.m * oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I]]) self.M = spsp.bmat([[oc.m, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]]) self.dK = oc.sigma_xz self.dC = oc.sigma_xPz self.dM = oc.I
def _rebuild_operators(self): dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, use_shifted_differences=self.spatial_shifted_differences) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx*sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1,)) self.K = spsp.bmat([[oc.m*oc.sigma_xz-oc.L, oc.minus_Dx, oc.minus_Dz ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty ], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz ]]) self.C = spsp.bmat([[oc.m*oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I ]]) self.M = spsp.bmat([[ oc.m, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]])
def _rebuild_operators(self): if self.mesh.x.lbc.type == 'pml' and self.compact: # build intermediates for the compact operator raise ValidationFunctionError( " This solver is in construction and is not yet complete. For variable density and compact PML." ) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2) # build the static components if not built: # build Dxx oc.Dxx = build_derivative_matrix( self.mesh, 2, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dzz oc.Dzz = build_derivative_matrix( self.mesh, 2, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build Dx oc.Dx = build_derivative_matrix( self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dz oc.Dz = build_derivative_matrix( self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build sigma oc.sx, oc.sz, oc.sxp, oc.szp = self._sigma_PML(self.mesh) oc._numpy_components_built = True else: # build intermediates for operator with auxiliary fields dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix( self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix( self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx * sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz - sx)) * oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx - sz)) * oc.minus_Dz oc._numpy_components_built = True kappa = self.model_parameters.kappa rho = self.model_parameters.rho oc.m1 = make_diag_mtx((kappa**-1).reshape(-1, )) oc.m2 = make_diag_mtx((rho**-1).reshape(-1, )) # build heterogenous laplacian sh = self.mesh.shape(include_bc=True, as_grid=True) deltas = [self.mesh.x.delta, self.mesh.z.delta] oc.L = build_derivative_matrix_VDA(self.mesh, 2, self.spatial_accuracy_order, alpha=rho**-1) # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho. # Currently the creation of oc.L is slow. This is because we have implemented a cenetered heterogenous laplacian. # To speed up computation, we could compute a div(m2 grad) operator that is not centered by simply multiplying # a divergence operator by oc.m2 by a gradient operator. self.K = spsp.bmat([[ oc.m1 * oc.sigma_xz - oc.L, oc.minus_Dx * oc.m2, oc.minus_Dz * oc.m2 ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz]]) self.C = spsp.bmat([[oc.m1 * oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I]]) self.M = spsp.bmat([[oc.m1, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]])
def _rebuild_operators(self): dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx*sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz oc._numpy_components_built = True kappa = self.model_parameters.kappa rho = self.model_parameters.rho oc.m1 = make_diag_mtx((kappa**-1).reshape(-1,)) oc.m2 = make_diag_mtx((rho**-1).reshape(-1,)) # build heterogenous laplacian sh = self.mesh.shape(include_bc=True,as_grid=True) deltas = [self.mesh.x.delta,self.mesh.z.delta] oc.L = build_heterogenous_laplacian(sh,rho**-1,deltas) # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho. # Currently the creation of oc.L is slow. This is because we have implemented a cenetered heterogenous laplacian. # To speed up computation, we could compute a div(m2 grad) operator that is not centered by simply multiplying # a divergence operator by oc.m2 by a gradient operator. self.K = spsp.bmat([[oc.m1*oc.sigma_xz-oc.L, oc.minus_Dx*oc.m2, oc.minus_Dz*oc.m2 ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty ], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz ]]) self.C = spsp.bmat([[oc.m1*oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I ]]) self.M = spsp.bmat([[ oc.m1, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]])
def _rebuild_operators(self): if self.mesh.x.lbc.type == 'pml' and self.compact: # build intermediates for compact operator dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2) # build the static components if not built: # build Dxx oc.Dxx = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dzz oc.Dzz = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build Dyy oc.Dyy = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, dimension='y', use_shifted_differences=self.spatial_shifted_differences) # build Dx oc.Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build Dz oc.Dy = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='y', use_shifted_differences=self.spatial_shifted_differences) # build sigma oc.sx, oc.sy, oc.sz, oc.sxp, oc.syp, oc.szp = self._sigma_PML(self.mesh) oc._numpy_components_built = True else : # build intermediates for operator with auxiliary fields dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, use_shifted_differences=self.spatial_shifted_differences) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmay sy = build_sigma(self.mesh, self.mesh.y) oc.sigmay = make_diag_mtx(sy) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dx.data *= -1 # build Dy oc.minus_Dy = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='y', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dy.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.minus_I = -1*oc.I oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_sum_pair_prod = make_diag_mtx(sx*sy + sx*sz + sy*sz) oc.sigma_sum = make_diag_mtx(sx+sy+sz) oc.sigma_prod = make_diag_mtx(sx*sy*sz) oc.minus_sigma_yPzMx_Dx = make_diag_mtx(sy+sz-sx)*oc.minus_Dx oc.minus_sigma_xPzMy_Dy = make_diag_mtx(sx+sz-sy)*oc.minus_Dy oc.minus_sigma_xPyMz_Dz = make_diag_mtx(sx+sy-sz)*oc.minus_Dz oc.minus_sigma_yz_Dx = make_diag_mtx(sy*sz)*oc.minus_Dx oc.minus_sigma_zx_Dy = make_diag_mtx(sz*sx)*oc.minus_Dy oc.minus_sigma_xy_Dz = make_diag_mtx(sx*sy)*oc.minus_Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1,)) self.K = spsp.bmat([[oc.m*oc.sigma_sum_pair_prod-oc.L, oc.m*oc.sigma_prod, oc.minus_Dx, oc.minus_Dy, oc.minus_Dz ], [oc.minus_I, oc.empty, oc.empty, oc.empty, oc.empty ], [oc.minus_sigma_yPzMx_Dx, oc.minus_sigma_yz_Dx, oc.sigmax, oc.empty, oc.empty ], [oc.minus_sigma_xPzMy_Dy, oc.minus_sigma_zx_Dy, oc.empty, oc.sigmay, oc.empty ], [oc.minus_sigma_xPyMz_Dz, oc.minus_sigma_xy_Dz, oc.empty, oc.empty, oc.sigmaz ]]) self.C = spsp.bmat([[oc.m*oc.sigma_sum, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.I, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.I ]]) / self.dt self.M = spsp.bmat([[ oc.m, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty]])
def _rebuild_operators(self): ConstantDensityAcousticTimeScalar_2D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x') oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx*sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1,)) K = spsp.bmat([[oc.m*oc.sigma_xz-oc.L, oc.minus_Dx, oc.minus_Dz], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz]]) C = spsp.bmat([[oc.m*oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I]]) / self.dt M = spsp.bmat([[oc.m, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]]) / self.dt**2 Stilde_inv = M+C Stilde_inv.data = 1./Stilde_inv.data self.A_k = Stilde_inv*(2*M - K + C) self.A_km1 = -1*Stilde_inv*(M) self.A_f = Stilde_inv
def _build_derivative_matrix_staggered_structured_cartesian(mesh, derivative, order_accuracy, dimension='all', alpha = None, return_1D_matrix=False, **kwargs): #Some of the operators could be cached the same way I did to make 'build_permutation_matrix' faster. #Could be considered if the current speed is ever considered to be insufficient. import time tt = time.time() if return_1D_matrix: raise Exception('Not yet implemented') if derivative < 1 or derivative > 2: raise ValueError('Only defined for first and second order right now') if derivative == 1 and dimension not in ['x', 'y', 'z']: raise ValueError('First derivative requires a direciton') sh = mesh.shape(include_bc = True, as_grid = True) #Will include PML padding if len(sh) != 2: raise Exception('currently hardcoded 2D implementation, relatively straight-forward to change. Look at the function build_derivative_matrix to get a more general function.') nx = sh[0] nz = sh[-1] #Currently I am working with density input on the regular grid. #In the derivation of the variable density solver we only require density at the stagger points #For now I am just interpolating density defined on regular points towards the stagger points and use that as 'density model'. #Later it is probably better to define the density directly on the stagger points (and evaluate density gradient there to update directly at these points?) if type(alpha) == None: #If no alpha is given, we set it to a uniform vector. The result should be the homogeneous Laplacian. alpha = np.ones(nx*nz) alpha = alpha.flatten() #make 1D dx = mesh.x.delta dz = mesh.z.delta #Get 1D linear interpolation matrices Jx_1d = build_linear_interpolation_matrix_part(nx) Jz_1d = build_linear_interpolation_matrix_part(nz) #Get 1D derivative matrix for first spatial derivative using the desired order of accuracy lbc_x = _set_bc(mesh.x.lbc) rbc_x = _set_bc(mesh.x.rbc) lbc_z = _set_bc(mesh.z.lbc) rbc_z = _set_bc(mesh.z.rbc) Dx_1d = _build_staggered_first_derivative_matrix_part(nx, order_accuracy, h=dx, lbc = lbc_x, rbc = rbc_x) Dz_1d = _build_staggered_first_derivative_matrix_part(nz, order_accuracy, h=dz, lbc = lbc_z, rbc = rbc_z) #Some empty matrices of the right shape so we can use kronsum to get the proper 2D matrices for the operations we want. #The same is used in the homogeneous 'build_derivative_matrix' function. Ix = spsp.eye(nx) Iz = spsp.eye(nz) Dx_2d = spsp.kron(Dx_1d, Iz, format='csr') if dimension == 'x' and derivative == 1: return Dx_2d Dz_2d = spsp.kron(Ix, Dz_1d, format='csr') if dimension == 'z' and derivative == 1: return Dz_2d #If we are evaluating this we want to make the heterogeneous Laplacian Jx_2d = spsp.kron(Jx_1d, Iz, format='csr') Jz_2d = spsp.kron(Ix, Jz_1d, format='csr') #alpha interpolated to x stagger points. Make diag mat diag_alpha_x = make_diag_mtx(Jx_2d*alpha) #alpha interpolated to z stagger points. Make diag mat diag_alpha_z = make_diag_mtx(Jz_2d*alpha) #Create laplacian components #The negative transpose of Dx and Dz takes care of the divergence term of the heterogeneous laplacian Dxx_2d = -Dx_2d.T*diag_alpha_x*Dx_2d Dzz_2d = -Dz_2d.T*diag_alpha_z*Dz_2d #Correct the Laplacian around the boundary. This is also done in the homogeneous Laplacian #I want the heterogeneous Laplacian to be the same as the homogeneous Laplacian when alpha is uniform #This is the only part of the Laplacian that deviates from symmetry, just as in the homogeneous case. #But because of these conditions on the dirichlet boundary the wavefield will always equal 0 there and this deviation from symmetry is fine. #For indexing, get list of all boundary node numbers left_node_nrs = np.arange(nz) right_node_nrs = np.arange((nx-1)*nz,nx*nz) top_node_nrs = np.arange(nz,(nx-1)*nz,nz) #does not include left and right top node bot_node_nrs = top_node_nrs + nz - 1 #does not include left and right top node all_boundary_node_nrs = np.concatenate((left_node_nrs, right_node_nrs, top_node_nrs, bot_node_nrs)) nb = all_boundary_node_nrs.size L = Dxx_2d + Dzz_2d all_node_numbers = np.arange(0,(nx*nz), dtype='int32') internal_node_numbers = list(set(all_node_numbers) - set(all_boundary_node_nrs)) L = L.tocsr() #so we can extract rows efficiently #Operation below fixes the boundary rows quite efficiently. L_fixed = _turn_sparse_rows_to_identity(L, internal_node_numbers, all_boundary_node_nrs) return L_fixed.tocsr()
def _rebuild_operators(self): VariableDensityAcousticTimeScalar_2D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x') oc.minus_Dx = copy.deepcopy(oc.Dx) #more storage, but less computations oc.minus_Dx.data *= -1 # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') oc.minus_Dz = copy.deepcopy(oc.Dz) #more storage, but less computations oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx*sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz oc._numpy_components_built = True kappa = self.model_parameters.kappa rho = self.model_parameters.rho oc.m1 = make_diag_mtx((kappa**-1).reshape(-1,)) oc.m2 = make_diag_mtx((rho**-1).reshape(-1,)) oc.L = build_derivative_matrix_VDA(self.mesh, 2, self.spatial_accuracy_order, alpha = rho**-1 ) # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho. # Ian's implementation used the regular Dx operators in the PML even though the heterogeneous Laplacian with staggered derivative operators is used in the physical domain. # I (Bram) did not change this or investigate if this causes some problems but am noting it here for completeness. K = spsp.bmat([[oc.m1*oc.sigma_xz-oc.L, oc.minus_Dx*oc.m2, oc.minus_Dz*oc.m2 ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty ], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz ]]) C = spsp.bmat([[oc.m1*oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I ]]) / self.dt M = spsp.bmat([[ oc.m1, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]]) / self.dt**2 Stilde_inv = M+C Stilde_inv.data = 1./Stilde_inv.data self.A_k = Stilde_inv*(2*M - K + C) self.A_km1 = -1*Stilde_inv*(M) self.A_f = Stilde_inv
def _rebuild_operators(self): VariableDensityAcousticTimeScalar_2D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x') oc.minus_Dx = copy.deepcopy( oc.Dx) #more storage, but less computations oc.minus_Dx.data *= -1 # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') oc.minus_Dz = copy.deepcopy( oc.Dz) #more storage, but less computations oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx * sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz - sx)) * oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx - sz)) * oc.minus_Dz oc._numpy_components_built = True kappa = self.model_parameters.kappa rho = self.model_parameters.rho oc.m1 = make_diag_mtx((kappa**-1).reshape(-1, )) oc.m2 = make_diag_mtx((rho**-1).reshape(-1, )) oc.L = build_derivative_matrix_VDA(self.mesh, 2, self.spatial_accuracy_order, alpha=rho**-1) # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho. # Ian's implementation used the regular Dx operators in the PML even though the heterogeneous Laplacian with staggered derivative operators is used in the physical domain. # I (Bram) did not change this or investigate if this causes some problems but am noting it here for completeness. K = spsp.bmat([[ oc.m1 * oc.sigma_xz - oc.L, oc.minus_Dx * oc.m2, oc.minus_Dz * oc.m2 ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz]]) C = spsp.bmat([[oc.m1 * oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I] ]) / self.dt M = spsp.bmat([[oc.m1, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]]) / self.dt**2 Stilde_inv = M + C Stilde_inv.data = 1. / Stilde_inv.data self.A_k = Stilde_inv * (2 * M - K + C) self.A_km1 = -1 * Stilde_inv * (M) self.A_f = Stilde_inv
def _build_derivative_matrix_staggered_structured_cartesian( mesh, derivative, order_accuracy, dimension='all', alpha=None, return_1D_matrix=False, **kwargs): #Some of the operators could be cached the same way I did to make 'build_permutation_matrix' faster. #Could be considered if the current speed is ever considered to be insufficient. import time tt = time.time() if return_1D_matrix: raise Exception('Not yet implemented') if derivative < 1 or derivative > 2: raise ValueError('Only defined for first and second order right now') if derivative == 1 and dimension not in ['x', 'y', 'z']: raise ValueError('First derivative requires a direciton') sh = mesh.shape(include_bc=True, as_grid=True) #Will include PML padding if len(sh) != 2: raise Exception( 'currently hardcoded 2D implementation, relatively straight-forward to change. Look at the function build_derivative_matrix to get a more general function.' ) nx = sh[0] nz = sh[-1] #Currently I am working with density input on the regular grid. #In the derivation of the variable density solver we only require density at the stagger points #For now I am just interpolating density defined on regular points towards the stagger points and use that as 'density model'. #Later it is probably better to define the density directly on the stagger points (and evaluate density gradient there to update directly at these points?) if type( alpha ) == None: #If no alpha is given, we set it to a uniform vector. The result should be the homogeneous Laplacian. alpha = np.ones(nx * nz) alpha = alpha.flatten() #make 1D dx = mesh.x.delta dz = mesh.z.delta #Get 1D linear interpolation matrices Jx_1d = build_linear_interpolation_matrix_part(nx) Jz_1d = build_linear_interpolation_matrix_part(nz) #Get 1D derivative matrix for first spatial derivative using the desired order of accuracy lbc_x = _set_bc(mesh.x.lbc) rbc_x = _set_bc(mesh.x.rbc) lbc_z = _set_bc(mesh.z.lbc) rbc_z = _set_bc(mesh.z.rbc) Dx_1d = _build_staggered_first_derivative_matrix_part(nx, order_accuracy, h=dx, lbc=lbc_x, rbc=rbc_x) Dz_1d = _build_staggered_first_derivative_matrix_part(nz, order_accuracy, h=dz, lbc=lbc_z, rbc=rbc_z) #Some empty matrices of the right shape so we can use kronsum to get the proper 2D matrices for the operations we want. #The same is used in the homogeneous 'build_derivative_matrix' function. Ix = spsp.eye(nx) Iz = spsp.eye(nz) Dx_2d = spsp.kron(Dx_1d, Iz, format='csr') if dimension == 'x' and derivative == 1: return Dx_2d Dz_2d = spsp.kron(Ix, Dz_1d, format='csr') if dimension == 'z' and derivative == 1: return Dz_2d #If we are evaluating this we want to make the heterogeneous Laplacian Jx_2d = spsp.kron(Jx_1d, Iz, format='csr') Jz_2d = spsp.kron(Ix, Jz_1d, format='csr') #alpha interpolated to x stagger points. Make diag mat diag_alpha_x = make_diag_mtx(Jx_2d * alpha) #alpha interpolated to z stagger points. Make diag mat diag_alpha_z = make_diag_mtx(Jz_2d * alpha) #Create laplacian components #The negative transpose of Dx and Dz takes care of the divergence term of the heterogeneous laplacian Dxx_2d = -Dx_2d.T * diag_alpha_x * Dx_2d Dzz_2d = -Dz_2d.T * diag_alpha_z * Dz_2d #Correct the Laplacian around the boundary. This is also done in the homogeneous Laplacian #I want the heterogeneous Laplacian to be the same as the homogeneous Laplacian when alpha is uniform #This is the only part of the Laplacian that deviates from symmetry, just as in the homogeneous case. #But because of these conditions on the dirichlet boundary the wavefield will always equal 0 there and this deviation from symmetry is fine. #For indexing, get list of all boundary node numbers left_node_nrs = np.arange(nz) right_node_nrs = np.arange((nx - 1) * nz, nx * nz) top_node_nrs = np.arange(nz, (nx - 1) * nz, nz) #does not include left and right top node bot_node_nrs = top_node_nrs + nz - 1 #does not include left and right top node all_boundary_node_nrs = np.concatenate( (left_node_nrs, right_node_nrs, top_node_nrs, bot_node_nrs)) nb = all_boundary_node_nrs.size L = Dxx_2d + Dzz_2d all_node_numbers = np.arange(0, (nx * nz), dtype='int32') internal_node_numbers = list( set(all_node_numbers) - set(all_boundary_node_nrs)) L = L.tocsr() #so we can extract rows efficiently #Operation below fixes the boundary rows quite efficiently. L_fixed = _turn_sparse_rows_to_identity(L, internal_node_numbers, all_boundary_node_nrs) return L_fixed.tocsr()
def _rebuild_operators(self): VariableDensityAcousticTimeScalar_2D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x') oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx*sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz oc._numpy_components_built = True kappa = self.model_parameters.kappa rho = self.model_parameters.rho oc.m1 = make_diag_mtx((kappa**-1).reshape(-1,)) oc.m2 = make_diag_mtx((rho**-1).reshape(-1,)) # build heterogenous laplacian sh = self.mesh.shape(include_bc=True,as_grid=True) deltas = [self.mesh.x.delta,self.mesh.z.delta] oc.L = build_heterogenous_laplacian(sh,rho**-1,deltas) # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho. # Currently the creation of oc.L is slow. This is because we have implemented a cenetered heterogenous laplacian. # To speed up computation, we could compute a div(m2 grad) operator that is not centered by simply multiplying # a divergence operator by oc.m2 by a gradient operator. K = spsp.bmat([[oc.m1*oc.sigma_xz-oc.L, oc.minus_Dx*oc.m2, oc.minus_Dz*oc.m2 ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty ], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz ]]) C = spsp.bmat([[oc.m1*oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I ]]) / self.dt M = spsp.bmat([[ oc.m1, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]]) / self.dt**2 Stilde_inv = M+C Stilde_inv.data = 1./Stilde_inv.data self.A_k = Stilde_inv*(2*M - K + C) self.A_km1 = -1*Stilde_inv*(M) self.A_f = Stilde_inv
def _rebuild_operators(self): ConstantDensityAcousticTimeScalar_3D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get("_numpy_components_built", False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmay sy = build_sigma(self.mesh, self.mesh.y) oc.sigmay = make_diag_mtx(sy) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension="x") oc.minus_Dx.data *= -1 # build Dy oc.minus_Dy = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension="y") oc.minus_Dy.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension="z") oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.minus_I = -1 * oc.I oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_sum_pair_prod = make_diag_mtx(sx * sy + sx * sz + sy * sz) oc.sigma_sum = make_diag_mtx(sx + sy + sz) oc.sigma_prod = make_diag_mtx(sx * sy * sz) oc.minus_sigma_yPzMx_Dx = make_diag_mtx(sy + sz - sx) * oc.minus_Dx oc.minus_sigma_xPzMy_Dy = make_diag_mtx(sx + sz - sy) * oc.minus_Dy oc.minus_sigma_xPyMz_Dz = make_diag_mtx(sx + sy - sz) * oc.minus_Dz oc.minus_sigma_yz_Dx = make_diag_mtx(sy * sz) * oc.minus_Dx oc.minus_sigma_zx_Dy = make_diag_mtx(sz * sx) * oc.minus_Dy oc.minus_sigma_xy_Dz = make_diag_mtx(sx * sy) * oc.minus_Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C ** -2).reshape(-1)) K = spsp.bmat( [ [oc.m * oc.sigma_sum_pair_prod - oc.L, oc.m * oc.sigma_prod, oc.minus_Dx, oc.minus_Dy, oc.minus_Dz], [oc.minus_I, oc.empty, oc.empty, oc.empty, oc.empty], [oc.minus_sigma_yPzMx_Dx, oc.minus_sigma_yz_Dx, oc.sigmax, oc.empty, oc.empty], [oc.minus_sigma_xPzMy_Dy, oc.minus_sigma_zx_Dy, oc.empty, oc.sigmay, oc.empty], [oc.minus_sigma_xPyMz_Dz, oc.minus_sigma_xy_Dz, oc.empty, oc.empty, oc.sigmaz], ] ) C = ( spsp.bmat( [ [oc.m * oc.sigma_sum, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.I, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.I], ] ) / self.dt ) M = ( spsp.bmat( [ [oc.m, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], ] ) / self.dt ** 2 ) Stilde_inv = M + C Stilde_inv.data = 1.0 / Stilde_inv.data self.A_k = Stilde_inv * (2 * M - K + C) self.A_km1 = -1 * Stilde_inv * (M) self.A_f = Stilde_inv
def _rebuild_operators(self): dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, use_shifted_differences=self.spatial_shifted_differences) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmay sy = build_sigma(self.mesh, self.mesh.y) oc.sigmay = make_diag_mtx(sy) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dx.data *= -1 # build Dy oc.minus_Dy = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='y', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dy.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.minus_I = -1*oc.I oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_sum_pair_prod = make_diag_mtx(sx*sy + sx*sz + sy*sz) oc.sigma_sum = make_diag_mtx(sx+sy+sz) oc.sigma_prod = make_diag_mtx(sx*sy*sz) oc.minus_sigma_yPzMx_Dx = make_diag_mtx(sy+sz-sx)*oc.minus_Dx oc.minus_sigma_xPzMy_Dy = make_diag_mtx(sx+sz-sy)*oc.minus_Dy oc.minus_sigma_xPyMz_Dz = make_diag_mtx(sx+sy-sz)*oc.minus_Dz oc.minus_sigma_yz_Dx = make_diag_mtx(sy*sz)*oc.minus_Dx oc.minus_sigma_zx_Dy = make_diag_mtx(sz*sx)*oc.minus_Dy oc.minus_sigma_xy_Dz = make_diag_mtx(sx*sy)*oc.minus_Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1,)) self.K = spsp.bmat([[oc.m*oc.sigma_sum_pair_prod-oc.L, oc.m*oc.sigma_prod, oc.minus_Dx, oc.minus_Dy, oc.minus_Dz ], [oc.minus_I, oc.empty, oc.empty, oc.empty, oc.empty ], [oc.minus_sigma_yPzMx_Dx, oc.minus_sigma_yz_Dx, oc.sigmax, oc.empty, oc.empty ], [oc.minus_sigma_xPzMy_Dy, oc.minus_sigma_zx_Dy, oc.empty, oc.sigmay, oc.empty ], [oc.minus_sigma_xPyMz_Dz, oc.minus_sigma_xy_Dz, oc.empty, oc.empty, oc.sigmaz ]]) self.C = spsp.bmat([[oc.m*oc.sigma_sum, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.I, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.I ]]) / self.dt self.M = spsp.bmat([[ oc.m, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty, oc.empty, oc.empty]])
def _rebuild_operators(self): if self.mesh.x.lbc.type == 'pml' and self.compact: # build intermediates for the compact operator raise ValidationFunctionError(" This solver is in construction and is not yet complete. For variable density and compact PML.") dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2) # build the static components if not built: # build Dxx oc.Dxx = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dzz oc.Dzz = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build Dx oc.Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build sigma oc.sx, oc.sz, oc.sxp, oc.szp = self._sigma_PML(self.mesh) oc._numpy_components_built = True else: # build intermediates for operator with auxiliary fields dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx*sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz oc._numpy_components_built = True kappa = self.model_parameters.kappa rho = self.model_parameters.rho oc.m1 = make_diag_mtx((kappa**-1).reshape(-1,)) oc.m2 = make_diag_mtx((rho**-1).reshape(-1,)) # build heterogenous laplacian sh = self.mesh.shape(include_bc=True,as_grid=True) deltas = [self.mesh.x.delta,self.mesh.z.delta] oc.L = build_heterogenous_laplacian(sh,rho**-1,deltas) # oc.L is a heterogenous laplacian operator. It computes div(m2 grad), where m2 = 1/rho. # Currently the creation of oc.L is slow. This is because we have implemented a cenetered heterogenous laplacian. # To speed up computation, we could compute a div(m2 grad) operator that is not centered by simply multiplying # a divergence operator by oc.m2 by a gradient operator. self.K = spsp.bmat([[oc.m1*oc.sigma_xz-oc.L, oc.minus_Dx*oc.m2, oc.minus_Dz*oc.m2 ], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty ], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz ]]) self.C = spsp.bmat([[oc.m1*oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I ]]) self.M = spsp.bmat([[ oc.m1, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]])
def _rebuild_operators(self): ConstantDensityAcousticTimeScalar_2D._rebuild_operators(self) dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x') oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z') oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx * sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz - sx)) * oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx - sz)) * oc.minus_Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1, )) K = spsp.bmat([[oc.m * oc.sigma_xz - oc.L, oc.minus_Dx, oc.minus_Dz], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz]]) C = spsp.bmat([[oc.m * oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I] ]) / self.dt M = spsp.bmat([[oc.m, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]]) / self.dt**2 Stilde_inv = M + C Stilde_inv.data = 1. / Stilde_inv.data self.A_k = Stilde_inv * (2 * M - K + C) self.A_km1 = -1 * Stilde_inv * (M) self.A_f = Stilde_inv
def _rebuild_operators(self): if self.mesh.x.lbc.type == 'pml' and self.compact: # build intermediates for the compact operator dof = self.mesh.dof(include_bc=True) oc = self.operator_components built = oc.get('_numpy_components_built', False) oc.M = make_diag_mtx(self.model_parameters.C.squeeze()**-2) oc.I = spsp.eye(dof, dof) # build the static components if not built: # build Dxx oc.Dxx = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dzz oc.Dzz = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build Dx oc.Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) # build Dz oc.Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) # build sigma oc.sx, oc.sz, oc.sxp, oc.szp = self._sigma_PML(self.mesh) oc._numpy_components_built = True self.dK = 0 self.dC = 0 self.dM = oc.I else: # build intermediates for operator with auxiliary fields dof = self.mesh.dof(include_bc=True) oc = self.operator_components oc.I = spsp.eye(dof, dof) built = oc.get('_numpy_components_built', False) # build the static components if not built: # build laplacian oc.L = build_derivative_matrix(self.mesh, 2, self.spatial_accuracy_order, use_shifted_differences=self.spatial_shifted_differences) # build sigmax sx = build_sigma(self.mesh, self.mesh.x) oc.sigmax = make_diag_mtx(sx) # build sigmaz sz = build_sigma(self.mesh, self.mesh.z) oc.sigmaz = make_diag_mtx(sz) # build Dx oc.minus_Dx = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='x', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dx.data *= -1 # build Dz oc.minus_Dz = build_derivative_matrix(self.mesh, 1, self.spatial_accuracy_order, dimension='z', use_shifted_differences=self.spatial_shifted_differences) oc.minus_Dz.data *= -1 # build other useful things oc.I = spsp.eye(dof, dof) oc.empty = spsp.csr_matrix((dof, dof)) # useful intermediates oc.sigma_xz = make_diag_mtx(sx*sz) oc.sigma_xPz = oc.sigmax + oc.sigmaz oc.minus_sigma_zMx_Dx = make_diag_mtx((sz-sx))*oc.minus_Dx oc.minus_sigma_xMz_Dz = make_diag_mtx((sx-sz))*oc.minus_Dz oc._numpy_components_built = True C = self.model_parameters.C oc.m = make_diag_mtx((C**-2).reshape(-1,)) self.K = spsp.bmat([[oc.m*oc.sigma_xz-oc.L, oc.minus_Dx, oc.minus_Dz], [oc.minus_sigma_zMx_Dx, oc.sigmax, oc.empty], [oc.minus_sigma_xMz_Dz, oc.empty, oc.sigmaz]]) self.C = spsp.bmat([[oc.m*oc.sigma_xPz, oc.empty, oc.empty], [oc.empty, oc.I, oc.empty], [oc.empty, oc.empty, oc.I]]) self.M = spsp.bmat([[oc.m, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty], [oc.empty, oc.empty, oc.empty]]) self.dK = oc.sigma_xz self.dC = oc.sigma_xPz self.dM = oc.I