def aveF2CC(self): "Construct the averaging operator on cell faces to cell centers." if getattr(self, '_aveF2CC', None) is None: n = self.vnC if self.isSymmetric: avR = Utils.av(n[0])[:, 1:] avR[0, 0] = 1. self._aveF2CC = ((0.5)*sp.hstack((sp.kron(Utils.speye(n[2]), avR), sp.kron(Utils.av(n[2]), Utils.speye(n[0]))), format="csr")) else: raise NotImplementedError('wrapping in the averaging is not ' 'yet implemented') # self._aveF2CC = (1./3.)*sp.hstack((Utils.kron3(Utils.speye(n[2]), # Utils.speye(n[1]), # Utils.av(n[0])), # Utils.kron3(Utils.speye(n[2]), # Utils.av(n[1]), # Utils.speye(n[0])), # Utils.kron3(Utils.av(n[2]), # Utils.speye(n[1]), # Utils.speye(n[0]))), # format="csr") return self._aveF2CC
def W(self): """Regularization matrix W""" if getattr(self, '_W', None) is None: ntx = self.xyz_line.shape[0] meshline = Mesh.TensorMesh([ntx]) Gx = meshline.cellGradx Wx = np.sqrt(self.alpha_x) * sp.kron(Gx, Utils.speye(self.ntau)) Ws = np.sqrt(self.alpha_s) * Utils.speye(self.ntau * ntx) wlist = (Wx, Ws) self._W = sp.vstack(wlist) return self._W
def faceDivz(self): """ Construct divergence operator in the z component (face-stg to cell-centres). """ if getattr(self, "_faceDivz", None) is None: D3 = Utils.kron3(Utils.ddx(self.nCz), Utils.speye(self.nCy), Utils.speye(self.nCx)) S = self.r(self.area, "F", "Fz", "V") V = self.vol self._faceDivz = Utils.sdiag(1 / V) * D3 * Utils.sdiag(S) return self._faceDivz
def faceDivz(self): """ Construct divergence operator in the z component (face-stg to cell-centres). """ if getattr(self, '_faceDivz', None) is None: D3 = Utils.kron3(Utils.ddx(self.nCz), Utils.speye(self.nCy), Utils.speye(self.nCx)) S = self.r(self.area, 'F', 'Fz', 'V') V = self.vol self._faceDivz = Utils.sdiag(1/V)*D3*Utils.sdiag(S) return self._faceDivz
def aveF2CCV(self): "Construct the averaging operator on cell faces to cell centers." if getattr(self, "_aveF2CCV", None) is None: n = self.vnC if self.isSymmetric: avR = Utils.av(n[0])[:, 1:] avR[0, 0] = 1.0 self._aveF2CCV = sp.block_diag( (sp.kron(Utils.speye(n[2]), avR), sp.kron(Utils.av(n[2]), Utils.speye(n[0]))), format="csr" ) else: raise NotImplementedError("wrapping in the averaging is not " "yet implemented") return self._aveF2CCV
def faceDivy(self): """ Construct divergence operator in the y component (face-stg to cell-centres). """ raise NotImplementedError("Wrapping the Utils.ddx is not yet " "implemented.") if getattr(self, "_faceDivy", None) is None: # TODO: this needs to wrap to join up faces which are # connected in the cylinder D2 = Utils.kron3(Utils.speye(self.nCz), Utils.ddx(self.nCy), Utils.speye(self.nCx)) S = self.r(self.area, "F", "Fy", "V") V = self.vol self._faceDivy = Utils.sdiag(1 / V) * D2 * Utils.sdiag(S) return self._faceDivy
def get_grad_horizontal(self, xy, hz): """ Compute Gradient in horizontal direction using Delaunay """ tri = sp.spatial.Delaunay(xy) # Split the triangulation into connections edges = np.r_[tri.simplices[:, :2], tri.simplices[:, 1:], tri.simplices[:, [0, 2]]] # Sort and keep uniques edges = np.sort(edges, axis=1) edges = np.unique(edges[np.argsort(edges[:, 0]), :], axis=0) # Create 2D operator, dimensionless for now nN = edges.shape[0] nStn = xy.shape[0] stn, count = np.unique(edges[:, 0], return_counts=True) col = [] row = [] dm = [] avg = [] for ii in range(nN): row += [ii] * 2 col += [edges[ii, 0], edges[ii, 1]] scale = count[stn == edges[ii, 0]][0] dm += [-1., 1.] avg += [0.5, 0.5] D = sp.sparse.csr_matrix((dm, (row, col)), shape=(nN, nStn)) A = sp.sparse.csr_matrix((avg, (row, col)), shape=(nN, nStn)) # Kron vertically for nCz Grad = sp.sparse.kron(D, Utils.speye(hz.size)) Avg = sp.sparse.kron(A, Utils.speye(hz.size)) # Override the gradient operator in y-drection # This is because of ordering ... See def get_2d_mesh # y first then x self.regmesh._cellDiffyStencil = self.regmesh.cellDiffxStencil.copy() # Override the gradient operator in x-drection self.regmesh._cellDiffxStencil = Grad # Do the same for the averaging operator self.regmesh._aveCC2Fy = self.regmesh.aveCC2Fx.copy() self.regmesh._aveCC2Fx = Avg self.regmesh._aveFy2CC = self.regmesh.aveFx2CC.copy() self.regmesh._aveFx2CC = Avg.T return tri
def aveF2CCV(self): "Construct the averaging operator on cell faces to cell centers." if getattr(self, '_aveF2CCV', None) is None: n = self.vnC if self.isSymmetric: avR = Utils.av(n[0])[:, 1:] avR[0, 0] = 1. self._aveF2CCV = sp.block_diag( (sp.kron(Utils.speye(n[2]), avR), sp.kron(Utils.av(n[2]), Utils.speye(n[0]))), format="csr") else: raise NotImplementedError('wrapping in the averaging is not ' 'yet implemented') return self._aveF2CCV
def faceDivy(self): """ Construct divergence operator in the y component (face-stg to cell-centres). """ raise NotImplementedError('Wrapping the Utils.ddx is not yet ' 'implemented.') if getattr(self, '_faceDivy', None) is None: # TODO: this needs to wrap to join up faces which are # connected in the cylinder D2 = Utils.kron3(Utils.speye(self.nCz), Utils.ddx(self.nCy), Utils.speye(self.nCx)) S = self.r(self.area, 'F', 'Fy', 'V') V = self.vol self._faceDivy = Utils.sdiag(1/V)*D2*Utils.sdiag(S) return self._faceDivy
def Pac(self): """ diagonal matrix that nulls out inactive cells :rtype: scipy.sparse.csr_matrix :return: active cell diagonal matrix """ if getattr(self, "_Pac", None) is None: if self.indActive is None: self._Pac = Utils.speye(self.mesh.nC) else: e = np.zeros(self.mesh.nC) e[self.indActive] = 1.0 # self._Pac = Utils.speye(self.mesh.nC)[:, self.indActive] self._Pac = Utils.sdiag(e) return self._Pac
def Pafy(self): """ diagonal matrix that nulls out inactive y-faces to full modelling space (ie. nFy x nindActive_Fy ) :rtype: scipy.sparse.csr_matrix :return: active face-y diagonal matrix """ if getattr(self, '_Pafy', None) is None: if self.indActive is None: self._Pafy = Utils.speye(self.mesh.nFy) else: indActive_Fy = (self.mesh.aveFy2CC.T * self.indActive) >= 1 e = np.zeros(self.mesh.nFy) e[indActive_Fy] = 1. self._Pafy = Utils.sdiag(e) return self._Pafy
def Pafz(self): """ diagonal matrix that nulls out inactive z-faces to full modelling space (ie. nFz x nindActive_Fz ) :rtype: scipy.sparse.csr_matrix :return: active face-z diagonal matrix """ if getattr(self, "_Pafz", None) is None: if self.indActive is None: self._Pafz = Utils.speye(self.mesh.nFz) else: indActive_Fz = (self.mesh.aveFz2CC.T * self.indActive) >= 1 e = np.zeros(self.mesh.nFz) e[indActive_Fz] = 1.0 self._Pafz = Utils.sdiag(e) return self._Pafz
def Pafx(self): """ diagonal matrix that nulls out inactive x-faces to full modelling space (ie. nFx x nindActive_Fx ) :rtype: scipy.sparse.csr_matrix :return: active face-x diagonal matrix """ if getattr(self, "_Pafx", None) is None: if self.indActive is None: self._Pafx = Utils.speye(self.mesh.nFx) else: indActive_Fx = self.mesh.aveFx2CC.T * self.indActive >= 1 e = np.zeros(self.mesh.nFx) e[indActive_Fx] = 1.0 self._Pafx = Utils.sdiag(e) return self._Pafx
def getJtJdiag(self, m, W=None, threshold=1e-8): """ Compute diagonal component of JtJ or trace of sensitivity matrix (J) """ J_sigma = self.getJ_sigma(m) J_matrix = J_sigma*(Utils.sdiag(1./self.sigma)*(self.sigmaDeriv)) if self.hMap is not None: J_height = self.getJ_height(m) J_matrix += J_height*self.hDeriv if W is None: W = Utils.speye(J_matrix.shape[0]) J_matrix = W*J_matrix JtJ_diag = (J_matrix.T*J_matrix).diagonal() JtJ_diag /= JtJ_diag.max() JtJ_diag += threshold return JtJ_diag
def getAdiag(self, tInd): """ System matrix at a given time index .. math:: (\mathbf{I} + \mathbf{dt} \mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f}) """ assert tInd >= 0 and tInd < self.nT dt = self.timeSteps[tInd] C = self.mesh.edgeCurl MeSigmaI = self.MeSigmaI MfMui = self.MfMui I = Utils.speye(self.mesh.nF) A = 1./dt * I + ( C * ( MeSigmaI * (C.T * MfMui ) ) ) if self._makeASymmetric is True: return MfMui.T * A return A
def getAdiag(self, tInd): """ System matrix at a given time index .. math:: (\mathbf{I} + \mathbf{dt} \mathbf{C} \mathbf{M_{\sigma}^e}^{-1} \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f}) """ assert tInd >= 0 and tInd < self.nT dt = self.timeSteps[tInd] C = self.mesh.edgeCurl MeSigmaI = self.MeSigmaI MfMui = self.MfMui I = Utils.speye(self.mesh.nF) A = 1. / dt * I + (C * (MeSigmaI * (C.T * MfMui))) if self._makeASymmetric is True: return MfMui.T * A return A
def run(plotIt=True, n=60): """ Mesh: Operators: Cahn Hilliard ============================== This example is based on the example in the FiPy_ library. Please see their documentation for more information about the Cahn-Hilliard equation. The "Cahn-Hilliard" equation separates a field \\\\( \\\\phi \\\\) into 0 and 1 with smooth transitions. .. math:: \\frac{\partial \phi}{\partial t} = \\nabla \cdot D \\nabla \left( \\frac{\partial f}{\partial \phi} - \epsilon^2 \\nabla^2 \phi \\right) Where \\\\( f \\\\) is the energy function \\\\( f = ( a^2 / 2 )\\\\phi^2(1 - \\\\phi)^2 \\\\) which drives \\\\( \\\\phi \\\\) towards either 0 or 1, this competes with the term \\\\(\\\\epsilon^2 \\\\nabla^2 \\\\phi \\\\) which is a diffusion term that creates smooth changes in \\\\( \\\\phi \\\\). The equation can be factored: .. math:: \\frac{\partial \phi}{\partial t} = \\nabla \cdot D \\nabla \psi \\\\ \psi = \\frac{\partial^2 f}{\partial \phi^2} (\phi - \phi^{\\text{old}}) + \\frac{\partial f}{\partial \phi} - \epsilon^2 \\nabla^2 \phi Here we will need the derivatives of \\\\( f \\\\): .. math:: \\frac{\partial f}{\partial \phi} = (a^2/2)2\phi(1-\phi)(1-2\phi) \\frac{\partial^2 f}{\partial \phi^2} = (a^2/2)2[1-6\phi(1-\phi)] The implementation below uses backwards Euler in time with an exponentially increasing time step. The initial \\\\( \\\\phi \\\\) is a normally distributed field with a standard deviation of 0.1 and mean of 0.5. The grid is 60x60 and takes a few seconds to solve ~130 times. The results are seen below, and you can see the field separating as the time increases. .. _FiPy: http://www.ctcms.nist.gov/fipy/examples/cahnHilliard/generated/examples.cahnHilliard.mesh2DCoupled.html """ np.random.seed(5) # Here we are going to rearrange the equations: # (phi_ - phi)/dt = A*(d2fdphi2*(phi_ - phi) + dfdphi - L*phi_) # (phi_ - phi)/dt = A*(d2fdphi2*phi_ - d2fdphi2*phi + dfdphi - L*phi_) # (phi_ - phi)/dt = A*d2fdphi2*phi_ + A*( - d2fdphi2*phi + dfdphi - L*phi_) # phi_ - phi = dt*A*d2fdphi2*phi_ + dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) # phi_ - dt*A*d2fdphi2 * phi_ = dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi # (I - dt*A*d2fdphi2) * phi_ = dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi # (I - dt*A*d2fdphi2) * phi_ = dt*A*dfdphi - dt*A*d2fdphi2*phi - dt*A*L*phi_ + phi # (dt*A*d2fdphi2 - I) * phi_ = dt*A*d2fdphi2*phi + dt*A*L*phi_ - phi - dt*A*dfdphi # (dt*A*d2fdphi2 - I - dt*A*L) * phi_ = (dt*A*d2fdphi2 - I)*phi - dt*A*dfdphi h = [(0.25, n)] M = Mesh.TensorMesh([h, h]) # Constants D = a = epsilon = 1. I = Utils.speye(M.nC) # Operators A = D * M.faceDiv * M.cellGrad L = epsilon**2 * M.faceDiv * M.cellGrad duration = 75 elapsed = 0. dexp = -5 phi = np.random.normal(loc=0.5, scale=0.01, size=M.nC) ii, jj = 0, 0 PHIS = [] capture = np.logspace(-1, np.log10(duration), 8) while elapsed < duration: dt = min(100, np.exp(dexp)) elapsed += dt dexp += 0.05 dfdphi = a**2 * 2 * phi * (1 - phi) * (1 - 2 * phi) d2fdphi2 = Utils.sdiag(a**2 * 2 * (1 - 6 * phi * (1 - phi))) MAT = (dt * A * d2fdphi2 - I - dt * A * L) rhs = (dt * A * d2fdphi2 - I) * phi - dt * A * dfdphi phi = Solver(MAT) * rhs if elapsed > capture[jj]: PHIS += [(elapsed, phi.copy())] jj += 1 if ii % 10 == 0: print(ii, elapsed) ii += 1 if plotIt: fig, axes = plt.subplots(2, 4, figsize=(14, 6)) axes = np.array(axes).flatten().tolist() for ii, ax in zip(np.linspace(0, len(PHIS) - 1, len(axes)), axes): ii = int(ii) M.plotImage(PHIS[ii][1], ax=ax) ax.axis('off') ax.set_title('Elapsed Time: {0:4.1f}'.format(PHIS[ii][0]))
def run(plotIt=True, n=60): np.random.seed(5) # Here we are going to rearrange the equations: # (phi_ - phi)/dt = A*(d2fdphi2*(phi_ - phi) + dfdphi - L*phi_) # (phi_ - phi)/dt = A*(d2fdphi2*phi_ - d2fdphi2*phi + dfdphi - L*phi_) # (phi_ - phi)/dt = A*d2fdphi2*phi_ + A*( - d2fdphi2*phi + dfdphi - L*phi_) # phi_ - phi = dt*A*d2fdphi2*phi_ + dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) # phi_ - dt*A*d2fdphi2 * phi_ = dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi # (I - dt*A*d2fdphi2) * phi_ = dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi # (I - dt*A*d2fdphi2) * phi_ = dt*A*dfdphi - dt*A*d2fdphi2*phi - dt*A*L*phi_ + phi # (dt*A*d2fdphi2 - I) * phi_ = dt*A*d2fdphi2*phi + dt*A*L*phi_ - phi - dt*A*dfdphi # (dt*A*d2fdphi2 - I - dt*A*L) * phi_ = (dt*A*d2fdphi2 - I)*phi - dt*A*dfdphi h = [(0.25, n)] M = Mesh.TensorMesh([h, h]) # Constants D = a = epsilon = 1. I = Utils.speye(M.nC) # Operators A = D * M.faceDiv * M.cellGrad L = epsilon**2 * M.faceDiv * M.cellGrad duration = 75 elapsed = 0. dexp = -5 phi = np.random.normal(loc=0.5, scale=0.01, size=M.nC) ii, jj = 0, 0 PHIS = [] capture = np.logspace(-1, np.log10(duration), 8) while elapsed < duration: dt = min(100, np.exp(dexp)) elapsed += dt dexp += 0.05 dfdphi = a**2 * 2 * phi * (1 - phi) * (1 - 2 * phi) d2fdphi2 = Utils.sdiag(a**2 * 2 * (1 - 6 * phi * (1 - phi))) MAT = (dt*A*d2fdphi2 - I - dt*A*L) rhs = (dt*A*d2fdphi2 - I)*phi - dt*A*dfdphi phi = Solver(MAT)*rhs if elapsed > capture[jj]: PHIS += [(elapsed, phi.copy())] jj += 1 if ii % 10 == 0: print(ii, elapsed) ii += 1 if plotIt: fig, axes = plt.subplots(2, 4, figsize=(14, 6)) axes = np.array(axes).flatten().tolist() for ii, ax in zip(np.linspace(0, len(PHIS)-1, len(axes)), axes): ii = int(ii) M.plotImage(PHIS[ii][1], ax=ax) ax.axis('off') ax.set_title('Elapsed Time: {0:4.1f}'.format(PHIS[ii][0]))
def run(plotIt=True, n=60): np.random.seed(5) # Here we are going to rearrange the equations: # (phi_ - phi)/dt = A*(d2fdphi2*(phi_ - phi) + dfdphi - L*phi_) # (phi_ - phi)/dt = A*(d2fdphi2*phi_ - d2fdphi2*phi + dfdphi - L*phi_) # (phi_ - phi)/dt = A*d2fdphi2*phi_ + A*( - d2fdphi2*phi + dfdphi - L*phi_) # phi_ - phi = dt*A*d2fdphi2*phi_ + dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) # phi_ - dt*A*d2fdphi2 * phi_ = dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi # (I - dt*A*d2fdphi2) * phi_ = dt*A*(- d2fdphi2*phi + dfdphi - L*phi_) + phi # (I - dt*A*d2fdphi2) * phi_ = dt*A*dfdphi - dt*A*d2fdphi2*phi - dt*A*L*phi_ + phi # (dt*A*d2fdphi2 - I) * phi_ = dt*A*d2fdphi2*phi + dt*A*L*phi_ - phi - dt*A*dfdphi # (dt*A*d2fdphi2 - I - dt*A*L) * phi_ = (dt*A*d2fdphi2 - I)*phi - dt*A*dfdphi h = [(0.25, n)] M = Mesh.TensorMesh([h, h]) # Constants D = a = epsilon = 1. I = Utils.speye(M.nC) # Operators A = D * M.faceDiv * M.cellGrad L = epsilon**2 * M.faceDiv * M.cellGrad duration = 75 elapsed = 0. dexp = -5 phi = np.random.normal(loc=0.5, scale=0.01, size=M.nC) ii, jj = 0, 0 PHIS = [] capture = np.logspace(-1, np.log10(duration), 8) while elapsed < duration: dt = min(100, np.exp(dexp)) elapsed += dt dexp += 0.05 dfdphi = a**2 * 2 * phi * (1 - phi) * (1 - 2 * phi) d2fdphi2 = Utils.sdiag(a**2 * 2 * (1 - 6 * phi * (1 - phi))) MAT = (dt * A * d2fdphi2 - I - dt * A * L) rhs = (dt * A * d2fdphi2 - I) * phi - dt * A * dfdphi phi = Solver(MAT) * rhs if elapsed > capture[jj]: PHIS += [(elapsed, phi.copy())] jj += 1 if ii % 10 == 0: print(ii, elapsed) ii += 1 if plotIt: fig, axes = plt.subplots(2, 4, figsize=(14, 6)) axes = np.array(axes).flatten().tolist() for ii, ax in zip(np.linspace(0, len(PHIS) - 1, len(axes)), axes): ii = int(ii) M.plotImage(PHIS[ii][1], ax=ax) ax.axis('off') ax.set_title('Elapsed Time: {0:4.1f}'.format(PHIS[ii][0]))
def get_grad_horizontal( self, xy, hz, dim=3, use_cell_weights=True, minimum_distance=None ): """ Compute Gradient in horizontal direction using Delaunay """ if use_cell_weights: self.cell_weights = np.tile(hz, (xy.shape[0], 1)).flatten() if dim == 3: tri = sp.spatial.Delaunay(xy) # Split the triangulation into connections edges = np.r_[ tri.simplices[:, :2], tri.simplices[:, 1:], tri.simplices[:, [0, 2]] ] # Sort and keep uniques edges = np.sort(edges, axis=1) edges = np.unique( edges[np.argsort(edges[:, 0]), :], axis=0 ) # Compute distance if minimum_distance is not None: dx = xy[edges[:, 0], 0]-xy[edges[:, 1], 0] dy = xy[edges[:, 0], 1]-xy[edges[:, 1], 1] distance = np.sqrt(dx**2+dy**2) inds = distance < minimum_distance edges = edges[inds, :] # Create 2D operator, dimensionless for now nN = edges.shape[0] nStn = xy.shape[0] stn, count = np.unique(edges[:, 0], return_counts=True) col = [] row = [] dm = [] avg = [] for ii in range(nN): row += [ii]*2 col += [edges[ii, 0], edges[ii, 1]] scale = count[stn == edges[ii, 0]][0] dm += [-1., 1.] avg += [0.5, 0.5] D = sp.sparse.csr_matrix((dm, (row, col)), shape=(nN, nStn)) A = sp.sparse.csr_matrix((avg, (row, col)), shape=(nN, nStn)) # Kron vertically for nCz Grad = sp.sparse.kron(D, Utils.speye(hz.size)) Avg = sp.sparse.kron(A, Utils.speye(hz.size)) # Override the gradient operator in y-drection # This is because of ordering ... See def get_2d_mesh # y first then x self.regmesh._cellDiffyStencil = self.regmesh.cellDiffxStencil.copy() # Override the gradient operator in x-drection self.regmesh._cellDiffxStencil = Grad # Do the same for the averaging operator self.regmesh._aveCC2Fy = self.regmesh.aveCC2Fx.copy() self.regmesh._aveCC2Fx = Avg self.regmesh._aveFy2CC = self.regmesh.aveFx2CC.copy() self.regmesh._aveFx2CC = Avg.T return tri elif dim == 2: # Override the gradient operator in y-drection # This is because of ordering ... See def get_2d_mesh # y first then x temp_x = self.regmesh.cellDiffxStencil.copy() temp_y = self.regmesh.cellDiffyStencil.copy() self.regmesh._cellDiffyStencil = temp_x # Override the gradient operator in x-drection self.regmesh._cellDiffxStencil = temp_y # Do the same for the averaging operator temp_x = self.regmesh.aveCC2Fx.copy() temp_y = self.regmesh.aveCC2Fy.copy() self.regmesh._aveCC2Fy = temp_x self.regmesh._aveCC2Fx = temp_y temp_x = self.regmesh.aveCC2Fx.copy() temp_y = self.regmesh.aveCC2Fy.copy() self.regmesh._aveFy2CC = temp_x self.regmesh._aveFx2CC = temp_y return True
vec = np.c_[mx, my, mz] nC = mesh.nC atp = Utils.matutils.xyz2atp(vec) theta = atp[nC:2 * nC] phi = atp[2 * nC:] # theta = np.ones(mesh.nC) * 45 # phi = np.ones(mesh.nC) * 0 indActive = np.zeros(mesh.nC, dtype=bool) indActive[actv] = True print("Building operators") Pac = Utils.speye(mesh.nC)[:, indActive] Dx1 = Regularization.getDiffOpRot(mesh, np.deg2rad(0.), theta, phi, 'X') Dy1 = Regularization.getDiffOpRot(mesh, np.deg2rad(0.), theta, phi, 'Y') Dz1 = Regularization.getDiffOpRot(mesh, np.deg2rad(0.), theta, phi, 'Z') Dx1 = Pac.T * Dx1 * Pac Dy1 = Pac.T * Dy1 * Pac Dz1 = Pac.T * Dz1 * Pac Dx2 = Regularization.getDiffOpRot(mesh, np.deg2rad(0.), theta, phi, 'X', forward=False)
def get_grad_horizontal( self, xy, hz, dim=3, use_cell_weights=True, minimum_distance=None ): """ Compute Gradient in horizontal direction using Delaunay """ self.cell_weights = np.tile(hz, (xy.shape[0], 1)).flatten() if dim == 3: tri = sp.spatial.Delaunay(xy) # Split the triangulation into connections edges = np.r_[ tri.simplices[:, :2], tri.simplices[:, 1:], tri.simplices[:, [0, 2]] ] # Sort and keep uniques edges = np.sort(edges, axis=1) edges = np.unique( edges[np.argsort(edges[:, 0]), :], axis=0 ) # Compute distance if minimum_distance is not None: dx = xy[edges[:, 0], 0]-xy[edges[:, 1], 0] dy = xy[edges[:, 0], 1]-xy[edges[:, 1], 1] distance = np.sqrt(dx**2+dy**2) inds = distance < minimum_distance edges = edges[inds, :] # Create 2D operator, dimensionless for now nN = edges.shape[0] nStn = xy.shape[0] stn, count = np.unique(edges[:, 0], return_counts=True) col = [] row = [] dm = [] avg = [] for ii in range(nN): row += [ii]*2 col += [edges[ii, 0], edges[ii, 1]] scale = count[stn == edges[ii, 0]][0] dm += [-1., 1.] avg += [0.5, 0.5] D = sp.sparse.csr_matrix((dm, (row, col)), shape=(nN, nStn)) A = sp.sparse.csr_matrix((avg, (row, col)), shape=(nN, nStn)) # Kron vertically for nCz Grad = sp.sparse.kron(D, Utils.speye(hz.size)) Avg = sp.sparse.kron(A, Utils.speye(hz.size)) # Override the gradient operator in y-drection # This is because of ordering ... See def get_2d_mesh # y first then x self.regmesh._cellDiffyStencil = self.regmesh.cellDiffxStencil.copy() # Override the gradient operator in x-drection self.regmesh._cellDiffxStencil = Grad # Do the same for the averaging operator self.regmesh._aveCC2Fy = self.regmesh.aveCC2Fx.copy() self.regmesh._aveCC2Fx = Avg self.regmesh._aveFy2CC = self.regmesh.aveFx2CC.copy() self.regmesh._aveFx2CC = Avg.T return tri elif dim == 2: # Override the gradient operator in y-drection # This is because of ordering ... See def get_2d_mesh # y first then x temp_x = self.regmesh.cellDiffxStencil.copy() temp_y = self.regmesh.cellDiffyStencil.copy() self.regmesh._cellDiffyStencil = temp_x # Override the gradient operator in x-drection self.regmesh._cellDiffxStencil = temp_y # Do the same for the averaging operator temp_x = self.regmesh.aveCC2Fx.copy() temp_y = self.regmesh.aveCC2Fy.copy() self.regmesh._aveCC2Fy = temp_x self.regmesh._aveCC2Fx = temp_y temp_x = self.regmesh.aveCC2Fx.copy() temp_y = self.regmesh.aveCC2Fy.copy() self.regmesh._aveFy2CC = temp_x self.regmesh._aveFx2CC = temp_y return True