def getError(self): #Test function phi = lambda x: np.cos(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1]) j_funX = lambda x: -np.pi * np.sin(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1]) j_funY = lambda x: -np.pi * np.cos(np.pi * x[:, 0]) * np.sin(np.pi * x[:, 1]) q_fun = lambda x: -2 * (np.pi**2) * phi(x) xc_ana = phi(self.M.gridCC) q_ana = q_fun(self.M.gridCC) jX_ana = j_funX(self.M.gridFx) jY_ana = j_funY(self.M.gridFy) j_ana = np.r_[jX_ana, jY_ana] #TODO: Check where our boundary conditions are CCx or Nx # fxm,fxp,fym,fyp = self.M.faceBoundaryInd # gBFx = self.M.gridFx[(fxm|fxp),:] # gBFy = self.M.gridFy[(fym|fyp),:] fxm, fxp, fym, fyp = self.M.cellBoundaryInd gBFx = self.M.gridCC[(fxm | fxp), :] gBFy = self.M.gridCC[(fym | fyp), :] bc = phi(np.r_[gBFx, gBFy]) # P = sp.csr_matrix(([-1,1],([0,self.M.nF-1],[0,1])), shape=(self.M.nF, 2)) P, Pin, Pout = self.M.getBCProjWF('dirichlet') Mc = self.M.getFaceInnerProduct() McI = Utils.sdInv(self.M.getFaceInnerProduct()) G = -self.M.faceDiv.T * Utils.sdiag(self.M.vol) D = self.M.faceDiv j = McI * (G * xc_ana + P * bc) q = D * j # self.M.plotImage(j, 'FxFy', showIt=True) # Rearrange if we know q to solve for x A = D * McI * G rhs = q_ana - D * McI * P * bc if self.myTest == 'j': err = np.linalg.norm((j - j_ana), np.inf) elif self.myTest == 'q': err = np.linalg.norm((q - q_ana), np.inf) elif self.myTest == 'xc': xc = Solver(A) * (rhs) err = np.linalg.norm((xc - xc_ana), np.inf) elif self.myTest == 'xcJ': xc = Solver(A) * (rhs) j = McI * (G * xc + P * bc) err = np.linalg.norm((j - j_ana), np.inf) return err
def MagneticsDiffSecondaryInv(mesh, model, data, **kwargs): """ Inversion module for MagneticsDiffSecondary """ from SimPEG import Optimization, Regularization, Parameters, ObjFunction, Inversion prob = MagneticsDiffSecondary(mesh, model) miter = kwargs.get('maxIter', 10) if prob.ispaired: prob.unpair() if data.ispaired: data.unpair() prob.pair(data) # Create an optimization program opt = Optimization.InexactGaussNewton(maxIter=miter) opt.bfgsH0 = Solver(sp.identity(model.nP), flag='D') # Create a regularization program reg = Regularization.Tikhonov(model) # Create an objective function beta = Parameters.BetaSchedule(beta0=1e0) obj = ObjFunction.BaseObjFunction(data, reg, beta=beta) # Create an inversion object inv = Inversion.BaseInversion(obj, opt) return inv, reg
def getError(self): # Test function def phi_fun(x): return np.cos(np.pi * x) def j_fun(x): return np.pi * np.sin(np.pi * x) def phi_deriv(x): return -j_fun(x) def q_fun(x): return (np.pi**2) * np.cos(np.pi * x) xc_ana = phi_fun(self.M.gridCC) q_ana = q_fun(self.M.gridCC) j_ana = j_fun(self.M.gridFx) # Get boundary locations vecN = self.M.vectorNx vecC = self.M.vectorCCx # Setup Mixed B.C (alpha, beta, gamma) alpha_xm, alpha_xp = 1., 1. beta_xm, beta_xp = 1., 1. alpha = np.r_[alpha_xm, alpha_xp] beta = np.r_[beta_xm, beta_xp] vecN = self.M.vectorNx vecC = self.M.vectorCCx phi_bc = phi_fun(vecN[[0, -1]]) phi_deriv_bc = phi_deriv(vecN[[0, -1]]) gamma = alpha * phi_bc + beta * phi_deriv_bc x_BC, y_BC = getxBCyBC_CC(self.M, alpha, beta, gamma) sigma = np.ones(self.M.nC) Mfrho = self.M.getFaceInnerProduct(1. / sigma) MfrhoI = self.M.getFaceInnerProduct(1. / sigma, invMat=True) V = Utils.sdiag(self.M.vol) Div = V * self.M.faceDiv P_BC, B = self.M.getBCProjWF_simple() q = q_fun(self.M.gridCC) M = B * self.M.aveCC2F G = Div.T - P_BC * Utils.sdiag(y_BC) * M # Mrhoj = D.T V phi + P_BC*Utils.sdiag(y_BC)*M phi - P_BC*x_BC rhs = V * q + Div * MfrhoI * P_BC * x_BC A = Div * MfrhoI * G if self.myTest == 'xc': # TODO: fix the null space Ainv = Solver(A) xc = Ainv * rhs err = np.linalg.norm((xc - xc_ana), np.inf) else: NotImplementedError return err
def getError(self): #Test function phi = lambda x: np.cos(np.pi * x) j_fun = lambda x: -np.pi * np.sin(np.pi * x) q_fun = lambda x: -(np.pi**2) * np.cos(np.pi * x) xc_ana = phi(self.M.gridCC) q_ana = q_fun(self.M.gridCC) j_ana = j_fun(self.M.gridFx) #TODO: Check where our boundary conditions are CCx or Nx # vec = self.M.vectorNx vec = self.M.vectorCCx phi_bc = phi(vec[[0, -1]]) j_bc = j_fun(vec[[0, -1]]) P, Pin, Pout = self.M.getBCProjWF([['dirichlet', 'dirichlet']]) Mc = self.M.getFaceInnerProduct() McI = Utils.sdInv(self.M.getFaceInnerProduct()) V = Utils.sdiag(self.M.vol) G = -Pin.T * Pin * self.M.faceDiv.T * V D = self.M.faceDiv j = McI * (G * xc_ana + P * phi_bc) q = V * D * Pin.T * Pin * j + V * D * Pout.T * j_bc # Rearrange if we know q to solve for x A = V * D * Pin.T * Pin * McI * G rhs = V * q_ana - V * D * Pin.T * Pin * McI * P * phi_bc - V * D * Pout.T * j_bc # A = D*McI*G # rhs = q_ana - D*McI*P*phi_bc if self.myTest == 'j': err = np.linalg.norm((j - j_ana), np.inf) elif self.myTest == 'q': err = np.linalg.norm((q - V * q_ana), np.inf) elif self.myTest == 'xc': #TODO: fix the null space solver = SolverCG(A, maxiter=1000) xc = solver * (rhs) print 'ACCURACY', np.linalg.norm(Utils.mkvc(A * xc) - rhs) err = np.linalg.norm((xc - xc_ana), np.inf) elif self.myTest == 'xcJ': #TODO: fix the null space xc = Solver(A) * (rhs) print np.linalg.norm(Utils.mkvc(A * xc) - rhs) j = McI * (G * xc + P * phi_bc) err = np.linalg.norm((j - j_ana), np.inf) return err
def getError(self): # Create some functions to integrate fun = lambda x: np.sin(2 * np.pi * x[:, 0]) * np.sin( 2 * np.pi * x[:, 1]) * np.sin(2 * np.pi * x[:, 2]) sol = lambda x: -3. * ((2 * np.pi)**2) * fun(x) self.M.setCellGradBC('dirichlet') D = self.M.faceDiv G = self.M.cellGrad if self.forward: sA = sol(self.M.gridCC) sN = D * G * fun(self.M.gridCC) err = np.linalg.norm((sA - sN), np.inf) else: fA = fun(self.M.gridCC) fN = Solver(D * G) * (sol(self.M.gridCC)) err = np.linalg.norm((fA - fN), np.inf) return err
def MagneticsDiffSecondaryInv(mesh, model, data, **kwargs): """ Inversion module for MagneticsDiffSecondary """ from SimPEG import Optimization, Regularization, Parameters, ObjFunction, Inversion prob = Simulation3DDifferential(mesh, survey=data, mu=model) miter = kwargs.get("maxIter", 10) # Create an optimization program opt = Optimization.InexactGaussNewton(maxIter=miter) opt.bfgsH0 = Solver(sp.identity(model.nP), flag="D") # Create a regularization program reg = Regularization.Tikhonov(model) # Create an objective function beta = Parameters.BetaSchedule(beta0=1e0) obj = ObjFunction.BaseObjFunction(prob, reg, beta=beta) # Create an inversion object inv = Inversion.BaseInversion(obj, opt) return inv, reg
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 simulateMT(mesh, sigma, frequency, rtype="app_res"): """ Compute apparent resistivity and phase at each frequency. Return apparent resistivity and phase for rtype="app_res", or impedance for rtype="impedance" """ # Angular frequency (rad/s) def omega(freq): return 2*np.pi*freq # make sure we are working with numpy arrays if type(frequency) is float: frequency = np.r_[frequency] # make it a list to loop over later if it is just a scalar elif type(frequency) is list: frequency = np.array(frequency) # Grad mesh.setCellGradBC([['dirichlet', 'dirichlet']]) # Setup boundary conditions Grad = mesh.cellGrad # Gradient matrix # MfMu mu = np.ones(mesh.nC)*mu_0 # magnetic permeability values for all cells Mmu = Utils.sdiag(mesh.aveCC2F * mu) # Mccsigma sigmahat = sigma # quasi-static assumption Msighat = Utils.sdiag(sigmahat) # Div Div = mesh.faceDiv # Divergence matrix # Right Hand Side B = mesh.cellGradBC # a matrix for boundary conditions Exbc = np.r_[0., 1.] # boundary values for Ex # Right-hand side rhs = np.r_[ -B*Exbc, np.zeros(mesh.nC) ] # loop over frequencies Zxy = [] for freq in frequency: # A-matrix A = sp.vstack([ sp.hstack([Grad, 1j*omega(freq)*Mmu]), # Top row of A matrix sp.hstack((Msighat, Div)) # Bottom row of A matrix ]) Ainv = Solver(A) # Factorize A matrix sol = Ainv*rhs # Solve A^-1 rhs = sol Ex = sol[:mesh.nC] # Extract Ex from solution vector u Hy = sol[mesh.nC:mesh.nC+mesh.nN] # Extract Hy from solution vector u Zxy.append(- 1./Hy[-1]) # Impedance at the surface # turn it into an array Zxy = np.array(Zxy) if rtype.lower() == "impedance": return Zxy elif rtype.lower() == "app_res": app_res = abs(Zxy)**2 / (mu_0*omega(frequency)) app_phase = np.rad2deg(np.arctan(Zxy.imag / Zxy.real)) return app_res, app_phase else: raise Exception("rtype must be 'impedance' or 'app_res', not {}".format(rtype.lower()))
def dc_resistivity( log_sigma_background=1., # Conductivity of the background, S/m log_sigma_block=2, # Conductivity of the block, S/m plot_type='potential' # "conductivity", "potential", or "current" ): from pylab import rcParams rcParams['figure.figsize'] = 10, 10 # Define a unit-cell mesh mesh = Mesh.TensorMesh([100, 100]) # setup a mesh on which to solve # model parameters sigma_background = 10**log_sigma_background sigma_block = 10**log_sigma_block # add a block to our model x_block = np.r_[0.4, 0.6] y_block = np.r_[0.4, 0.6] # assign them on the mesh # create a physical property model sigma = sigma_background * np.ones(mesh.nC) block_indices = ((mesh.gridCC[:, 0] >= x_block[0]) & # left boundary (mesh.gridCC[:, 0] <= x_block[1]) & # right boundary (mesh.gridCC[:, 1] >= y_block[0]) & # bottom boundary (mesh.gridCC[:, 1] <= y_block[1])) # top boundary # add the block to the physical property model sigma[block_indices] = sigma_block # Define a source a_loc, b_loc = np.r_[0.2, 0.5], np.r_[0.8, 0.5] source_locs = [a_loc, b_loc] # locate it on the mesh source_loc_inds = Utils.closestPoints(mesh, source_locs) a_loc_mesh = mesh.gridCC[source_loc_inds[0], :] b_loc_mesh = mesh.gridCC[source_loc_inds[1], :] if plot_type == 'conductivity': plt.colorbar(mesh.plotImage(sigma)[0]) plt.plot(a_loc_mesh[0], a_loc_mesh[1], 'wv', markersize=8) plt.plot(b_loc_mesh[0], b_loc_mesh[1], 'w^', markersize=8) plt.title('electrical conductivity, $\sigma$') return # Assemble and solve the DC resistivity problem Div = mesh.faceDiv Sigma = mesh.getFaceInnerProduct(sigma, invProp=True, invMat=True) Vol = Utils.sdiag(mesh.vol) # assemble the system matrix A = Vol * Div * Sigma * Div.T * Vol # right hand side q = np.zeros(mesh.nC) q[source_loc_inds] = np.r_[+1, -1] # solve the DC resistivity problem Ainv = Solver(A) # create a matrix that behaves like A inverse phi = Ainv * q if plot_type == 'potential': plt.colorbar(mesh.plotImage(phi)[0]) plt.title('Electric Potential, $\phi$') return if plot_type == 'current': j = Sigma * mesh.faceDiv.T * Utils.sdiag(mesh.vol) * phi plt.colorbar( mesh.plotImage(j, vType='F', view='vec', streamOpts={'color': 'w'})[0]) plt.title('Current, $j$') return
if showIt: plt.show() return [scalarMap] if __name__ == '__main__': import numpy as np from SimPEG import Mesh, Utils, Solver hx = [(5, 2, -1.3), (2, 4), (5, 2, 1.3)] hy = [(2, 2, -1.3), (2, 6), (2, 2, 1.3)] hz = [(2, 2, -1.3), (2, 6), (2, 2, 1.3)] M = Mesh.TensorMesh([hx, hy, hz], x0=[10, 20, 14]) q = np.zeros(M.vnC) q[[4, 4], [4, 4], [2, 6]] = [-1, 1] q = Utils.mkvc(q) A = M.faceDiv * M.cellGrad b = Solver(A) * (q) M.plotSlice(M.cellGrad * b, 'F', view='vec', grid=True, pcolorOpts={'alpha': 0.8}) M2 = Mesh.TensorMesh([10, 20], x0=[10, 5]) f = np.r_[np.sin(M2.gridFx[:, 0] * 2 * np.pi), np.sin(M2.gridFy[:, 1] * 2 * np.pi)] M2.plotImage(f, 'F', view='vec', grid=True, pcolorOpts={'alpha': 0.8}) M2.plotImage(f, 'Fx') f = np.r_[np.sin(M2.gridEx[:, 0] * 2 * np.pi), np.sin(M2.gridEy[:, 1] * 2 * np.pi)] M2.plotImage(f, 'E', view='vec', grid=True, pcolorOpts={'alpha': 0.8})
def getError(self): # Test function def phi_fun(x): return (np.cos(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1]) * np.cos(np.pi * x[:, 2])) def j_funX(x): return (np.pi * np.sin(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1]) * np.cos(np.pi * x[:, 2])) def j_funY(x): return (np.pi * np.cos(np.pi * x[:, 0]) * np.sin(np.pi * x[:, 1]) * np.cos(np.pi * x[:, 2])) def j_funZ(x): return (np.pi * np.cos(np.pi * x[:, 0]) * np.cos(np.pi * x[:, 1]) * np.sin(np.pi * x[:, 2])) def phideriv_funX(x): return -j_funX(x) def phideriv_funY(x): return -j_funY(x) def phideriv_funZ(x): return -j_funZ(x) def q_fun(x): return 3 * (np.pi**2) * phi_fun(x) xc_ana = phi_fun(self.M.gridCC) q_ana = q_fun(self.M.gridCC) jX_ana = j_funX(self.M.gridFx) jY_ana = j_funY(self.M.gridFy) j_ana = np.r_[jX_ana, jY_ana, jY_ana] # Get boundary locations fxm, fxp, fym, fyp, fzm, fzp = self.M.faceBoundaryInd gBFxm = self.M.gridFx[fxm, :] gBFxp = self.M.gridFx[fxp, :] gBFym = self.M.gridFy[fym, :] gBFyp = self.M.gridFy[fyp, :] gBFzm = self.M.gridFz[fzm, :] gBFzp = self.M.gridFz[fzp, :] # Setup Mixed B.C (alpha, beta, gamma) alpha_xm = np.ones_like(gBFxm[:, 0]) alpha_xp = np.ones_like(gBFxp[:, 0]) beta_xm = np.ones_like(gBFxm[:, 0]) beta_xp = np.ones_like(gBFxp[:, 0]) alpha_ym = np.ones_like(gBFym[:, 1]) alpha_yp = np.ones_like(gBFyp[:, 1]) beta_ym = np.ones_like(gBFym[:, 1]) beta_yp = np.ones_like(gBFyp[:, 1]) alpha_zm = np.ones_like(gBFzm[:, 2]) alpha_zp = np.ones_like(gBFzp[:, 2]) beta_zm = np.ones_like(gBFzm[:, 2]) beta_zp = np.ones_like(gBFzp[:, 2]) phi_bc_xm, phi_bc_xp = phi_fun(gBFxm), phi_fun(gBFxp) phi_bc_ym, phi_bc_yp = phi_fun(gBFym), phi_fun(gBFyp) phi_bc_zm, phi_bc_zp = phi_fun(gBFzm), phi_fun(gBFzp) phiderivX_bc_xm = phideriv_funX(gBFxm) phiderivX_bc_xp = phideriv_funX(gBFxp) phiderivY_bc_ym = phideriv_funY(gBFym) phiderivY_bc_yp = phideriv_funY(gBFyp) phiderivY_bc_zm = phideriv_funZ(gBFzm) phiderivY_bc_zp = phideriv_funZ(gBFzp) def gamma_fun(alpha, beta, phi, phi_deriv): return alpha * phi + beta * phi_deriv gamma_xm = gamma_fun(alpha_xm, beta_xm, phi_bc_xm, phiderivX_bc_xm) gamma_xp = gamma_fun(alpha_xp, beta_xp, phi_bc_xp, phiderivX_bc_xp) gamma_ym = gamma_fun(alpha_ym, beta_ym, phi_bc_ym, phiderivY_bc_ym) gamma_yp = gamma_fun(alpha_yp, beta_yp, phi_bc_yp, phiderivY_bc_yp) gamma_zm = gamma_fun(alpha_zm, beta_zm, phi_bc_zm, phiderivY_bc_zm) gamma_zp = gamma_fun(alpha_zp, beta_zp, phi_bc_zp, phiderivY_bc_zp) alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp] beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp] gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp] x_BC, y_BC = getxBCyBC_CC(self.M, alpha, beta, gamma) sigma = np.ones(self.M.nC) Mfrho = self.M.getFaceInnerProduct(1. / sigma) MfrhoI = self.M.getFaceInnerProduct(1. / sigma, invMat=True) V = Utils.sdiag(self.M.vol) Div = V * self.M.faceDiv P_BC, B = self.M.getBCProjWF_simple() q = q_fun(self.M.gridCC) M = B * self.M.aveCC2F G = Div.T - P_BC * Utils.sdiag(y_BC) * M rhs = V * q + Div * MfrhoI * P_BC * x_BC A = Div * MfrhoI * G if self.myTest == 'xc': # TODO: fix the null space Ainv = Solver(A) xc = Ainv * rhs err = np.linalg.norm((xc - xc_ana), np.inf) else: NotImplementedError return err
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): """ 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]))