mirror of
https://github.com/wassname/simpeg.git
synced 2026-06-29 07:58:48 +08:00
resolved conflicts
This commit is contained in:
+22
-3
@@ -111,13 +111,13 @@ In applied geophysics, which means in practice, it is common to refer to measure
|
||||
|
||||
.. math ::
|
||||
|
||||
\triangle\vec{B} = |\vec{B}_0-\vec{B}_s|-|\vec{B}_0| \approx |\vec{B}_s|cos \theta
|
||||
\triangle\vec{B} = |\hat{B}_o-\vec{B}_s|-|\hat{B}_o| \approx |\vec{B}_s|cos \theta
|
||||
|
||||
where \\(\\theta\\) is the angle between total and anomalous fields. Equivalently, we can use the vector dot product to show that the anomalous field is aproximately equal to the projection of that field onto the direction of the inducing field. Using this approach we would write
|
||||
where \\(\\theta\\) is the angle between total and anomalous fields, \\(\\hat{B}_o\\) is the unit vector for \\(\\vec{B}_o\\). Equivalently, we can use the vector dot product to show that the anomalous field is aproximately equal to the projection of that field onto the direction of the inducing field. Using this approach we would write
|
||||
|
||||
.. math ::
|
||||
|
||||
\triangle\vec{B} = |\vec{B}_s|cos \theta = |\vec{B}_o||\vec{B}_s|cos \theta = \vec{B}_o \cdot \vec{B}_s
|
||||
\triangle\vec{B} = |\vec{B}_s|cos \theta = |\hat{B}_o||\vec{B}_s|cos \theta = \hat{B}_o \cdot \vec{B}_s
|
||||
|
||||
This is important because, in practice we usually use a total field magnetometer (like a proton precession or optically pumped sensor), which can measure only that part of the anomalous field which is in the direction of the earth's main field.
|
||||
|
||||
@@ -128,6 +128,19 @@ Sphere in a whole space
|
||||
Forward problem
|
||||
===============
|
||||
|
||||
Differential equation approach
|
||||
------------------------------
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{A}\mathbf{u} = \mathbf{rhs}
|
||||
|
||||
\mathbf{A} = \Div(\MfMui)^{-1}\Div^{T}
|
||||
|
||||
\mathbf{rhs} = \Div(\MfMui)^{-1}\mathbf{M}^f_{\mu_0^{-1}}\mathbf{B}_0 - \Div\mathbf{B}_0+\diag(v)\mathbf{D} \mathbf{P}_{out}^T \mathbf{B}_{sBC}
|
||||
|
||||
\mathbf{B}_s = (\MfMui)^{-1}\mathbf{M}^f_{\mu_0^{-1}}\mathbf{B}_0-\mathbf{B}_0 -(\MfMui)^{-1}\Div^T \mathbf{u}
|
||||
|
||||
|
||||
|
||||
Inverse problem
|
||||
@@ -143,6 +156,12 @@ Mag Differential eq. approach
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: simpegPF.BaseMag.BaseMagData
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
|
||||
Mag Integral eq. approach
|
||||
*************************
|
||||
|
||||
+47
-16
@@ -11,10 +11,14 @@ class BaseMagData(Data.BaseData):
|
||||
def __init__(self, **kwargs):
|
||||
Data.BaseData.__init__(self, **kwargs)
|
||||
|
||||
#TODO: change to inc, dec, intensity
|
||||
def setBackgroundField(self, x=1., y=0., z=0.):
|
||||
# Primary field in x-direction (background)
|
||||
self.B0 = np.r_[x,y,z]
|
||||
|
||||
def setBackgroundField(self, Inc, Dec, Btot):
|
||||
|
||||
Bx = Btot*np.cos(Inc/180.*np.pi)*np.sin(Dec/180.*np.pi)
|
||||
By = Btot*np.cos(Inc/180.*np.pi)*np.cos(Dec/180.*np.pi)
|
||||
Bz = -Btot*np.sin(Inc/180.*np.pi)
|
||||
|
||||
self.B0 = np.r_[Bx,By,Bz]
|
||||
|
||||
@property
|
||||
def Qfx(self):
|
||||
@@ -34,36 +38,63 @@ class BaseMagData(Data.BaseData):
|
||||
self._Qfz = self.prob.mesh.getInterpolationMat(self.rxLoc,'Fz')
|
||||
return self._Qfz
|
||||
|
||||
def projectFields(self, B):
|
||||
def projectFields(self, u):
|
||||
"""
|
||||
This function projects the fields onto the data space.
|
||||
|
||||
Esepcially, here for we use total magnetic intensity (TMI) data,
|
||||
which is common in practice.
|
||||
|
||||
First we project our B on to data location
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = \mathbf{P} u(m)
|
||||
|
||||
\mathbf{B}_{rec} = \mathbf{P} \mathbf{B}
|
||||
|
||||
then we take the dot product between B and b_0
|
||||
|
||||
.. math ::
|
||||
|
||||
\\text{TMI} = \\vec{B}_s \cdot \hat{B}_0
|
||||
|
||||
"""
|
||||
#TODO: There can be some different tyes of data like |B| or B
|
||||
|
||||
# bfx = self.Qfx*B
|
||||
# bfy = self.Qfy*B
|
||||
bfz = self.Qfz*B
|
||||
return bfz
|
||||
bfx = self.Qfx*u['B']
|
||||
bfy = self.Qfy*u['B']
|
||||
bfz = self.Qfz*u['B']
|
||||
|
||||
# return np.sqrt(bfx**2 + bfy**2 + bfz**2)
|
||||
|
||||
# Generate unit vector
|
||||
B0 = self.prob.data.B0
|
||||
Bot = np.sqrt(B0[0]**2+B0[1]**2+B0[2]**2)
|
||||
box = B0[0]/Bot
|
||||
boy = B0[1]/Bot
|
||||
boz = B0[2]/Bot
|
||||
|
||||
# return bfx*box + bfx*boy + bfx*boz
|
||||
return bfx*box + bfy*boy + bfz*boz
|
||||
|
||||
# return np.sqrt(bfx**2 + bfy**2 + bfz**2)
|
||||
|
||||
@Utils.count
|
||||
def projectFieldsDeriv(self, B):
|
||||
"""
|
||||
This function projects the fields onto the data space.
|
||||
|
||||
|
||||
.. math::
|
||||
|
||||
\\frac{\partial d_\\text{pred}}{\partial u} = \mathbf{P}
|
||||
\\frac{\partial d_\\text{pred}}{\partial \mathbf{B}} = \mathbf{P}
|
||||
|
||||
Esepcially, this function is for TMI data type
|
||||
|
||||
"""
|
||||
return self.Qfz
|
||||
# Generate unit vector
|
||||
B0 = self.prob.data.B0
|
||||
Bot = np.sqrt(B0[0]**2+B0[1]**2+B0[2]**2)
|
||||
box = B0[0]/Bot
|
||||
boy = B0[1]/Bot
|
||||
boz = B0[2]/Bot
|
||||
|
||||
return self.Qfx*box+self.Qfy*boy+self.Qfz*boz
|
||||
|
||||
|
||||
def projectFieldsAsVector(self, B):
|
||||
|
||||
+197
-94
@@ -41,6 +41,7 @@ class MagneticsDiffSecondary(Problem.BaseProblem):
|
||||
self._MfMu0 = self.mesh.getFaceMass(1/mu_0)
|
||||
# self._MfMu0 = self.mesh.getFaceInnerProduct(1/mu_0)
|
||||
|
||||
@Utils.requires('data')
|
||||
def getB0(self):
|
||||
b0 = self.data.B0
|
||||
B0 = np.r_[b0[0]*np.ones(self.mesh.nFx),
|
||||
@@ -49,17 +50,21 @@ class MagneticsDiffSecondary(Problem.BaseProblem):
|
||||
return B0
|
||||
|
||||
def getRHS(self, m):
|
||||
"""
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{rhs} = \Div(\MfMui)^{-1}\mathbf{M}^f_{\mu_0^{-1}}\mathbf{B}_0 - \Div\mathbf{B}_0+\diag(v)\mathbf{D} \mathbf{P}_{out}^T \mathbf{B}_{sBC}
|
||||
|
||||
"""
|
||||
B0 = self.getB0()
|
||||
Dface = self.mesh.faceDiv
|
||||
Mc = Utils.sdiag(self.mesh.vol)
|
||||
|
||||
chi = self.model.transform(m, asMu=False)
|
||||
Bbc, const = CongruousMagBC(self.mesh, self.data.B0, chi)
|
||||
self.Bbc_const = const
|
||||
Bbc, Bbc_const = CongruousMagBC(self.mesh, self.data.B0, chi)
|
||||
self.Bbc = Bbc
|
||||
#TODO: put congrous BC back in
|
||||
# return self._Div*self.MfMuI*self.MfMu0*B0 - self._Div*B0 #+ Mc*Dface*self._Pout.T*Bbc
|
||||
self.Bbc_const = Bbc_const
|
||||
return self._Div*self.MfMuI*self.MfMu0*B0 - self._Div*B0 + Mc*Dface*self._Pout.T*Bbc
|
||||
|
||||
def getA(self, m):
|
||||
@@ -68,41 +73,39 @@ class MagneticsDiffSecondary(Problem.BaseProblem):
|
||||
|
||||
The A matrix has the form:
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{A}\mathbf{u} = \mathbf{rhs}
|
||||
|
||||
\mathbf{A} = - \Div(\MfMui)^{-1}\Div^{T}
|
||||
|
||||
\mathbf{rhs} = - \Div(\MfMui)^{-1}\mathbf{M}^f_{\\frac{1}{\mu_0}}\mathbf{B}_0 + \Div\mathbf{B}_0-\diag(v)\mathbf{D} \mathbf{P}_{out}^T \mathbf{B}_{sBC}
|
||||
.. math ::
|
||||
|
||||
\mathbf{A} = \Div(\MfMui)^{-1}\Div^{T}
|
||||
|
||||
"""
|
||||
return self._Div*self.MfMuI*self._Div.T
|
||||
|
||||
|
||||
def fields(self, m):
|
||||
"""
|
||||
Return magnetic potential (u) and flux (B)
|
||||
u: defined on the cell center [nC x 1]
|
||||
B: defined on the cell center [nF x 1]
|
||||
|
||||
After we compute u, then we update B.
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{B}_s = (\MfMui)^{-1}\mathbf{M}^f_{\mu_0^{-1}}\mathbf{B}_0-\mathbf{B}_0 -(\MfMui)^{-1}\Div^T \mathbf{u}
|
||||
|
||||
"""
|
||||
self.makeMassMatrices(m)
|
||||
A = self.getA(m)
|
||||
rhs = self.getRHS(m)
|
||||
|
||||
m1 = sp.linalg.interface.aslinearoperator(Utils.sdiag(1/A.diagonal()))
|
||||
u, info = sp.linalg.bicgstab(A, rhs, tol=1e-6, maxiter=1000, M=m1)
|
||||
|
||||
B0 = self.getB0()
|
||||
|
||||
B = self.MfMuI*self.MfMu0*B0-B0-self.MfMuI*self._Div.T*u
|
||||
|
||||
#TODO: Create a mag fields object class.
|
||||
# F = self.getInitialFields()
|
||||
# e.g. {'B': B, 'u': u}
|
||||
|
||||
return {'B': B, 'u': u}
|
||||
|
||||
# return self.forward(m, self.getRHS, self.calcFields, F=F)
|
||||
|
||||
@Utils.timeIt
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, fields=None):
|
||||
"""
|
||||
Computing Jacobian multiplied by vector
|
||||
|
||||
@@ -122,7 +125,7 @@ class MagneticsDiffSecondary(Problem.BaseProblem):
|
||||
\\frac{\delta \mathbf{u}}{\delta \mathbf{m}} = - [\\nabla_u \mathbf{C}(\mathbf{u})]^{-1}\\nabla_m \mathbf{C}(\mathbf{m})
|
||||
|
||||
With some linear algebra we can have
|
||||
|
||||
|
||||
.. math ::
|
||||
|
||||
\\nabla_u \mathbf{C}(\mathbf{u}) = \mathbf{A}
|
||||
@@ -138,66 +141,177 @@ class MagneticsDiffSecondary(Problem.BaseProblem):
|
||||
\dMfMuI = \diag(\MfMui)^{-1}_{vec} \mathbf{Av}_{F2CC}^T\diag(\mathbf{v})\diag(\\frac{1}{\mu^2})
|
||||
|
||||
\\frac{\partial \mathbf{rhs}(\mathbf{m})}{\partial \mathbf{m}} = \\frac{\partial \mathbf{\mu}}{\partial \mathbf{m}} \left[
|
||||
\Div \diag(\M^f_{\mu_{0}^{-1} \mathbf{B}_0}) \dMfMuI \\right] - \diag(\mathbf{v})\mathbf{D} \mathbf{P}_{out}^T\\frac{\partial B_{sBC}}{\partial \mathbf{m}}
|
||||
\Div \diag(\M^f_{\mu_{0}^{-1}}\mathbf{B}_0) \dMfMuI \\right] - \diag(\mathbf{v})\mathbf{D} \mathbf{P}_{out}^T\\frac{\partial B_{sBC}}{\partial \mathbf{m}}
|
||||
|
||||
In the end,
|
||||
|
||||
.. math ::
|
||||
|
||||
\\frac{\delta \mathbf{u}}{\delta \mathbf{m}} =
|
||||
- [ \mathbf{A} ]^{-1}\left[ \\frac{\partial \mathbf{A}}{\partial \mathbf{m}}(\mathbf{m})\mathbf{u}
|
||||
- \\frac{\partial \mathbf{rhs}(\mathbf{m})}{\partial \mathbf{m}} \\right]
|
||||
|
||||
A little tricky point here is we are not interested in potential (u), but interested in magnetic flux (B).
|
||||
Thus, we need sensitivity for B. Now we take derivative of B w.r.t m and have
|
||||
|
||||
.. math ::
|
||||
|
||||
\\frac{\delta \mathbf{B}} {\delta \mathbf{m}} = \\frac{\partial \mathbf{\mu} } {\partial \mathbf{m} }
|
||||
\left[
|
||||
\diag(\M^f_{\mu_{0}^{-1} } \mathbf{B}_0) \dMfMuI \\
|
||||
- \diag (\Div^T\mathbf{u})\dMfMuI
|
||||
\\right ]
|
||||
|
||||
- (\MfMui)^{-1}\Div^T\\frac{\delta\mathbf{u}}{\delta \mathbf{m}}
|
||||
|
||||
Finally we evaluate the above, but we should remember that
|
||||
|
||||
.. note ::
|
||||
|
||||
We only want to evalute
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{J}\mathbf{v} = \\frac{\delta \mathbf{P}\mathbf{B}} {\delta \mathbf{m}}\mathbf{v}
|
||||
|
||||
Since forming sensitivity matrix is very expensive in that this monster is "big" and "dense" matrix!!
|
||||
|
||||
|
||||
"""
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
|
||||
#TODO: B, u = u['B'], u['u']
|
||||
|
||||
B, u = u['B'], u['u']
|
||||
if fields is None:
|
||||
fields = self.fields(m)
|
||||
|
||||
B, u = fields['B'], fields['u']
|
||||
mu = self.model.transform(m, asMu=True)
|
||||
dmudm = self.model.transform(m, asMu=True)
|
||||
|
||||
P = self.data.projectFieldsDeriv(u)
|
||||
|
||||
A = self.getA(m)
|
||||
dCdu = A
|
||||
# (Av_m)^-1
|
||||
# -(Av_m)^-2 * MfMu_dm * d/dm(1/mu(m))
|
||||
# (Av_m)^-2 * MfMu_dm * diag(mu(m)^-2) * mT_dm
|
||||
|
||||
#TODO: only works for diagonal MfMui
|
||||
# Some chain rule!
|
||||
|
||||
|
||||
# harm_dm = Utils.sdiag(self.MfMui.diagonal()**(-2))
|
||||
# MfMu_dm = self.mesh.getFaceMassDeriv()
|
||||
# dmuI_dm = Utils.sdiag(mu**(-2))
|
||||
# mT_dm = self.model.transformDeriv(m, asMu=True)
|
||||
|
||||
getFIPconst = 1./3
|
||||
MfMuIvec = 1/self.MfMui.diagonal()*getFIPconst
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*self.mesh.aveF2CC.T*Utils.sdiag(self.mesh.vol*1./mu**2)
|
||||
dmudm = self.model.transformDeriv(m, asMu=True)
|
||||
dmdmu = Utils.sdiag(1/(dmudm.diagonal()))
|
||||
|
||||
vol = self.mesh.vol
|
||||
Div = self._Div
|
||||
# lots-o-bracket for vector multiplication first!
|
||||
# MfMu_dmXv = harm_dm * ( MfMu_dm * ( dmuI_dm * ( mT_dm * v ) ) )
|
||||
#dCdm_A = D * ( Utils.sdiag( D.T * u ) * MfMu_dmXv )
|
||||
|
||||
dCdm_A = dmudm*Div * ( Utils.sdiag( Div.T * u * dMfMuI ) )
|
||||
|
||||
# rhs = D * MfMuI * MfMu0 * B0
|
||||
|
||||
Dface = self.mesh.faceDiv
|
||||
P = self.data.projectFieldsDeriv(B) # Projection matrix
|
||||
B0 = self.getB0()
|
||||
|
||||
#TODO: add congrous stuff
|
||||
dCdm_RHS = dmudm* Div * Utils.sdiag( self.MfMu0*B0 ) * dMfMuI - Utils.sdiag(self.mesh.vol)*self.mesh.faceDiv*self.Pout.T*self.Bbc*self.Bbc_const
|
||||
MfMuIvec = 1/self.MfMui.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*self.mesh.aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
|
||||
# A = self._Div*self.MfMuI*self._Div.T
|
||||
# RHS = Div*MfMuI*MfMu0*B0 - Div*B0 + Mc*Dface*Pout.T*Bbc
|
||||
# C(m,u) = A*m-rhs
|
||||
# dudm = -(dCdu)^(-1)dCdm
|
||||
|
||||
# c(m,u) = A(m)u - rhs(m)
|
||||
dCdm = dCdm_A - dCdm_RHS
|
||||
dCdu = self.getA(m)
|
||||
dCdm_A = Div * ( Utils.sdiag( Div.T * u )* dMfMuI *dmudm )
|
||||
dCdm_RHS1 = Div * (Utils.sdiag( self.MfMu0*B0 ) * dMfMuI)
|
||||
temp1 = (Dface*(self._Pout.T*self.Bbc_const*self.Bbc))
|
||||
dCdm_RHS2v = (Utils.sdiag(vol)*temp1)*np.inner(vol, v)
|
||||
dCdm_RHSv = dCdm_RHS1*(dmudm*v) + dCdm_RHS2v
|
||||
dCdm_v = dCdm_A*v - dCdm_RHSv
|
||||
|
||||
solve = Solver(dCdu)
|
||||
m1 = sp.linalg.interface.aslinearoperator(Utils.sdiag(1/dCdu.diagonal()))
|
||||
sol, info = sp.linalg.bicgstab(dCdu, dCdm_v, tol=1e-8, maxiter=1000, M=m1)
|
||||
|
||||
#TODO: Multiply by the dP(u(m))/du
|
||||
# We transformed u in our fields object.
|
||||
# ( dBdu * + dBdm(u) )
|
||||
Jv = - P * solve.solve(dCdm)
|
||||
return Utils.mkvc(Jv)
|
||||
if info > 0:
|
||||
raise Exception ("Iterative solver did not work well")
|
||||
|
||||
# B = self.MfMuI*self.MfMu0*B0-B0-self.MfMuI*self._Div.T*u
|
||||
# dBdm = d\mudm*dBd\mu
|
||||
|
||||
dudm = -sol
|
||||
dBdmv = ( Utils.sdiag(self.MfMu0*B0)*(dMfMuI * (dmudm*v)) \
|
||||
- Utils.sdiag(Div.T*u)*(dMfMuI* (dmudm*v)) \
|
||||
- self.MfMuI*(Div.T* (dudm)) )
|
||||
|
||||
return Utils.mkvc(P*dBdmv)
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec(self, m, v, fields=None):
|
||||
"""
|
||||
Computing Jacobian^T multiplied by vector.
|
||||
|
||||
.. math ::
|
||||
|
||||
(\\frac{\delta \mathbf{P}\mathbf{B}} {\delta \mathbf{m}})^{T} = \left[ \mathbf{P}_{deriv}\\frac{\partial \mathbf{\mu} } {\partial \mathbf{m} }
|
||||
\left[
|
||||
\diag(\M^f_{\mu_{0}^{-1} } \mathbf{B}_0) \dMfMuI \\
|
||||
- \diag (\Div^T\mathbf{u})\dMfMuI
|
||||
\\right ]\\right]^{T}
|
||||
|
||||
- \left[\mathbf{P}_{deriv}(\MfMui)^{-1}\Div^T\\frac{\delta\mathbf{u}}{\delta \mathbf{m}} \\right]^{T}
|
||||
|
||||
where
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{P}_{derv} = \\frac{\partial \mathbf{P}}{\partial\mathbf{B}}
|
||||
|
||||
.. note ::
|
||||
|
||||
Here we only want to compute
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{J}^{T}\mathbf{v} = (\\frac{\delta \mathbf{P}\mathbf{B}} {\delta \mathbf{m}})^{T} \mathbf{v}
|
||||
|
||||
"""
|
||||
if fields is None:
|
||||
fields = self.fields(m)
|
||||
|
||||
B, u = fields['B'], fields['u']
|
||||
mu = self.model.transform(m, asMu=True)
|
||||
dmudm = self.model.transformDeriv(m, asMu=True)
|
||||
dmdmu = Utils.sdiag(1/(dmudm.diagonal()))
|
||||
|
||||
vol = self.mesh.vol
|
||||
Div = self._Div
|
||||
Dface = self.mesh.faceDiv
|
||||
P = self.data.projectFieldsDeriv(B) # Projection matrix
|
||||
B0 = self.getB0()
|
||||
|
||||
MfMuIvec = 1/self.MfMui.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*self.mesh.aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
|
||||
# A = self._Div*self.MfMuI*self._Div.T
|
||||
# RHS = Div*MfMuI*MfMu0*B0 - Div*B0 + Mc*Dface*Pout.T*Bbc
|
||||
# C(m,u) = A*m-rhs
|
||||
# dudm = -(dCdu)^(-1)dCdm
|
||||
|
||||
dCdu = self.getA(m)
|
||||
s = Div * ( self.MfMuI.T * ( P.T*v ) )
|
||||
|
||||
m1 = sp.linalg.interface.aslinearoperator(Utils.sdiag(1/(dCdu.T).diagonal()))
|
||||
sol, info = sp.linalg.bicgstab(dCdu.T, s, tol=1e-8, maxiter=1000, M=m1)
|
||||
|
||||
if info > 0:
|
||||
raise Exception ("Iterative solver did not work well")
|
||||
|
||||
# dCdm_A = Div * ( Utils.sdiag( Div.T * u )* dMfMuI *dmudm )
|
||||
dCdm_Atsol = ( dMfMuI.T*( Utils.sdiag( Div.T * u ) * (Div.T * dmudm)) ) * sol
|
||||
|
||||
# dCdm_RHS1 = Div * (Utils.sdiag( self.MfMu0*B0 ) * dMfMuI)
|
||||
dCdm_RHS1tsol = (dMfMuI.T*( Utils.sdiag( self.MfMu0*B0 ) ) * Div.T * dmudm) * sol
|
||||
|
||||
# temp1 = (Dface*(self._Pout.T*self.Bbc_const*self.Bbc))
|
||||
# dCdm_RHS2v = (Utils.sdiag(vol)*temp1)*np.inner(vol, v)
|
||||
temp1sol = ( Dface.T*( Utils.sdiag(vol)*sol ) )
|
||||
temp2 = self.Bbc_const*(self._Pout.T*self.Bbc).T
|
||||
dCdm_RHS2tsol = vol*np.inner(temp2, temp1sol)
|
||||
dCdm_RHStsol = dCdm_RHS1tsol - dCdm_RHS2tsol
|
||||
|
||||
# dCdm_RHSv = dCdm_RHS1*(dmudm*v) + dCdm_RHS2v
|
||||
# dCdm_v = dCdm_A*v - dCdm_RHSv
|
||||
|
||||
Ctv = dCdm_Atsol - dCdm_RHStsol
|
||||
|
||||
# B = self.MfMuI*self.MfMu0*B0-B0-self.MfMuI*self._Div.T*u
|
||||
# dBdm = d\mudm*dBd\mu
|
||||
# dPBdm^T*v = Atemp^T*P^T*v - Btemp^T*P^T*v - Ctv
|
||||
|
||||
Atemp = Utils.sdiag(self.MfMu0*B0)*(dMfMuI * (dmudm))
|
||||
Btemp = Utils.sdiag(Div.T*u)*(dMfMuI* (dmudm))
|
||||
Jtv = Atemp.T*(P.T*v) - Btemp.T*(P.T*v) - Ctv
|
||||
|
||||
return Utils.mkvc(Jtv)
|
||||
|
||||
|
||||
|
||||
@@ -218,7 +332,12 @@ if __name__ == '__main__':
|
||||
# mu = (1.+chi)*mu_0
|
||||
|
||||
data = BaseMag.BaseMagData()
|
||||
data.setBackgroundField(x=1., y=1., z=0.)
|
||||
Inc = 90.
|
||||
Dec = 0.
|
||||
Btot = 51000
|
||||
|
||||
data.setBackgroundField(Inc, Dec, Btot)
|
||||
|
||||
xr = np.linspace(-300, 300, 41)
|
||||
yr = np.linspace(-300, 300, 41)
|
||||
X, Y = np.meshgrid(xr, yr)
|
||||
@@ -230,30 +349,14 @@ if __name__ == '__main__':
|
||||
|
||||
prob.pair(data)
|
||||
|
||||
B = prob.fields(chi)
|
||||
# mesh.plotSlice(B, 'F', view='vec', showIt=True)
|
||||
|
||||
dpred = data.dpred(chi, u=B)
|
||||
|
||||
|
||||
# ##################
|
||||
# # Test J
|
||||
# ##################
|
||||
|
||||
# d_chi = 0.8*chi #np.random.rand(mesh.nCz)
|
||||
# d_sph_ind = spheremodel(mesh, 0., 0., -100., 50)
|
||||
# d_chi[d_sph_ind] = 0.02
|
||||
|
||||
# from SimPEG.Tests import checkDerivative
|
||||
|
||||
# derChk = lambda m: [prob.data.dpred(m), lambda mx: -prob.Jvec(chi, mx)]
|
||||
# print '\n'
|
||||
# passed = checkDerivative(derChk, chi, plotIt=False, dx=d_chi, num=2)
|
||||
|
||||
|
||||
# # plt.pcolor(X, Y, dpred.reshape(X.shape, order='F'))
|
||||
|
||||
# # plt.show()
|
||||
dpred = data.dpred(chi)
|
||||
fig = plt.figure( figsize = (8,5) )
|
||||
ax = plt.subplot(111)
|
||||
dat = plt.imshow(np.reshape(dpred, (xr.size, yr.size), order='F'), extent=[min(xr), max(xr), min(yr), max(yr)])
|
||||
plt.colorbar(dat, ax = ax)
|
||||
plt.show()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import matplotlib.pyplot as plt
|
||||
import simpegPF as PF
|
||||
|
||||
|
||||
class MagProblemTests(unittest.TestCase):
|
||||
class MagFwdProblemTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
@@ -29,7 +29,13 @@ class MagProblemTests(unittest.TestCase):
|
||||
def test_anal_forward(self):
|
||||
|
||||
data = PF.BaseMag.BaseMagData()
|
||||
data.setBackgroundField(x=1., y=1., z=0.)
|
||||
|
||||
Inc = 90.
|
||||
Dec = 0.
|
||||
Btot = 51000
|
||||
|
||||
b0 = PF.MagAnalytics.IDTtoxyz(Inc, Dec, Btot)
|
||||
data.setBackgroundField(Inc, Dec, Btot)
|
||||
xr = np.linspace(-300, 300, 41)
|
||||
yr = np.linspace(-300, 300, 41)
|
||||
X, Y = np.meshgrid(xr, yr)
|
||||
@@ -38,9 +44,10 @@ class MagProblemTests(unittest.TestCase):
|
||||
data.rxLoc = rxLoc
|
||||
|
||||
self.prob.pair(data)
|
||||
B = self.prob.fields(self.chi)
|
||||
u = self.prob.fields(self.chi)
|
||||
B = u['B']
|
||||
|
||||
bxa,bya,bza = PF.MagAnalytics.MagSphereAnalFunA(rxLoc[:,0],rxLoc[:,1],rxLoc[:,2],100.,0.,0.,0.,0.01,np.array([1.,1.,0.]),'secondary')
|
||||
bxa,bya,bza = PF.MagAnalytics.MagSphereAnalFunA(rxLoc[:,0],rxLoc[:,1],rxLoc[:,2],100.,0.,0.,0.,0.01, b0,'secondary')
|
||||
|
||||
dpred = data.projectFieldsAsVector(B)
|
||||
err = np.linalg.norm(dpred-np.r_[bxa, bya, bza])/np.linalg.norm(np.r_[bxa, bya, bza])
|
||||
@@ -50,6 +57,6 @@ class MagProblemTests(unittest.TestCase):
|
||||
else:
|
||||
print "Anaytic test is passed"
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
import unittest
|
||||
from SimPEG import *
|
||||
from simpegPF import BaseMag
|
||||
import matplotlib.pyplot as plt
|
||||
import simpegPF as PF
|
||||
from scipy.constants import mu_0
|
||||
|
||||
|
||||
class MagSensProblemTests(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
||||
hxind = ((5,25,1.3),(21, 25.),(5,25,1.3))
|
||||
hyind = ((5,25,1.3),(21, 25.),(5,25,1.3))
|
||||
hzind = ((5,25,1.3),(20, 25.),(5,25,1.3))
|
||||
hx, hy, hz = Utils.meshTensors(hxind, hyind, hzind)
|
||||
M = Mesh.TensorMesh([hx, hy, hz], [-hx.sum()/2,-hy.sum()/2,-hz.sum()/2])
|
||||
chibkg = 0.001
|
||||
chiblk = 0.01
|
||||
chi = np.ones(M.nC)*chibkg
|
||||
|
||||
Inc = 90.
|
||||
Dec = 0.
|
||||
Btot = 51000
|
||||
|
||||
b0 = PF.MagAnalytics.IDTtoxyz(Inc, Dec, Btot)
|
||||
sph_ind = PF.MagAnalytics.spheremodel(M, 0., 0., 0., 100)
|
||||
chi[sph_ind] = chiblk
|
||||
model = PF.BaseMag.BaseMagModel(M)
|
||||
|
||||
data = BaseMag.BaseMagData()
|
||||
|
||||
data.setBackgroundField(Inc, Dec, Btot)
|
||||
xr = np.linspace(-300, 300, 41)
|
||||
yr = np.linspace(-300, 300, 41)
|
||||
X, Y = np.meshgrid(xr, yr)
|
||||
Z = np.ones((xr.size, yr.size))*150
|
||||
rxLoc = np.c_[Utils.mkvc(X), Utils.mkvc(Y), Utils.mkvc(Z)]
|
||||
data.rxLoc = rxLoc
|
||||
|
||||
|
||||
|
||||
prob = PF.Magnetics.MagneticsDiffSecondary(M, model)
|
||||
prob.pair(data)
|
||||
dpre = data.dpred(chi)
|
||||
|
||||
fields = prob.fields(chi)
|
||||
self.u = fields['u']
|
||||
self.B = fields['B']
|
||||
|
||||
self.data = data
|
||||
self.model = model
|
||||
self.prob = prob
|
||||
self.M = M
|
||||
self.chi = chi
|
||||
|
||||
|
||||
|
||||
def test_mass(self):
|
||||
print '\n >>Derivative for MfMuI works.'
|
||||
mu = self.model.transform(self.chi, asMu=True)
|
||||
def MfmuI(mu):
|
||||
|
||||
chi = mu/mu_0-1
|
||||
self.prob.makeMassMatrices(chi)
|
||||
vol = self.prob.mesh.vol
|
||||
aveF2CC = self.prob.mesh.aveF2CC
|
||||
MfMuI = self.prob.MfMuI.diagonal()
|
||||
|
||||
return MfMuI
|
||||
|
||||
def dMfmuI(mu, v):
|
||||
|
||||
chi = mu/mu_0-1
|
||||
self.prob.makeMassMatrices(chi)
|
||||
vol = self.prob.mesh.vol
|
||||
aveF2CC = self.prob.mesh.aveF2CC
|
||||
MfMuI = self.prob.MfMuI.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuI**2)*aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
|
||||
return dMfMuI*v
|
||||
|
||||
d_mu = mu*0.8
|
||||
derChk = lambda m: [MfmuI(m), lambda mx: dMfmuI(self.chi, mx)]
|
||||
passed = Tests.checkDerivative(derChk, mu, num=4, dx = d_mu, plotIt=False)
|
||||
|
||||
|
||||
self.assertTrue(passed)
|
||||
|
||||
|
||||
def test_dCdm_Av(self):
|
||||
print '\n >>Derivative for Cm_A.'
|
||||
Div = self.prob._Div
|
||||
vol = self.prob.mesh.vol
|
||||
aveF2CC = self.prob.mesh.aveF2CC
|
||||
|
||||
def Cm_A(chi):
|
||||
dmudm = self.model.transformDeriv(chi, asMu=True)
|
||||
u = self.u
|
||||
# chi = mu/mu_0-1
|
||||
self.prob.makeMassMatrices(chi)
|
||||
mu = self.model.transform(self.chi, asMu=True)
|
||||
A = self.prob.getA(self.chi)
|
||||
MfMuIvec = 1/self.prob.MfMui.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
|
||||
Cm_A = A*u
|
||||
|
||||
return Cm_A
|
||||
|
||||
def dCdm_A(chi, v):
|
||||
|
||||
dmudm = self.model.transformDeriv(chi, asMu=True)
|
||||
u = self.u
|
||||
self.prob.makeMassMatrices(chi)
|
||||
mu = self.model.transform(self.chi, asMu=True)
|
||||
A = self.prob.getA(self.chi)
|
||||
MfMuIvec = 1/self.prob.MfMui.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
|
||||
Cm_A = A*u
|
||||
dCdm_A = Div * ( Utils.sdiag( Div.T * u )* dMfMuI *dmudm )
|
||||
|
||||
return dCdm_A*v
|
||||
|
||||
d_chi = self.chi*0.8
|
||||
derChk = lambda m: [Cm_A(m), lambda mx: dCdm_A(self.chi, mx)]
|
||||
passed = Tests.checkDerivative(derChk, self.chi, num=4, dx = d_chi, plotIt=False)
|
||||
self.assertTrue(passed)
|
||||
|
||||
|
||||
def test_dCdmu_RHS(self):
|
||||
print '\n >>Derivative for Cm_RHS.'
|
||||
u = self.u
|
||||
Div = self.prob._Div
|
||||
mu = self.model.transform(self.chi, asMu=True)
|
||||
vol = self.prob.mesh.vol
|
||||
Mc = Utils.sdiag(vol)
|
||||
aveF2CC = self.prob.mesh.aveF2CC
|
||||
B0 = self.prob.getB0()
|
||||
Dface = self.prob.mesh.faceDiv
|
||||
|
||||
def Cm_RHS(chi):
|
||||
|
||||
self.prob.makeMassMatrices(chi)
|
||||
dmudm = self.model.transformDeriv(chi, asMu=True)
|
||||
dchidmu = Utils.sdiag(1/(dmudm.diagonal()))
|
||||
Bbc, Bbc_const = PF.MagAnalytics.CongruousMagBC(self.prob.mesh, self.data.B0, chi)
|
||||
MfMuIvec = 1/self.prob.MfMui.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
RHS1 = Div*self.prob.MfMuI*self.prob.MfMu0*B0
|
||||
RHS2 = Mc*Dface*self.prob._Pout.T*Bbc
|
||||
RHS = RHS1 + RHS2 + Div*B0
|
||||
|
||||
return RHS
|
||||
|
||||
|
||||
def dCdm_RHS(chi, v):
|
||||
|
||||
|
||||
self.prob.makeMassMatrices(chi)
|
||||
dmudm = self.model.transformDeriv(chi, asMu=True)
|
||||
dmdmu = Utils.sdiag(1/(dmudm.diagonal()))
|
||||
Bbc, Bbc_const = PF.MagAnalytics.CongruousMagBC(self.prob.mesh, self.data.B0, chi)
|
||||
MfMuIvec = 1/self.prob.MfMui.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
dCdm_RHS1 = Div * (Utils.sdiag( self.prob.MfMu0*B0 ) * dMfMuI)
|
||||
temp1 = (Dface*(self.prob._Pout.T*Bbc_const*Bbc))
|
||||
dCdm_RHS2v = (Utils.sdiag(vol)*temp1)*np.inner(vol, v)
|
||||
dCdm_RHSv = dCdm_RHS1*(dmudm*v) + dCdm_RHS2v
|
||||
|
||||
return dCdm_RHSv
|
||||
|
||||
d_chi = self.chi*0.8
|
||||
derChk = lambda m: [Cm_RHS(m), lambda mx: dCdm_RHS(self.chi, mx)]
|
||||
passed = Tests.checkDerivative(derChk, self.chi, num=4, dx = d_chi, plotIt=False)
|
||||
self.assertTrue(passed)
|
||||
|
||||
|
||||
def test_dudm(self):
|
||||
print ">> Derivative test for dudm"
|
||||
u = self.u
|
||||
Div = self.prob._Div
|
||||
mu = self.model.transform(self.chi, asMu=True)
|
||||
vol = self.prob.mesh.vol
|
||||
Mc = Utils.sdiag(vol)
|
||||
aveF2CC = self.prob.mesh.aveF2CC
|
||||
B0 = self.prob.getB0()
|
||||
Dface = self.prob.mesh.faceDiv
|
||||
|
||||
def ufun(chi):
|
||||
u = self.prob.fields(chi)['u']
|
||||
return u
|
||||
|
||||
def dudm(chi, v):
|
||||
|
||||
chi = mu/mu_0-1
|
||||
self.prob.makeMassMatrices(chi)
|
||||
u = self.u
|
||||
dmudm = self.model.transformDeriv(chi, asMu=True)
|
||||
dmdmu = Utils.sdiag(1/(dmudm.diagonal()))
|
||||
Bbc, Bbc_const = PF.MagAnalytics.CongruousMagBC(self.prob.mesh, self.data.B0, chi)
|
||||
MfMuIvec = 1/self.prob.MfMui.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
dCdu = self.prob.getA(chi)
|
||||
dCdm_A = Div * ( Utils.sdiag( Div.T * u )* dMfMuI *dmudm )
|
||||
dCdm_RHS1 = Div * (Utils.sdiag( self.prob.MfMu0*B0 ) * dMfMuI)
|
||||
temp1 = (Dface*(self.prob._Pout.T*Bbc_const*Bbc))
|
||||
dCdm_RHS2v = (Utils.sdiag(vol)*temp1)*np.inner(vol, v)
|
||||
dCdm_RHSv = dCdm_RHS1*(dmudm*v) + dCdm_RHS2v
|
||||
dCdm_v = dCdm_A*v - dCdm_RHSv
|
||||
m1 = sp.linalg.interface.aslinearoperator(Utils.sdiag(1/dCdu.diagonal()))
|
||||
sol, info = sp.linalg.bicgstab(dCdu, dCdm_v, tol=1e-8, maxiter=1000, M=m1)
|
||||
|
||||
dudm = -sol
|
||||
|
||||
return dudm
|
||||
|
||||
d_chi = 10.0*self.chi #np.random.rand(mesh.nCz)
|
||||
d_sph_ind = PF.MagAnalytics.spheremodel(self.prob.mesh, 0., 0., -50., 50)
|
||||
d_chi[d_sph_ind] = 0.1
|
||||
|
||||
derChk = lambda m: [ufun(m), lambda mx: dudm(self.chi, mx)]
|
||||
# TODO: I am not sure why the order get worse as step decreases .. --;
|
||||
passed = Tests.checkDerivative(derChk, self.chi, num=2, dx = d_chi, plotIt=False)
|
||||
self.assertTrue(passed)
|
||||
|
||||
|
||||
def test_dBdm(self):
|
||||
print ">> Derivative test for dBdm"
|
||||
u = self.u
|
||||
Div = self.prob._Div
|
||||
mu = self.model.transform(self.chi, asMu=True)
|
||||
vol = self.prob.mesh.vol
|
||||
Mc = Utils.sdiag(vol)
|
||||
aveF2CC = self.prob.mesh.aveF2CC
|
||||
B0 = self.prob.getB0()
|
||||
Dface = self.prob.mesh.faceDiv
|
||||
|
||||
def Bfun(chi):
|
||||
B = self.prob.fields(chi)['B']
|
||||
return B
|
||||
|
||||
def dBdm(chi, v):
|
||||
|
||||
chi = mu/mu_0-1
|
||||
self.prob.makeMassMatrices(chi)
|
||||
u = self.u
|
||||
dmudm = self.model.transformDeriv(chi, asMu=True)
|
||||
dmdmu = Utils.sdiag(1/(dmudm.diagonal()))
|
||||
Bbc, Bbc_const = PF.MagAnalytics.CongruousMagBC(self.prob.mesh, self.data.B0, chi)
|
||||
MfMuIvec = 1/self.prob.MfMui.diagonal()
|
||||
dMfMuI = Utils.sdiag(MfMuIvec**2)*aveF2CC.T*Utils.sdiag(vol*1./mu**2)
|
||||
dCdu = self.prob.getA(chi)
|
||||
dCdm_A = Div * ( Utils.sdiag( Div.T * u )* dMfMuI *dmudm )
|
||||
dCdm_RHS1 = Div * (Utils.sdiag( self.prob.MfMu0*B0 ) * dMfMuI)
|
||||
temp1 = (Dface*(self.prob._Pout.T*Bbc_const*Bbc))
|
||||
dCdm_RHS2v = (Utils.sdiag(vol)*temp1)*np.inner(vol, v)
|
||||
dCdm_RHSv = dCdm_RHS1*(dmudm*v) + dCdm_RHS2v
|
||||
dCdm_v = dCdm_A*v - dCdm_RHSv
|
||||
m1 = sp.linalg.interface.aslinearoperator(Utils.sdiag(1/dCdu.diagonal()))
|
||||
sol, info = sp.linalg.bicgstab(dCdu, dCdm_v, tol=1e-8, maxiter=1000, M=m1)
|
||||
|
||||
dudm = -sol
|
||||
dBdmv = ( Utils.sdiag(self.prob.MfMu0*B0)*(dMfMuI * (dmudm*v)) \
|
||||
- Utils.sdiag(Div.T*u)*(dMfMuI* (dmudm*v)) \
|
||||
- self.prob.MfMuI*(Div.T* (dudm)) )
|
||||
|
||||
return dBdmv
|
||||
|
||||
d_chi = 10.0*self.chi #np.random.rand(mesh.nCz)
|
||||
d_sph_ind = PF.MagAnalytics.spheremodel(self.prob.mesh, 0., 0., -50., 50)
|
||||
d_chi[d_sph_ind] = 0.1
|
||||
|
||||
derChk = lambda m: [Bfun(m), lambda mx: dBdm(self.chi, mx)]
|
||||
# TODO: I am not sure why the order get worse as step decreases .. --;
|
||||
passed = Tests.checkDerivative(derChk, self.chi, num=3, dx = d_chi, plotIt=False)
|
||||
self.assertTrue(passed)
|
||||
|
||||
|
||||
|
||||
def test_Jvec(self):
|
||||
print ">> Derivative test for Jvec"
|
||||
mu = self.model.transform(self.chi, asMu=True)
|
||||
|
||||
d_chi = 10.0*self.chi #np.random.rand(mesh.nCz)
|
||||
d_sph_ind = PF.MagAnalytics.spheremodel(self.prob.mesh, 0., 0., -50., 50)
|
||||
d_chi[d_sph_ind] = 0.1
|
||||
|
||||
a = self.prob.Jvec(self.chi, d_chi)
|
||||
|
||||
derChk = lambda m: [self.data.dpred(m), lambda mx: self.prob.Jvec(self.chi, mx)]
|
||||
# TODO: I am not sure why the order get worse as step decreases .. --;
|
||||
passed = Tests.checkDerivative(derChk, self.chi, num=2, dx = d_chi, plotIt=False)
|
||||
self.assertTrue(passed)
|
||||
|
||||
def test_Jtvec(self):
|
||||
print ">> Derivative test for Jtvec"
|
||||
mu = self.model.transform(self.chi, asMu=True)
|
||||
dobs = self.data.dpred(self.chi)
|
||||
|
||||
def misfit (m, dobs):
|
||||
dpre = self.data.dpred(m)
|
||||
misfit = 0.5*np.linalg.norm(dpre-dobs)**2
|
||||
residual = dpre-dobs
|
||||
dmisfit = self.prob.Jtvec(self.chi, residual)
|
||||
|
||||
return misfit, dmisfit
|
||||
|
||||
# TODO: I am not sure why the order get worse as step decreases .. --;
|
||||
derChk = lambda m: misfit(m, dobs)
|
||||
passed = Tests.checkDerivative(derChk, self.chi, num=4, plotIt=False)
|
||||
self.assertTrue(passed)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user