In [2]:
from SimPEG import *
import scipy.sparse as sp
%pylab inline
Here we test inhomogeneous boundary conditions with Finite volume approach.
$$\nabla \phi = \frac{1}{\mu}\mathbf{B}$$$$\nabla \cdot \mathbf{B} = q $$In discretized form we have
$$\mathbf{M}^f\mathbf{G} \phi = \mathbf{M}^f_{\frac{1}{\mu}}\mathbf{B}$$$$\mathbf{D}\mathbf{M}^f\mathbf{B} = \mathbf{M}^cq $$$$\mathbf{D}\mathbf{M}^f(\mathbf{M}^f_{\frac{1}{\mu}})^{-1}\mathbf{M}^f\mathbf{G} \phi = \mathbf{M}^c q $$
In [3]:
n = 100
hx = np.ones(n)*pi/n
M = Mesh.TensorMesh([hx])
Phia = lambda x: -np.cos(x)
Ba = lambda x: np.sin(x)
qa = lambda x: np.cos(x)
M.setCellGradBC('dirichlet')
G = M.cellGrad
D = M.faceDiv
Bbc = M.cellGradBC
Mf = M.getFaceMass()
In [4]:
A = D*G
xsol = sp.linalg.minres(A, qa(M.gridCC)-D*Bbc*np.array([-1., 1.]))
q = A*Phia(M.gridCC)
In [5]:
plt.subplot(131)
plt.plot(M.gridCC, xsol[0], M.gridCC, Phia(M.gridCC), 'r.')
plt.subplot(132)
plt.plot(M.gridCC, qa(M.gridCC)+D*Bbc*np.array([1., -1.]), M.gridCC, q ,'r.')
plt.subplot(133)
plt.plot(M.gridN, G*xsol[0], 'b--', M.gridN, Ba(M.gridN), 'r-')
Out[5]:
In [6]:
n = 20
hx = np.ones(n)*pi/n
M = Mesh.TensorMesh([hx])
Phia = lambda x: np.sin(x)
Ba = lambda x: np.cos(x)
qa = lambda x: -np.sin(x)
M.setCellGradBC('neumann')
G = M.cellGrad
D = M.faceDiv
Mf = M.getFaceMass()
In [7]:
h = pi/n
bc = np.zeros(n)
bc[0] = -1.
bc[n-1] = -1.
bc = bc/h
A = -D*D.T
In [8]:
rhs = qa(M.gridCC)-bc
xsol = sp.linalg.minres(A, rhs)
q = A*Phia(M.gridCC)
In [9]:
figsize(12, 5)
plt.subplot(131)
plt.plot(M.gridCC, xsol[0], M.gridCC, Phia(M.gridCC), 'r.')
plt.subplot(132)
plt.plot(M.gridCC, rhs, 'b.', M.gridCC, q, 'r.')
plt.subplot(133)
plt.plot(M.gridN, G*xsol[0], 'b--', M.gridN, Ba(M.gridN), 'r-')
Out[9]:
Idea for implementing boundary condition for flux is
$$ \mathbf{D}\mathbf{B} = q $$$$ \mathbf{D}\mathbf{B}_{inner}+\mathbf{D}\mathbf{P}\mathbf{B}_{bc} = q $$Here we need to use G for homogenous neuman case and $\mathbf{P}$ is a projection to boundary. Now, to make it work :), we need to generate
In [10]:
from SimPEG import *
from test_boundary import ddxFaceDivBC, faceDivBC, faceBCind
%pylab inline
In [11]:
hxind = ((5,25,1.3),(20, 25),(5,25,1.3))
hx = Utils.meshTensors(hxind)
hx = hx/sum(hx)*np.pi
# hx = np.ones(n)*np.pi/n
M3 = Mesh.TensorMesh([hx, hx, hx])
M3.setCellGradBC('neumann')
G = M3.cellGrad
Bbc = M3.cellGradBC
D = M3.faceDiv
BC = [['neumann', 'neumann'], ['neumann', 'neumann'], ['neumann', 'neumann']]
In [12]:
Bbc.shape
Out[12]:
So, the number of boundary faces elements is 600 (100$\times$6)
In [13]:
print M3.gridFx.shape
print M3.gridFy.shape
print M3.gridFz.shape
print M3.nF
In [14]:
indxd, indxu, indyd, indyu, indzd, indzu = faceBCind(M3)
ind = np.r_[(indxd | indxu), (indyd | indyu), (indzd | indzu)]
In [15]:
Dbc = faceDivBC(M3, BC, ind)
In [16]:
figsize(16,4)
M3.plotImage(ind, imageType='F')
In [17]:
figsize(6,6)
M3.plotGrid()
In discrete form
$$ \mathbf{G} \mathbf{M}^c\phi + \mathbf{G}_{bc}\phi_{bc}= \mathbf{M}^f_{\frac{1}{\mu}}\mathbf{B}_{inner}$$$$ \mathbf{B}_{inner} = (\mathbf{M}^f_{\frac{1}{\mu}})^{-1}(\mathbf{G} \mathbf{M}^c\phi + \mathbf{G}_{bc}\phi_{bc})$$$$ \mathbf{M}^c\mathbf{D}\mathbf{B}_{inner}+\mathbf{M}^c\mathbf{D}_{bc}\mathbf{B}_{bc} = \mathbf{M}^cq $$$$ \mathbf{M}^c\mathbf{D}(\mathbf{M}^f_{\frac{1}{\mu}})^{-1}(\mathbf{G} \mathbf{M}^c\phi +\mathbf{G}_{bc}\phi_{bc})+\mathbf{M}^c\mathbf{D}_{bc}\mathbf{B}_{bc} = \mathbf{M}^cq $$$$ \mathbf{M}^c\mathbf{D}(\mathbf{M}^f_{\frac{1}{\mu}})^{-1}\mathbf{G} \mathbf{M}^c\phi = \mathbf{M}^cq -\mathbf{M}^c\mathbf{D}(\mathbf{M}^f_{\frac{1}{\mu}})^{-1}\mathbf{G}_{bc}\phi_{bc}-\mathbf{M}^c\mathbf{D}_{bc}\mathbf{B}_{bc}$$Since $\mathbf{G}_{bc}$ is going to be zero matrix in this case, we have
$$ \mathbf{M}^c\mathbf{D}(\mathbf{M}^f_{\frac{1}{\mu}})^{-1}\mathbf{G} \mathbf{M}^c\phi = \mathbf{M}^cq -\mathbf{M}^c\mathbf{D}_{bc}\mathbf{B}_{bc}$$And by assuming uniform mesh and constant $\mu$
$$ \mathbf{D}\mathbf{G}\phi = q - \mathbf{D}_{bc}\mathbf{B}_{bc}$$
In [18]:
def phitrue(x,y,z):
phi = np.sin(x)-np.cos(y)+np.cos(z)
return phi
def Btrue(x,y,z):
Bx = np.cos(x)
By = np.sin(y)
Bz = np.sin(z)
B = np.r_[Bx, By, Bz]
return B
def qtrue(x,y,z):
q = -np.sin(x)+np.cos(y)+np.cos(z)
return q
In [19]:
# def phitrue(x,y,z):
# phi = np.sin(x)+np.sin(y)+np.sin(z)
# return phi
# def Btrue(x,y,z):
# Bx = np.cos(x)
# By = np.cos(y)
# Bz = np.cos(z)
# B = np.r_[Bx, By, Bz]
# return B
# def qtrue(x,y,z):
# q = -np.sin(x)-np.sin(y)-np.sin(z)
# return q
In [20]:
Mc = Utils.sdiag(M3.vol)
Mfmu = Utils.sdiag(1/M3.getFaceMass().diagonal())
# A = Mc*D*Mfmu*G*Mc
A = D*G
In [21]:
qa = qtrue(M3.gridCC[:,0], M3.gridCC[:,1], M3.gridCC[:,2])
Ba = Btrue(M3.gridFx[:,0], M3.gridFy[:,1], M3.gridFz[:,2])
Phia = phitrue(M3.gridCC[:,0], M3.gridCC[:,1], M3.gridCC[:,2])
In [22]:
# M3.plotImage(Ba, imageType='F')
# M3.plotImage(qa, imageType='CC')
In [23]:
Bbcx = np.zeros(np.prod(M3.nFz))
Bbcy = np.zeros(np.prod(M3.nFz))
Bbcz = np.zeros(np.prod(M3.nFz))
In [24]:
# Bbcx[indxd] = 1
# Bbcx[indxu] = -1
# Bbcy[indyd] = 1
# Bbcy[indyu] = -1
# Bbcz[indzd] = 1
# Bbcz[indzu] = -1
# Bbc = np.r_[Bbcx, Bbcy, Bbcz]
In [25]:
Bbcx[indxd] = 1
Bbcx[indxu] = -1
Bbcy[indyd] = 0
Bbcy[indyu] = 0
Bbcz[indzd] = 0
Bbcz[indzu] = 0
Bbc = np.r_[Bbcx, Bbcy, Bbcz]
In [26]:
figsize(16,4)
M3.plotImage(Bbc, imageType='F')
In [27]:
# m1 = sp.linalg.interface.aslinearoperator(Utils.sdiag(-1/A.diagonal()))
In [28]:
# %%time
# rhs = Mc*qa-Mc*Dbc*Bbc[ind]
rhs = qa-Dbc*Bbc[ind]
# Try to use Jacobi preconditioner, but does not work well...
# x, info = sp.linalg.minres(A, rhs, M = m1,tol=1e-6, maxiter = 2000, show=False)
# x, info = sp.linalg.minres(A, rhs, tol=1e-6, maxiter = 1000)
# x, info = sp.linalg.minres(A, rhs, tol=1e-6, maxiter = 2000, show=False)
In [29]:
# rhs = Mc*qa-Mc*Dbc*Bbc[ind]
rhs = qa-Dbc*Bbc[ind]
import petsc4py
import sys
petsc4py.init(sys.argv)
from petsc4py import PETSc
import PETScIO as IO
Apetsc = PETSc.Mat().createAIJ(size=A.shape,csr=(A.indptr, A.indices, A.data))
bpetsc = IO.arrayToVec(rhs)
xpetsc = IO.arrayToVec(0*rhs)
In [30]:
%%time
ksp = PETSc.KSP().create()
pc = PETSc.PC().create()
ksp.setOperators(Apetsc)
ksp.setType(ksp.Type.GMRES)
pc = ksp.getPC()
pc.setType(pc.Type.SOR)
OptDB = PETSc.Options()
OptDB["ksp_rtol"] = 1e-8
OptDB["pc_factor_levels"] = 1
ksp.setFromOptions()
ksp.view()
ksp.solve(bpetsc, xpetsc)
x = IO.vecToArray(xpetsc)
In [31]:
rhsa = A*x
print np.linalg.norm(rhs-rhsa)/np.linalg.norm(rhs)
print info
In [32]:
print A.shape, Phia.shape, qa.shape, Dbc.shape, Bbc[ind].shape
In [33]:
fig, ax = plt.subplots(1,2, figsize=(16,4))
M3.plotImage(x, imageType='CC', ax = ax[0])
M3.plotImage(Phia, imageType='CC', ax = ax[1])
Out[33]:
In [34]:
M3.plotImage(Ba, imageType='F')
In [44]:
Bnum = G*x
# Bnum = G*x
M3.plotImage(Bnum, imageType='F')
In [45]:
print Mc.diagonal()
In [46]:
print np.linalg.norm(Ba[~ind]-Bnum[~ind])/np.linalg.norm(Ba[~ind])
In [47]:
clf;
plot(Ba[~ind]); hold
plot(Bnum[~ind], 'r')
Out[47]:
In [38]:
print np.linalg.norm(x-Phia)/np.linalg.norm(Phia)
In [39]:
plot(Phia); hold
plot(x, 'r')
Out[39]:
Here we can recognize that there are some static... since we do not treat null-space of $A$ properly