mirror of
https://github.com/wassname/simpeg.git
synced 2026-09-13 13:03:14 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2fcdabf3d5 | ||
|
|
b965c96242 | ||
|
|
f06ba238f8 | ||
|
|
11408a3788 | ||
|
|
358e2f96af | ||
|
|
cf5181016f | ||
|
|
d1f7d0c37a | ||
|
|
50c4a6caf8 | ||
|
|
b3029b697b | ||
|
|
8d4581e92f | ||
|
|
0a44796d4c | ||
|
|
8117ee3b06 | ||
|
|
fb7f5a53d4 | ||
|
|
f34314bba2 | ||
|
|
7087632701 | ||
|
|
382b31bd12 | ||
|
|
6cc509020a | ||
|
|
f2e13182bf | ||
|
|
09cd9c7fa3 | ||
|
|
62eb4541cb | ||
|
|
09eb2106ec | ||
|
|
f8b86abd5a | ||
|
|
e476bf0059 | ||
|
|
825511e9d3 | ||
|
|
3b4bec9c0b | ||
|
|
022e1f7660 | ||
|
|
406703f1c6 | ||
|
|
7b72d3a92d | ||
|
|
cf89f5f6a2 | ||
|
|
aa1086eba3 | ||
|
|
1c53129da6 | ||
|
|
6fd3be77de | ||
|
|
51d82eee26 | ||
|
|
f6b49c680a | ||
|
|
339543b893 | ||
|
|
44ad57e90d | ||
|
|
d98eef2560 | ||
|
|
21d817d9a2 | ||
|
|
f20fcb4504 | ||
|
|
2c87a50d29 | ||
|
|
beca0203df | ||
|
|
e25b496ab0 | ||
|
|
e5ec512517 | ||
|
|
342414bd25 | ||
|
|
8936fa4021 | ||
|
|
0179631fe3 | ||
|
|
c4c97ae054 | ||
|
|
e8bd78f63d | ||
|
|
d0a65dda1b | ||
|
|
a506d5c6be | ||
|
|
10c8791514 | ||
|
|
c88263234b | ||
|
|
d5219be3d8 | ||
|
|
fd3bde787f | ||
|
|
3cc46131a3 | ||
|
|
cd2360b815 | ||
|
|
029171fb1d | ||
|
|
a690cab131 | ||
|
|
e10d6878fb | ||
|
|
3dd9ecc9cd | ||
|
|
90a3030796 | ||
|
|
c1b1c2467f | ||
|
|
11e6b452c9 | ||
|
|
7964ebce50 | ||
|
|
955bd54019 | ||
|
|
2a802c1aa3 | ||
|
|
6165e619ed | ||
|
|
3f0c89f10b | ||
|
|
eaa37f42e4 | ||
|
|
1ab67b5790 | ||
|
|
fb5434695f | ||
|
|
a96e9e08d7 | ||
|
|
b1569e5734 | ||
|
|
e037597ecd | ||
|
|
73c219ff5c | ||
|
|
abd919e862 | ||
|
|
6e00b4c2fe | ||
|
|
906cca30f3 | ||
|
|
8803956d83 | ||
|
|
0a714663d3 | ||
|
|
cb042ac938 | ||
|
|
f7c46ed83b | ||
|
|
52747c0926 | ||
|
|
d8eeb7cd05 | ||
|
|
8278230476 | ||
|
|
069127333d | ||
|
|
b4ab60c260 | ||
|
|
fbb8cf2731 | ||
|
|
79e1378009 | ||
|
|
0379df2bf2 | ||
|
|
66440b0478 | ||
|
|
dbdcc3cefb | ||
|
|
4e296c4cd5 | ||
|
|
c488dabf9a | ||
|
|
5e1de61a71 | ||
|
|
69ec374415 | ||
|
|
224105364d | ||
|
|
00bbe0f35e | ||
|
|
a7f89131b4 | ||
|
|
6e12bdc57a | ||
|
|
354e57f24e | ||
|
|
ddb11096c8 | ||
|
|
fa6033c438 | ||
|
|
dd45a6a085 | ||
|
|
bd63e67161 | ||
|
|
d350dc258d | ||
|
|
22f0a742e7 | ||
|
|
350818d802 | ||
|
|
ba8f270b3a | ||
|
|
4df6f340d3 | ||
|
|
9b2eec0ea3 | ||
|
|
3d1dfc13d7 | ||
|
|
a6e995e9fb | ||
|
|
056dc09fa6 | ||
|
|
4257ea77b3 | ||
|
|
a0174e4f30 | ||
|
|
00db6746d4 | ||
|
|
028a16a45a | ||
|
|
c83b460672 | ||
|
|
225394f74e | ||
|
|
ace9cad016 | ||
|
|
38aef03f9d | ||
|
|
ef602eaab1 | ||
|
|
0610289fdf | ||
|
|
d14cd444ac | ||
|
|
92e2fd67de | ||
|
|
6a064c5f96 | ||
|
|
f944f9b76b | ||
|
|
dcd4fbf973 | ||
|
|
edc2c5feb6 | ||
|
|
1936a04683 | ||
|
|
fcc2b8b22a | ||
|
|
eeee594f09 | ||
|
|
a48224ed8b | ||
|
|
0bb001973c | ||
|
|
f55d9573a6 | ||
|
|
d8bfb27415 | ||
|
|
0e16645b67 | ||
|
|
8cac166fba | ||
|
|
73001abfc5 | ||
|
|
a9362bd38e | ||
|
|
64b94861a0 | ||
|
|
8775364d8f | ||
|
|
5ec6e79a39 | ||
|
|
79183ae9fb | ||
|
|
606488d152 | ||
|
|
2c09be9fc1 | ||
|
|
cd5339322e | ||
|
|
28005dde45 | ||
|
|
8739ba0f20 | ||
|
|
119bc801c7 | ||
|
|
18357a11da | ||
|
|
abc5d72725 | ||
|
|
23d2783bc1 | ||
|
|
b58ba55ffd | ||
|
|
0d6fe5f7a1 | ||
|
|
35bac38c8b | ||
|
|
05e3b02b3a | ||
|
|
bd318f0092 | ||
|
|
90b0301408 | ||
|
|
083742cb40 | ||
|
|
2a351be971 | ||
|
|
3e4f47711c | ||
|
|
e305600de5 | ||
|
|
8a18e479ab | ||
|
|
d13c540be0 | ||
|
|
f15a628136 | ||
|
|
fb60f45a3c | ||
|
|
822f6d333d | ||
|
|
6000034826 | ||
|
|
16c6cc8d74 | ||
|
|
636d178fbf | ||
|
|
0575490f56 | ||
|
|
ae9ca6cec9 | ||
|
|
f799733a9d | ||
|
|
2bd5829b42 | ||
|
|
8b94cd4dfe | ||
|
|
09f3f7b55b | ||
|
|
15d59a5b50 | ||
|
|
e646211e7d | ||
|
|
ba977206ea | ||
|
|
fb1ff4e867 | ||
|
|
a31319b46e | ||
|
|
d8aec96080 | ||
|
|
aad596a8cc | ||
|
|
8d6bd65923 | ||
|
|
df620b42bd | ||
|
|
31d418bed8 | ||
|
|
6482b94cf1 | ||
|
|
7a6f4e0780 | ||
|
|
2ee158e5d7 | ||
|
|
8f73b2e7be | ||
|
|
16d62a6d0a | ||
|
|
5d9d746932 | ||
|
|
df3d32cb35 | ||
|
|
f59cfa9481 | ||
|
|
99ed4ad50e | ||
|
|
b531c162a2 | ||
|
|
a220c75d78 | ||
|
|
c7883673bf | ||
|
|
d8d8915f94 | ||
|
|
35c6d50db1 | ||
|
|
9c220ef37c | ||
|
|
0a0caceaca | ||
|
|
936a7aaadc | ||
|
|
44049bb48c | ||
|
|
009806f2ba | ||
|
|
1d208a8747 | ||
|
|
b6438688d8 | ||
|
|
824ce64c7e | ||
|
|
7aa5599211 | ||
|
|
fbec011983 | ||
|
|
5fb8cdb88c | ||
|
|
b765699d2f | ||
|
|
fdc081970e | ||
|
|
c66db805af | ||
|
|
579f1d7a65 | ||
|
|
c51afa4aad | ||
|
|
cc9d2e5ac7 | ||
|
|
055061ac3b | ||
|
|
d5f73d0fd3 | ||
|
|
3d11431f2f | ||
|
|
f92ff1301d | ||
|
|
d302a59b2c | ||
|
|
ef467efce0 | ||
|
|
d226186c8e | ||
|
|
38b4079f0b | ||
|
|
9d4e2488f3 | ||
|
|
838035adae | ||
|
|
ef4513bcd4 | ||
|
|
4fefccc97d | ||
|
|
127c51974f | ||
|
|
1946e1f69e | ||
|
|
e96945b991 | ||
|
|
fc444a345f | ||
|
|
9a739d8380 | ||
|
|
664a7bb484 | ||
|
|
33c9059e4e | ||
|
|
d9b3c038c4 | ||
|
|
2f8b8a36bf | ||
|
|
5e5c7ba0fb | ||
|
|
6c33455d15 | ||
|
|
7000699e38 | ||
|
|
63bf8b9e4d | ||
|
|
e3af1fd94e | ||
|
|
4e871a43a9 | ||
|
|
b5f4d8e999 | ||
|
|
e4a3e0a16d | ||
|
|
1c2fecf3a2 | ||
|
|
c10777a245 | ||
|
|
05a85018de | ||
|
|
8aa23c31de | ||
|
|
a9c9ce6bc8 | ||
|
|
6286e48830 | ||
|
|
4cf5d49524 | ||
|
|
88ef74ac38 | ||
|
|
3a506b9051 | ||
|
|
fa6bcd3ffa | ||
|
|
47895ef270 | ||
|
|
429d8b1191 | ||
|
|
774d612c18 | ||
|
|
433457f649 | ||
|
|
3eeb5dbd3c | ||
|
|
df78f7b33a |
+1
-1
@@ -35,7 +35,7 @@ before_install:
|
||||
|
||||
# Install packages
|
||||
install:
|
||||
- conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython nose vtk
|
||||
- conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython ipywidgets nose vtk
|
||||
- pip install nose-cov python-coveralls
|
||||
|
||||
- git clone https://github.com/rowanc1/pymatsolver.git
|
||||
|
||||
@@ -25,6 +25,10 @@ SimPEG
|
||||
:target: https://coveralls.io/r/simpeg/simpeg?branch=master
|
||||
:alt: Coverage status
|
||||
|
||||
.. image:: http://img.shields.io/badge/GITTER-JOIN_CHAT-brightgreen.svg?style=flat-square
|
||||
:alt: gitter chat room at https://gitter.im/simpeg/simpeg
|
||||
:target: https://gitter.im/simpeg/simpeg
|
||||
|
||||
Simulation and Parameter Estimation in Geophysics - A python package for simulation and gradient based parameter estimation in the context of geophysical applications.
|
||||
|
||||
The vision is to create a package for finite volume simulation with applications to geophysical imaging and subsurface flow. To enable the understanding of the many different components, this package has the following features:
|
||||
|
||||
+11
-13
@@ -200,11 +200,11 @@ class ProblemDC_CC(Problem.BaseProblem):
|
||||
|
||||
return F
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: Jv
|
||||
|
||||
@@ -225,11 +225,10 @@ class ProblemDC_CC(Problem.BaseProblem):
|
||||
# Set current model; clear dependent property $\mathbf{A(m)}$
|
||||
self.curModel = m
|
||||
sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
|
||||
if u is None:
|
||||
if f is None:
|
||||
# Run forward simulation if $u$ not provided
|
||||
u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol']
|
||||
else:
|
||||
u = u[self.survey.srcList, 'phi_sol']
|
||||
f = self.fields(self.curModel)
|
||||
u = f[self.survey.srcList, 'phi_sol']
|
||||
|
||||
D = self.mesh.faceDiv
|
||||
G = self.mesh.cellGrad
|
||||
@@ -251,19 +250,18 @@ class ProblemDC_CC(Problem.BaseProblem):
|
||||
if self.Ainv is None:
|
||||
self.Ainv = self.Solver(dA_du, **self.solverOpts)
|
||||
|
||||
P = self.survey.getP(self.mesh)
|
||||
P = self.survey.getP(self.mesh)
|
||||
Jv = - P * mkvc( self.Ainv * dCdm_x_v )
|
||||
return Jv
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
|
||||
self.curModel = m
|
||||
sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
|
||||
if u is None:
|
||||
# Run forward simulation if $u$ not provided
|
||||
u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol']
|
||||
else:
|
||||
u = u[self.survey.srcList, 'phi_sol']
|
||||
if f is None:
|
||||
# Run forward simulation if $f$ not provided
|
||||
f = self.fields(self.curModel)
|
||||
u = f[self.survey.srcList, 'phi_sol']
|
||||
|
||||
shp = u.shape
|
||||
P = self.survey.getP(self.mesh)
|
||||
|
||||
@@ -14,12 +14,12 @@ class SurveyIP(SurveyDC):
|
||||
Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
self._Ps = {}
|
||||
|
||||
def dpred(self, m, u=None):
|
||||
def dpred(self, m, f=None):
|
||||
"""
|
||||
Predicted data.
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = Pu(m)
|
||||
d_\\text{pred} = Pf(m)
|
||||
"""
|
||||
|
||||
return self.prob.forward(m)
|
||||
@@ -143,10 +143,10 @@ class ProblemIP(Problem.BaseProblem):
|
||||
J_x_v = - P * mkvc( self.Ainv * dCdm_x_v )
|
||||
return -J_x_v
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
return self.forward(v)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
|
||||
self.curModel = m
|
||||
# sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
|
||||
|
||||
+324
-215
@@ -1,12 +1,16 @@
|
||||
from SimPEG import np
|
||||
from SimPEG import np, Utils
|
||||
import BaseDC as DC
|
||||
import BaseDC as IP
|
||||
import warnings
|
||||
|
||||
def getActiveindfromTopo(mesh, topo):
|
||||
# def genActiveindfromTopo(mesh, topo):
|
||||
"""
|
||||
Get active indices from topography
|
||||
"""
|
||||
warnings.warn(
|
||||
"`getActiveindfromTopo` is deprecated and will be removed in future versions. Use `SimPEG.Utils.surface2ind_topo` instead",
|
||||
FutureWarning)
|
||||
from scipy.interpolate import NearestNDInterpolator
|
||||
if mesh.dim==3:
|
||||
nCxy = mesh.nCx*mesh.nCy
|
||||
@@ -28,6 +32,9 @@ def gettopoCC(mesh, airind):
|
||||
"""
|
||||
Get topography from active indices of mesh.
|
||||
"""
|
||||
warnings.warn(
|
||||
"`gettopoCC` is deprecated and will be removed in future versions. Use `SimPEG.Utils.surface2ind_topo` instead",
|
||||
FutureWarning)
|
||||
mesh2D = Mesh.TensorMesh([mesh.hx, mesh.hy], mesh.x0[:2])
|
||||
zc = mesh.gridCC[:,2]
|
||||
AIRIND = airind.reshape((mesh.vnC[0]*mesh.vnC[1],mesh.vnC[2]), order='F')
|
||||
@@ -118,34 +125,27 @@ def readUBC_DC3Dobstopo(filename,mesh,topo,probType="CC"):
|
||||
|
||||
def readUBC_DC2DModel(fileName):
|
||||
"""
|
||||
Read UBC GIF 2DTensor model and generate 2D Tensor model in simpeg
|
||||
Read UBC GIF 2DTensor model and generate 2D Tensor model in simpeg
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF 2D model file
|
||||
|
||||
Output:
|
||||
:param SimPEG TensorMesh 2D object
|
||||
:return
|
||||
|
||||
Created on Thu Nov 12 13:14:10 2015
|
||||
|
||||
@author: dominiquef
|
||||
:param string fileName: path to the UBC GIF 2D model file
|
||||
:rtype: TensorMesh
|
||||
:return: SimPEG TensorMesh 2D object
|
||||
|
||||
"""
|
||||
from SimPEG import np, mkvc
|
||||
|
||||
# Open fileand skip header... assume that we know the mesh already
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
|
||||
obsfile = np.genfromtxt(fileName, delimiter=' \n', dtype=np.str, comments='!')
|
||||
|
||||
dim = np.array(obsfile[0].split(),dtype=float)
|
||||
dim = np.array(obsfile[0].split(), dtype=float)
|
||||
|
||||
temp = np.array(obsfile[1].split(),dtype=float)
|
||||
temp = np.array(obsfile[1].split(), dtype=float)
|
||||
|
||||
if len(temp) > 1:
|
||||
model = np.zeros(dim)
|
||||
|
||||
for ii in range(len(obsfile)-1):
|
||||
mm = np.array(obsfile[ii+1].split(),dtype=float)
|
||||
mm = np.array(obsfile[ii+1].split(), dtype=float)
|
||||
model[:,ii] = mm
|
||||
|
||||
model = model[:,::-1]
|
||||
@@ -153,10 +153,10 @@ def readUBC_DC2DModel(fileName):
|
||||
else:
|
||||
|
||||
if len(obsfile[1:])==1:
|
||||
mm = np.array(obsfile[1:].split(),dtype=float)
|
||||
mm = np.array(obsfile[1:].split(), dtype=float)
|
||||
|
||||
else:
|
||||
mm = np.array(obsfile[1:],dtype=float)
|
||||
mm = np.array(obsfile[1:], dtype=float)
|
||||
|
||||
# Permute the second dimension to flip the order
|
||||
model = mm.reshape(dim[1],dim[0])
|
||||
@@ -169,32 +169,25 @@ def readUBC_DC2DModel(fileName):
|
||||
|
||||
return model
|
||||
|
||||
def plot_pseudoSection(DCsurvey, axs, stype):
|
||||
|
||||
def plot_pseudoSection(DCsurvey, axs, surveyType='dipole-dipole', unitType='volt', clim=None, cblabel=True, axlabel = True, colorbar = True, contour = None):
|
||||
"""
|
||||
Read list of 2D tx-rx location and plot a speudo-section of apparent
|
||||
resistivity.
|
||||
Read list of 2D tx-rx location and plot a speudo-section of apparent
|
||||
resistivity.
|
||||
|
||||
Assumes flat topo for now...
|
||||
Assumes flat topo for now...
|
||||
|
||||
Input:
|
||||
:param d2D, z0
|
||||
:switch stype -> Either 'pdp' (pole-dipole) | 'dpdp' (dipole-dipole)
|
||||
|
||||
Output:
|
||||
:figure scatter plot overlayed on image
|
||||
|
||||
Edited Feb 17th, 2016
|
||||
|
||||
@author: dominiquef
|
||||
:param SurveyDC DCsurvey:
|
||||
:param string surveyType: Either 'pole-dipole' | 'dipole-dipole'
|
||||
:param string unitType: Either 'appResistivity' | 'appConductivity' | 'volt'
|
||||
:rtype: matplotlib.plt
|
||||
:return: figure scatter plot overlayed on image
|
||||
|
||||
"""
|
||||
from SimPEG import np
|
||||
from scipy.interpolate import griddata
|
||||
import pylab as plt
|
||||
|
||||
# Set depth to 0 for now
|
||||
z0 = 0.
|
||||
|
||||
# Pre-allocate
|
||||
midx = []
|
||||
midz = []
|
||||
@@ -221,69 +214,117 @@ def plot_pseudoSection(DCsurvey, axs, stype):
|
||||
Cmid = (Tx[0][0] + Tx[1][0])/2
|
||||
Pmid = (Rx[0][:,0] + Rx[1][:,0])/2
|
||||
|
||||
# Compute pant leg of apparent rho
|
||||
if stype == 'pdp':
|
||||
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
|
||||
# Change output for unitType
|
||||
if unitType == 'volt':
|
||||
|
||||
leg = np.log10(abs(1/leg))
|
||||
rho = np.hstack([rho,data])
|
||||
|
||||
elif stype == 'dpdp':
|
||||
leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA )
|
||||
else:
|
||||
|
||||
# Compute pant leg of apparent rho
|
||||
if surveyType == 'pole-dipole':
|
||||
|
||||
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
|
||||
|
||||
elif surveyType == 'dipole-dipole':
|
||||
|
||||
leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA )
|
||||
|
||||
else:
|
||||
print """unitType must be 'pole-dipole' | 'dipole-dipole' """
|
||||
break
|
||||
|
||||
|
||||
if unitType == 'appConductivity':
|
||||
|
||||
leg = np.log10(abs(1./leg))
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
elif unitType == 'appResistivity':
|
||||
|
||||
leg = np.log10(abs(leg))
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
else:
|
||||
print """unitType must be 'appResistivity' | 'appConductivity' | 'volt' """
|
||||
break
|
||||
|
||||
midx = np.hstack([midx, ( Cmid + Pmid )/2 ])
|
||||
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ])
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
|
||||
ax = axs
|
||||
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + (Tx[0][2] + Tx[1][2])/2 ])
|
||||
|
||||
# Grid points
|
||||
grid_x, grid_z = np.mgrid[np.min(midx):np.max(midx), np.min(midz):np.max(midz)]
|
||||
grid_rho = griddata(np.c_[midx,midz], rho.T, (grid_x, grid_z), method='linear')
|
||||
|
||||
# Scale the color scheme
|
||||
if clim == None:
|
||||
vmin, vmax = rho.min(), rho.max()
|
||||
else:
|
||||
vmin, vmax = clim[0], clim[1]
|
||||
|
||||
plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin = np.min(rho), vmax = np.max(rho))
|
||||
cbar = plt.colorbar(format = '%.2f',fraction=0.04,orientation="horizontal")
|
||||
# Plot data
|
||||
grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho)
|
||||
|
||||
cmin,cmax = cbar.get_clim()
|
||||
ticks = np.linspace(cmin,cmax,3)
|
||||
cbar.set_ticks(ticks)
|
||||
|
||||
# Plot apparent resistivity
|
||||
plt.scatter(midx,midz,s=50,c=rho.T)
|
||||
|
||||
ax.set_xticklabels([])
|
||||
ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, vmin = vmin, vmax = vmax)
|
||||
plt.gca().tick_params(axis='both', which='major', labelsize=8)
|
||||
|
||||
if contour is not None:
|
||||
plt.contour(grid_x,grid_z,grid_rho,levels = contour,colors = 'r', vmin = vmin, vmax = vmax)
|
||||
|
||||
# Add scatter points
|
||||
axs.scatter(midx,midz,s=10,c=rho.T, vmin = vmin, vmax = vmax)
|
||||
|
||||
if colorbar:
|
||||
|
||||
if unitType == 'volt':
|
||||
cbar = plt.colorbar(ph, ax = axs, format="%4.1f",fraction=0.04,orientation="horizontal")
|
||||
|
||||
else:
|
||||
cbar = plt.colorbar(ph, ax = axs, format="$10^{%.1f}$",fraction=0.04,orientation="horizontal")
|
||||
|
||||
cmin,cmax = cbar.get_clim()
|
||||
ticks = np.linspace(cmin,cmax,3)
|
||||
cbar.set_ticks(ticks)
|
||||
cbar.ax.tick_params(labelsize=10)
|
||||
|
||||
if unitType == 'appConductivity':
|
||||
cbar.set_label("App.Cond",size=12)
|
||||
elif unitType == 'appResistivity':
|
||||
cbar.set_label("App.Res.",size=12)
|
||||
elif unitType == 'volt':
|
||||
cbar.set_label("Potential (V)",size=12)
|
||||
|
||||
|
||||
if not axlabel:
|
||||
axs.set_xticklabels([])
|
||||
axs.set_yticklabels([])
|
||||
|
||||
ax.set_ylabel('Z')
|
||||
ax.yaxis.tick_right()
|
||||
ax.yaxis.set_label_position('right')
|
||||
plt.gca().set_aspect('equal', adjustable='box')
|
||||
|
||||
|
||||
return ax
|
||||
|
||||
def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
return ph
|
||||
|
||||
def gen_DCIPsurvey(endl, mesh, surveyType, AM_sep, MN_sep, nrx):
|
||||
"""
|
||||
Load in endpoints and survey specifications to generate Tx, Rx location
|
||||
stations.
|
||||
Load in endpoints and survey specifications to generate Tx, Rx location
|
||||
stations.
|
||||
|
||||
Assumes flat topo for now...
|
||||
Assumes flat topo for now...
|
||||
|
||||
Input:
|
||||
:param endl -> input endpoints [x1, y1, z1, x2, y2, z2]
|
||||
:object mesh -> SimPEG mesh object
|
||||
:switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient'
|
||||
: param a, n -> pole seperation, number of rx dipoles per tx
|
||||
:param numpy.array endl: input endpoints [[x1, y1] , [x2, y2]]
|
||||
:param Mesh mesh: SimPEG mesh object
|
||||
:param string surveyType: 'dipole-dipole' | 'pole-dipole' | 'gradient'
|
||||
:param float AM_sep: transmitter (A) - receiver (M) seperation
|
||||
:param float b: receiver dipole seperation
|
||||
:param float nrx: pole seperation, number of rx dipoles per tx
|
||||
|
||||
Output:
|
||||
:param Tx, Rx -> List objects for each tx location
|
||||
Lines: P1x, P1y, P1z, P2x, P2y, P2z
|
||||
:rtype: DC.Survey, Src, Rx
|
||||
:returns: DC survey, Source
|
||||
|
||||
Created on Wed December 9th, 2015
|
||||
|
||||
@author: dominiquef
|
||||
!! Require clean up to deal with DCsurvey
|
||||
!! Require clean up to deal with DCsurvey
|
||||
"""
|
||||
|
||||
from SimPEG import np
|
||||
@@ -299,17 +340,17 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
dl_x = ( endl[1,0] - endl[0,0] ) / dl_len
|
||||
dl_y = ( endl[1,1] - endl[0,1] ) / dl_len
|
||||
|
||||
nstn = np.floor( dl_len / a )
|
||||
nstn = np.floor( dl_len / AM_sep )
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a
|
||||
stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*AM_sep
|
||||
stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*AM_sep
|
||||
|
||||
# Create line of P1 locations
|
||||
M = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
# Create line of P2 locations
|
||||
N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
N = np.c_[stn_x+AM_sep*dl_x, stn_y+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
## Build list of Tx-Rx locations depending on survey type
|
||||
# Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn]
|
||||
@@ -319,14 +360,14 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
SrcList = []
|
||||
|
||||
|
||||
if stype != 'gradient':
|
||||
if surveyType != 'gradient':
|
||||
|
||||
for ii in range(0, int(nstn)-1):
|
||||
|
||||
|
||||
if stype == 'dpdp':
|
||||
if surveyType == 'dipole-dipole':
|
||||
tx = np.c_[M[ii,:],N[ii,:]]
|
||||
elif stype == 'pdp':
|
||||
elif surveyType == 'pole-dipole':
|
||||
tx = np.c_[M[ii,:],M[ii,:]]
|
||||
|
||||
# Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]])
|
||||
@@ -335,43 +376,33 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1])
|
||||
|
||||
# Number of receivers to fit
|
||||
nstn = np.min([np.floor( (AB - b) / a ) , n])
|
||||
nstn = np.min([np.floor( (AB - MN_sep) / AM_sep ) , nrx])
|
||||
|
||||
# Check if there is enough space, else break the loop
|
||||
if nstn <= 0:
|
||||
continue
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a
|
||||
stn_x = N[ii,0] + dl_x*MN_sep + np.array(range(int(nstn)))*dl_x*AM_sep
|
||||
stn_y = N[ii,1] + dl_y*MN_sep + np.array(range(int(nstn)))*dl_y*AM_sep
|
||||
|
||||
# Create receiver poles
|
||||
# Create line of P1 locations
|
||||
P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
# Create line of P2 locations
|
||||
P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
P2 = np.c_[stn_x+AM_sep*dl_x, stn_y+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
Rx.append(np.c_[P1,P2])
|
||||
rxClass = DC.RxDipole(P1, P2)
|
||||
Tx.append(tx)
|
||||
if stype == 'dpdp':
|
||||
if surveyType == 'dipole-dipole':
|
||||
srcClass = DC.SrcDipole([rxClass], M[ii,:],N[ii,:])
|
||||
elif stype == 'pdp':
|
||||
elif surveyType == 'pole-dipole':
|
||||
srcClass = DC.SrcDipole([rxClass], M[ii,:],M[ii,:])
|
||||
SrcList.append(srcClass)
|
||||
|
||||
#==============================================================================
|
||||
# elif re.match(stype,'dpdp'):
|
||||
#
|
||||
# for ii in range(0, int(nstn)-2):
|
||||
#
|
||||
# indx = np.min([ii+n+1,nstn])
|
||||
# Tx.append(np.c_[M[ii,:],N[ii,:]])
|
||||
# Rx.append(np.c_[M[ii+2:indx,:],N[ii+2:indx,:]])
|
||||
#==============================================================================
|
||||
|
||||
elif stype == 'gradient':
|
||||
elif surveyType == 'gradient':
|
||||
|
||||
# Gradient survey only requires Tx at end of line and creates a square
|
||||
# grid of receivers at in the middle at a pre-set minimum distance
|
||||
@@ -379,23 +410,23 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
Tx.append(np.c_[M[0,:],N[-1,:]])
|
||||
|
||||
# Get the edge limit of survey area
|
||||
min_x = endl[0,0] + dl_x * b
|
||||
min_y = endl[0,1] + dl_y * b
|
||||
min_x = endl[0,0] + dl_x * MN_sep
|
||||
min_y = endl[0,1] + dl_y * MN_sep
|
||||
|
||||
max_x = endl[1,0] - dl_x * b
|
||||
max_y = endl[1,1] - dl_y * b
|
||||
max_x = endl[1,0] - dl_x * MN_sep
|
||||
max_y = endl[1,1] - dl_y * MN_sep
|
||||
|
||||
box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 )
|
||||
box_w = box_l/2.
|
||||
|
||||
nstn = np.floor( box_l / a )
|
||||
nstn = np.floor( box_l / AM_sep )
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = min_x + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = min_y + np.array(range(int(nstn)))*dl_y*a
|
||||
stn_x = min_x + np.array(range(int(nstn)))*dl_x*AM_sep
|
||||
stn_y = min_y + np.array(range(int(nstn)))*dl_y*AM_sep
|
||||
|
||||
# Define number of cross lines
|
||||
nlin = int(np.floor( box_w / a ))
|
||||
nlin = int(np.floor( box_w / AM_sep ))
|
||||
lind = range(-nlin,nlin+1)
|
||||
|
||||
ngrad = nstn * len(lind)
|
||||
@@ -404,12 +435,12 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
for ii in range( len(lind) ):
|
||||
|
||||
# Move line in perpendicular direction by dipole spacing
|
||||
lxx = stn_x - lind[ii]*a*dl_y
|
||||
lyy = stn_y + lind[ii]*a*dl_x
|
||||
lxx = stn_x - lind[ii]*AM_sep*dl_y
|
||||
lyy = stn_y + lind[ii]*AM_sep*dl_x
|
||||
|
||||
|
||||
M = np.c_[ lxx, lyy , np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
N = np.c_[ lxx+AM_sep*dl_x, lyy+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N]
|
||||
|
||||
@@ -418,37 +449,37 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
srcClass = DC.SrcDipole([rxClass], M[0,:], N[-1,:])
|
||||
SrcList.append(srcClass)
|
||||
else:
|
||||
print """stype must be either 'pdp', 'dpdp' or 'gradient'. """
|
||||
print """surveyType must be either 'pole-dipole', 'dipole-dipole' or 'gradient'. """
|
||||
|
||||
survey = DC.SurveyDC(SrcList)
|
||||
return survey, Tx, Rx
|
||||
|
||||
def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
|
||||
|
||||
def writeUBC_DCobs(fileName, DCsurvey, dim, surveyType, iptype = 0):
|
||||
"""
|
||||
Write UBC GIF DCIP 2D or 3D observation file
|
||||
|
||||
Input:
|
||||
:string fileName -> including path where the file is written out
|
||||
:DCsurvey -> DC survey class object
|
||||
:string dtype -> either '2D' | '3D'
|
||||
:string stype -> either 'SURFACE' | 'GENERAL'
|
||||
|
||||
Output:
|
||||
:param UBC2D-Data file
|
||||
:return
|
||||
|
||||
Last edit: February 16th, 2016
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
:param string fileName: including path where the file is written out
|
||||
:param Survey DCsurvey: DC survey class object
|
||||
:param string dim: either '2D' | '3D'
|
||||
:param string surveyType: either 'SURFACE' | 'GENERAL'
|
||||
:rtype: file
|
||||
:return: UBC2D-Data file
|
||||
"""
|
||||
|
||||
from SimPEG import mkvc
|
||||
|
||||
assert (dtype=='2D') | (dtype=='3D'), "Data must be either '2D' | '3D'"
|
||||
assert (stype=='SURFACE') | (stype=='GENERAL') | (stype=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'"
|
||||
assert (dim=='2D') | (dim=='3D'), "Data must be either '2D' | '3D'"
|
||||
assert (surveyType=='SURFACE') | (surveyType=='GENERAL') | (surveyType=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'"
|
||||
|
||||
fid = open(fileName,'w')
|
||||
fid.write('! ' + stype + ' FORMAT\n')
|
||||
fid.write('! ' + surveyType + ' FORMAT\n')
|
||||
|
||||
if iptype!=0:
|
||||
fid.write('IPTYPE=%i\n'%iptype)
|
||||
|
||||
else:
|
||||
fid.write('! ' + stype + ' FORMAT\n')
|
||||
|
||||
count = 0
|
||||
|
||||
@@ -463,10 +494,10 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
|
||||
M = rx[0]
|
||||
N = rx[1]
|
||||
|
||||
# Adapt source-receiver location for dtype and stype
|
||||
if dtype=='2D':
|
||||
# Adapt source-receiver location for dim and surveyType
|
||||
if dim=='2D':
|
||||
|
||||
if stype == 'SIMPLE':
|
||||
if surveyType == 'SIMPLE':
|
||||
|
||||
#fid.writelines("%e " % ii for ii in mkvc(tx[0,:]))
|
||||
A = np.repeat(tx[0,0],M.shape[0],axis=0)
|
||||
@@ -479,58 +510,60 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
|
||||
|
||||
else:
|
||||
|
||||
if stype == 'SURFACE':
|
||||
if surveyType == 'SURFACE':
|
||||
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx[0,:]))
|
||||
fid.writelines("%f " % ii for ii in mkvc(tx[0,:]))
|
||||
M = M[:,0]
|
||||
N = N[:,0]
|
||||
|
||||
if stype == 'GENERAL':
|
||||
if surveyType == 'GENERAL':
|
||||
|
||||
# Flip sign for z-elevation to depth
|
||||
tx[2::2,:] = -tx[2::2,:]
|
||||
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx[::2,:]))
|
||||
M = M[:,0::2]
|
||||
N = N[:,0::2]
|
||||
|
||||
# Flip sign for z-elevation to depth
|
||||
M[:,1::2] = -M[:,1::2]
|
||||
N[:,1::2] = -N[:,1::2]
|
||||
|
||||
fid.write('%i\n'% nD)
|
||||
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n')
|
||||
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%f',delimiter=' ',newline='\n')
|
||||
|
||||
if dtype=='3D':
|
||||
if dim=='3D':
|
||||
|
||||
if stype == 'SURFACE':
|
||||
if surveyType == 'SURFACE':
|
||||
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx[0:2,:]))
|
||||
M = M[:,0:2]
|
||||
N = N[:,0:2]
|
||||
|
||||
if stype == 'GENERAL':
|
||||
if surveyType == 'GENERAL':
|
||||
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx))
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx[0:3,:]))
|
||||
|
||||
fid.write('%i\n'% nD)
|
||||
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n')
|
||||
fid.write('\n')
|
||||
|
||||
count += nD
|
||||
|
||||
fid.close()
|
||||
|
||||
def convertObs_DC3D_to_2D(DCsurvey,lineID):
|
||||
def convertObs_DC3D_to_2D(DCsurvey, lineID, flag='local'):
|
||||
"""
|
||||
Read DC survey and data and change
|
||||
coordinate system to distance along line assuming
|
||||
all data is acquired along line.
|
||||
First transmitter pole is assumed to be at the origin
|
||||
Read DC survey and projects the coordinate system
|
||||
according to the flag = 'Xloc' | 'Yloc' | 'local' (default)
|
||||
In the 'local' system, station coordinates are referenced
|
||||
to distance from the first srcLoc[0].loc[0]
|
||||
|
||||
Assumes flat topo for now...
|
||||
The Z value is preserved, but Y coordinates zeroed.
|
||||
|
||||
Input:
|
||||
:param Tx, Rx
|
||||
|
||||
Output:
|
||||
:figure Tx2d, Rx2d
|
||||
|
||||
Edited Feb 17th, 2016
|
||||
|
||||
@author: dominiquef
|
||||
:param DC.Survey survey3D: 3D simpeg DC survey
|
||||
:rtype: DC.Survey
|
||||
:return: survey2D
|
||||
|
||||
"""
|
||||
from SimPEG import np
|
||||
@@ -570,25 +603,39 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID):
|
||||
Rx = DCsurvey.srcList[indx[ii]].rxList[0].locs
|
||||
nrx = Rx[0].shape[0]
|
||||
|
||||
# Find A electrode along line
|
||||
vec, r = r_unit(x0,Tx[ii][0,0:2])
|
||||
A = stn_id(vecTx,vec,r)
|
||||
if flag == 'local':
|
||||
# Find A electrode along line
|
||||
vec, r = r_unit(x0,Tx[ii][0,0:2])
|
||||
A = stn_id(vecTx,vec,r)
|
||||
|
||||
# Find B electrode along line
|
||||
vec, r = r_unit(x0,Tx[ii][1,0:2])
|
||||
B = stn_id(vecTx,vec,r)
|
||||
# Find B electrode along line
|
||||
vec, r = r_unit(x0,Tx[ii][1,0:2])
|
||||
B = stn_id(vecTx,vec,r)
|
||||
|
||||
M = np.zeros(nrx)
|
||||
N = np.zeros(nrx)
|
||||
for kk in range(nrx):
|
||||
M = np.zeros(nrx)
|
||||
N = np.zeros(nrx)
|
||||
for kk in range(nrx):
|
||||
|
||||
# Find all M electrodes along line
|
||||
vec, r = r_unit(x0,Rx[0][kk,0:2])
|
||||
M[kk] = stn_id(vecTx,vec,r)
|
||||
# Find all M electrodes along line
|
||||
vec, r = r_unit(x0,Rx[0][kk,0:2])
|
||||
M[kk] = stn_id(vecTx,vec,r)
|
||||
|
||||
# Find all N electrodes along line
|
||||
vec, r = r_unit(x0,Rx[1][kk,0:2])
|
||||
N[kk] = stn_id(vecTx,vec,r)
|
||||
# Find all N electrodes along line
|
||||
vec, r = r_unit(x0,Rx[1][kk,0:2])
|
||||
N[kk] = stn_id(vecTx,vec,r)
|
||||
elif flag == 'Yloc':
|
||||
""" Flip the XY axis locs"""
|
||||
A = Tx[ii][0,1]
|
||||
B = Tx[ii][1,1]
|
||||
M = Rx[0][:,1]
|
||||
N = Rx[1][:,1]
|
||||
|
||||
elif flag == 'Xloc':
|
||||
""" Copy the rx-tx locs"""
|
||||
A = Tx[ii][0,0]
|
||||
B = Tx[ii][1,0]
|
||||
M = Rx[0][:,0]
|
||||
N = Rx[1][:,0]
|
||||
|
||||
Rx = DC.RxDipole(np.c_[M,np.zeros(nrx),Rx[0][:,2]],np.c_[N,np.zeros(nrx),Rx[1][:,2]])
|
||||
|
||||
@@ -602,50 +649,53 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID):
|
||||
|
||||
return DCsurvey2D
|
||||
|
||||
def readUBC_DC3Dobs(fileName):
|
||||
def readUBC_DC3Dobs(fileName, rtype = 'DC'):
|
||||
"""
|
||||
Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location
|
||||
Read UBC GIF IP 3D observation file and generate survey
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF 3D obs file
|
||||
|
||||
Output:
|
||||
:param rx, tx, d, wd
|
||||
:return
|
||||
|
||||
Created on Mon December 7th, 2015
|
||||
|
||||
@author: dominiquef
|
||||
:param string fileName:, path to the UBC GIF 3D obs file
|
||||
:rtype: Survey
|
||||
:return: DCIPsurvey
|
||||
|
||||
"""
|
||||
zflag = True # Flag for z value provided
|
||||
|
||||
# Load file
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
|
||||
if rtype == 'IP':
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='IPTYPE')
|
||||
|
||||
elif rtype == 'DC':
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
|
||||
|
||||
else:
|
||||
print "rtype must be 'DC'(default) | 'IP'"
|
||||
|
||||
# Pre-allocate
|
||||
srcLists = []
|
||||
Rx = []
|
||||
d = []
|
||||
wd = []
|
||||
zflag = True # Flag for z value provided
|
||||
|
||||
|
||||
# Countdown for number of obs/tx
|
||||
count = 0
|
||||
for ii in range(obsfile.shape[0]):
|
||||
|
||||
# Skip if blank line
|
||||
if not obsfile[ii]:
|
||||
continue
|
||||
|
||||
# First line is transmitter with number of receivers
|
||||
# First line or end of a transmitter block, read transmitter info
|
||||
if count==0:
|
||||
|
||||
temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T)
|
||||
# Read the line
|
||||
temp = (np.fromstring(obsfile[ii], dtype=float, sep=' ').T)
|
||||
count = int(temp[-1])
|
||||
|
||||
# Check if z value is provided, if False -> nan
|
||||
if len(temp)==5:
|
||||
tx = np.r_[temp[0:2],np.nan,temp[0:2],np.nan]
|
||||
zflag = False
|
||||
tx = np.r_[temp[0:2],np.nan,temp[2:4],np.nan]
|
||||
|
||||
zflag = False # Pass on the flag to the receiver loc
|
||||
|
||||
else:
|
||||
tx = temp[:-1]
|
||||
@@ -653,8 +703,16 @@ def readUBC_DC3Dobs(fileName):
|
||||
rx = []
|
||||
continue
|
||||
|
||||
temp = np.fromstring(obsfile[ii], dtype=float,sep=' ')
|
||||
temp = np.fromstring(obsfile[ii], dtype=float,sep=' ') # Get the string
|
||||
|
||||
# Filter out negative IP
|
||||
# if temp[-2] < 0:
|
||||
# count = count -1
|
||||
# print "Negative!"
|
||||
#
|
||||
# else:
|
||||
|
||||
# If the Z-location is provided, otherwise put nan
|
||||
if zflag:
|
||||
|
||||
rx.append(temp[:-2])
|
||||
@@ -664,7 +722,7 @@ def readUBC_DC3Dobs(fileName):
|
||||
wd.append(temp[-1])
|
||||
|
||||
else:
|
||||
rx.append(np.r_[temp[0:2],np.nan,temp[0:2],np.nan] )
|
||||
rx.append(np.r_[temp[0:2],np.nan,temp[2:4],np.nan] )
|
||||
# Check if there is data with the location
|
||||
if len(temp)==6:
|
||||
d.append(temp[-2])
|
||||
@@ -672,7 +730,7 @@ def readUBC_DC3Dobs(fileName):
|
||||
|
||||
count = count -1
|
||||
|
||||
# Reach the end of transmitter block
|
||||
# Reach the end of transmitter block, append the src, rx and continue
|
||||
if count == 0:
|
||||
rx = np.asarray(rx)
|
||||
Rx = DC.RxDipole(rx[:,:3],rx[:,3:])
|
||||
@@ -688,19 +746,12 @@ def readUBC_DC3Dobs(fileName):
|
||||
|
||||
def readUBC_DC2Dobs(fileName):
|
||||
"""
|
||||
------- NEEDS TO BE UPDATED ------
|
||||
Read UBC GIF 2D observation file and generate arrays for tx-rx location
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF 2D model file
|
||||
|
||||
Output:
|
||||
:param rx, tx
|
||||
:return
|
||||
|
||||
Created on Thu Nov 12 13:14:10 2015
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
:param string fileName: path to the UBC GIF 2D model file
|
||||
:rtype: (DC.Src, DC.Rx, ??, ??)
|
||||
:return: source_locs, rx_locs, ??, ??
|
||||
"""
|
||||
|
||||
from SimPEG import np
|
||||
@@ -735,16 +786,78 @@ def readUBC_DC2Dobs(fileName):
|
||||
|
||||
return tx, rx, d, wd
|
||||
|
||||
def readUBC_DC2Dpre(fileName):
|
||||
"""
|
||||
Read UBC GIF DCIP 2D observation file and generate arrays for tx-rx location
|
||||
|
||||
Input:
|
||||
:param string fileName: path to the UBC GIF 3D obs file
|
||||
:rtype: DC.Survey
|
||||
:return: DCsurvey
|
||||
|
||||
Created on Mon March 9th, 2016 << Doug's 70th Birthday !! >>
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
"""
|
||||
|
||||
# Load file
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
|
||||
|
||||
# Pre-allocate
|
||||
srcLists = []
|
||||
Rx = []
|
||||
d = []
|
||||
zflag = True # Flag for z value provided
|
||||
|
||||
for ii in range(obsfile.shape[0]):
|
||||
|
||||
if not obsfile[ii]:
|
||||
continue
|
||||
|
||||
# First line is transmitter with number of receivers
|
||||
|
||||
|
||||
temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T)
|
||||
|
||||
|
||||
# Check if z value is provided, if False -> nan
|
||||
if len(temp)==5:
|
||||
tx = np.r_[temp[0],np.nan,np.nan,temp[1],np.nan,np.nan]
|
||||
zflag = False
|
||||
|
||||
else:
|
||||
tx = np.r_[temp[0],np.nan,temp[1],temp[2],np.nan,temp[3]]
|
||||
|
||||
|
||||
if zflag:
|
||||
rx = np.c_[temp[4],np.nan,temp[5],temp[6],np.nan,temp[7]]
|
||||
|
||||
|
||||
else:
|
||||
rx = np.c_[temp[2],np.nan,np.nan,temp[3],np.nan,np.nan]
|
||||
# Check if there is data with the location
|
||||
|
||||
d.append(temp[-1])
|
||||
|
||||
|
||||
Rx = DC.RxDipole(rx[:,:3],rx[:,3:])
|
||||
srcLists.append( DC.SrcDipole( [Rx], tx[:3],tx[3:]) )
|
||||
|
||||
# Create survey class
|
||||
survey = DC.SurveyDC(srcLists)
|
||||
|
||||
survey.dobs = np.asarray(d)
|
||||
|
||||
return {'DCsurvey':survey}
|
||||
|
||||
def readUBC_DC2DMesh(fileName):
|
||||
"""
|
||||
Read UBC GIF 2DTensor mesh and generate 2D Tensor mesh in simpeg
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF mesh file
|
||||
|
||||
Output:
|
||||
:param SimPEG TensorMesh 2D object
|
||||
:return
|
||||
:param string fileName: path to the UBC GIF mesh file
|
||||
:rtype: Mesh.TensorMesh
|
||||
:return: SimPEG TensorMesh 2D object
|
||||
|
||||
Created on Thu Nov 12 13:14:10 2015
|
||||
|
||||
@@ -810,12 +923,9 @@ def xy_2_lineID(DCsurvey):
|
||||
they were collected. May need to generalize for random
|
||||
point locations, but will be more expensive
|
||||
|
||||
Input:
|
||||
:param DCdict Vectors of station location
|
||||
|
||||
Output:
|
||||
:param LineID Vector of integers
|
||||
:return
|
||||
:param numpy.array DCdict: Vectors of station location
|
||||
:rtype: numpy.array
|
||||
:return: LineID Vector of integers
|
||||
|
||||
Created on Thu Feb 11, 2015
|
||||
|
||||
@@ -928,7 +1038,6 @@ def getSrc_locs(DCsurvey):
|
||||
|
||||
srcMat = np.zeros((DCsurvey.nSrc,2,3))
|
||||
for ii in range(DCsurvey.nSrc):
|
||||
print np.asarray(DCsurvey.srcList[ii].loc).shape
|
||||
srcMat[ii,:,:] = np.asarray(DCsurvey.srcList[ii].loc)
|
||||
|
||||
return srcMat
|
||||
|
||||
+22
-26
@@ -22,11 +22,11 @@ class BaseDataMisfit(object):
|
||||
Utils.setKwargs(self,**kwargs)
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m, u=None):
|
||||
"""eval(m, u=None)
|
||||
def eval(self, m, f=None):
|
||||
"""eval(m, f=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: float
|
||||
:return: data misfit
|
||||
|
||||
@@ -34,11 +34,11 @@ class BaseDataMisfit(object):
|
||||
raise NotImplementedError('This method should be overwritten.')
|
||||
|
||||
@Utils.timeIt
|
||||
def evalDeriv(self, m, u=None):
|
||||
"""evalDeriv(m, u=None)
|
||||
def evalDeriv(self, m, f=None):
|
||||
"""evalDeriv(m, f=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: data misfit derivative
|
||||
|
||||
@@ -47,12 +47,12 @@ class BaseDataMisfit(object):
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def eval2Deriv(self, m, v, u=None):
|
||||
"""eval2Deriv(m, v, u=None)
|
||||
def eval2Deriv(self, m, v, f=None):
|
||||
"""eval2Deriv(m, v, f=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: data misfit derivative
|
||||
|
||||
@@ -89,7 +89,7 @@ class l2_DataMisfit(BaseDataMisfit):
|
||||
"""
|
||||
|
||||
if getattr(self, '_Wd', None) is None:
|
||||
|
||||
|
||||
survey = self.survey
|
||||
|
||||
if getattr(survey,'std', None) is None:
|
||||
@@ -108,24 +108,20 @@ class l2_DataMisfit(BaseDataMisfit):
|
||||
self._Wd = value
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m, u=None):
|
||||
"eval(m, u=None)"
|
||||
prob = self.prob
|
||||
survey = self.survey
|
||||
R = self.Wd * survey.residual(m, u=u)
|
||||
def eval(self, m, f=None):
|
||||
"eval(m, f=None)"
|
||||
if f is None: f = self.prob.fields(m)
|
||||
R = self.Wd * self.survey.residual(m, f)
|
||||
return 0.5*np.vdot(R, R)
|
||||
|
||||
@Utils.timeIt
|
||||
def evalDeriv(self, m, u=None):
|
||||
"evalDeriv(m, u=None)"
|
||||
prob = self.prob
|
||||
survey = self.survey
|
||||
if u is None: u = prob.fields(m)
|
||||
return prob.Jtvec(m, self.Wd * (self.Wd * survey.residual(m, u=u)), u=u)
|
||||
def evalDeriv(self, m, f=None):
|
||||
"evalDeriv(m, f=None)"
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return self.prob.Jtvec(m, self.Wd * (self.Wd * self.survey.residual(m, f=f)), f=f)
|
||||
|
||||
@Utils.timeIt
|
||||
def eval2Deriv(self, m, v, u=None):
|
||||
"eval2Deriv(m, v, u=None)"
|
||||
prob = self.prob
|
||||
if u is None: u = prob.fields(m)
|
||||
return prob.Jtvec_approx(m, self.Wd * (self.Wd * prob.Jvec_approx(m, v, u=u)), u=u)
|
||||
def eval2Deriv(self, m, v, f=None):
|
||||
"eval2Deriv(m, v, f=None)"
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return self.prob.Jtvec_approx(m, self.Wd * (self.Wd * self.prob.Jvec_approx(m, v, f=f)), f=f)
|
||||
|
||||
+204
-59
@@ -123,10 +123,10 @@ class BetaEstimate_ByEig(InversionDirective):
|
||||
if self.debug: print 'Calculating the beta0 parameter.'
|
||||
|
||||
m = self.invProb.curModel
|
||||
u = self.invProb.getFields(m, store=True, deleteWarmstart=False)
|
||||
f = self.invProb.getFields(m, store=True, deleteWarmstart=False)
|
||||
|
||||
x0 = np.random.rand(*m.shape)
|
||||
t = x0.dot(self.dmisfit.eval2Deriv(m,x0,u=u))
|
||||
t = x0.dot(self.dmisfit.eval2Deriv(m,x0,f=f))
|
||||
b = x0.dot(self.reg.eval2Deriv(m, v=x0))
|
||||
self.beta0 = self.beta0_ratio*(t/b)
|
||||
|
||||
@@ -144,12 +144,18 @@ class BetaSchedule(InversionDirective):
|
||||
if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter
|
||||
self.invProb.beta /= self.coolingFactor
|
||||
|
||||
|
||||
class TargetMisfit(InversionDirective):
|
||||
|
||||
chifact = 1.
|
||||
phi_d_star = None
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
if getattr(self, '_target', None) is None:
|
||||
self._target = self.survey.nD*0.5
|
||||
if self.phi_d_star is None:
|
||||
self.phi_d_star = 0.5 * self.survey.nD
|
||||
self._target = self.chifact * self.phi_d_star # the factor of 0.5 is because we do phid = 0.5*|| dpred - dobs||^2
|
||||
return self._target
|
||||
@target.setter
|
||||
def target(self, val):
|
||||
@@ -207,79 +213,218 @@ class SaveOutputEveryIteration(_SaveEveryIteration):
|
||||
f.close()
|
||||
|
||||
class SaveOutputDictEveryIteration(_SaveEveryIteration):
|
||||
"""SaveOutputDictEveryIteration"""
|
||||
"""
|
||||
Saves inversion parameters at every iteraion.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def initialize(self):
|
||||
print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '###-%s.npz'"%self.fileName
|
||||
|
||||
def endIter(self):
|
||||
# Save the data.
|
||||
ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) )
|
||||
phi_ms = 0.5*ms.dot(ms)
|
||||
if self.reg.smoothModel == True:
|
||||
mref = self.reg.mref
|
||||
else:
|
||||
mref = 0
|
||||
mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_mx = 0.5 * mx.dot(mx)
|
||||
if self.prob.mesh.dim==2:
|
||||
my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_my = 0.5 * my.dot(my)
|
||||
else:
|
||||
phi_my = 'NaN'
|
||||
if self.prob.mesh.dim==3:
|
||||
mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_mz = 0.5 * mz.dot(mz)
|
||||
else:
|
||||
phi_mz = 'NaN'
|
||||
|
||||
# Initialize the output dict
|
||||
outDict = {}
|
||||
# Save the data.
|
||||
outDict['iter'] = self.opt.iter
|
||||
outDict['beta'] = self.invProb.beta
|
||||
outDict['phi_d'] = self.invProb.phi_d
|
||||
outDict['phi_ms'] = self.reg._evalSmall(self.invProb.curModel)
|
||||
outDict['phi_mx'] = self.reg._evalSmoothx(self.invProb.curModel)
|
||||
outDict['phi_my'] = self.reg._evalSmoothy(self.invProb.curModel) if self.prob.mesh.dim >= 2 else 'NaN'
|
||||
outDict['phi_mz'] = self.reg._evalSmoothz(self.invProb.curModel) if self.prob.mesh.dim==3 else 'NaN'
|
||||
outDict['f'] = self.opt.f
|
||||
outDict['m'] = self.invProb.curModel
|
||||
outDict['dpred'] = self.invProb.dpred
|
||||
|
||||
# Save the file as a npz
|
||||
np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred)
|
||||
np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), outDict)
|
||||
|
||||
class SaveOutputDictEveryIteration(_SaveEveryIteration):
|
||||
"""SaveOutputDictEveryIteration
|
||||
A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info).
|
||||
"""
|
||||
class Update_IRLS(InversionDirective):
|
||||
|
||||
eps_min = None
|
||||
eps_p = None
|
||||
eps_q = None
|
||||
norms = [2.,2.,2.,2.]
|
||||
factor = None
|
||||
gamma = None
|
||||
phi_m_last = None
|
||||
phi_d_last = None
|
||||
f_old = None
|
||||
f_min_change = 1e-2
|
||||
beta_tol = 5e-2
|
||||
|
||||
# Solving parameter for IRLS (mode:2)
|
||||
IRLSiter = 0
|
||||
minGNiter = 5
|
||||
maxIRLSiter = 10
|
||||
iterStart = 0
|
||||
|
||||
# Beta schedule
|
||||
coolingFactor = 2.
|
||||
coolingRate = 1
|
||||
|
||||
mode = 1
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
if getattr(self, '_target', None) is None:
|
||||
self._target = self.survey.nD*0.5
|
||||
return self._target
|
||||
@target.setter
|
||||
def target(self, val):
|
||||
self._target = val
|
||||
|
||||
def initialize(self):
|
||||
print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName
|
||||
|
||||
if self.mode == 1:
|
||||
self.reg.norms = [2., 2., 2., 2.]
|
||||
|
||||
def endIter(self):
|
||||
# Save the data.
|
||||
ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) )
|
||||
phi_ms = 0.5*ms.dot(ms)
|
||||
if self.reg.smoothModel == True:
|
||||
mref = self.reg.mref
|
||||
else:
|
||||
mref = 0
|
||||
mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_mx = 0.5 * mx.dot(mx)
|
||||
if self.prob.mesh.dim==2:
|
||||
my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_my = 0.5 * my.dot(my)
|
||||
else:
|
||||
phi_my = 'NaN'
|
||||
if self.prob.mesh.dim==3 and 'CYL' not in self.prob.mesh._meshType:
|
||||
mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_mz = 0.5 * mz.dot(mz)
|
||||
else:
|
||||
phi_mz = 'NaN'
|
||||
|
||||
# After reaching target misfit with l2-norm, switch to IRLS (mode:2)
|
||||
if self.invProb.phi_d < self.target and self.mode == 1:
|
||||
print "Convergence with smooth l2-norm regularization: Start IRLS steps..."
|
||||
|
||||
self.mode = 2
|
||||
print self.eps_p, self.eps_q, self.norms
|
||||
self.reg.eps_p = self.eps_p
|
||||
self.reg.eps_q = self.eps_q
|
||||
self.reg.norms = self.norms
|
||||
self.coolingFactor = 1.
|
||||
self.coolingRate = 1
|
||||
self.iterStart = self.opt.iter
|
||||
self.phi_d_last = self.invProb.phi_d
|
||||
self.phi_m_last = self.invProb.phi_m_last
|
||||
|
||||
self.reg.l2model = self.invProb.curModel
|
||||
self.reg.curModel = self.invProb.curModel
|
||||
|
||||
if getattr(self, 'f_old', None) is None:
|
||||
self.f_old = self.reg.eval(self.invProb.curModel)#self.invProb.evalFunction(self.invProb.curModel, return_g=False, return_H=False)
|
||||
|
||||
# Beta Schedule
|
||||
if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0:
|
||||
if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter
|
||||
self.invProb.beta /= self.coolingFactor
|
||||
|
||||
|
||||
# Save the file as a npz
|
||||
np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred)
|
||||
# Only update after GN iterations
|
||||
if (self.opt.iter-self.iterStart) % self.minGNiter == 0 and self.mode==2:
|
||||
|
||||
self.IRLSiter += 1
|
||||
|
||||
phim_new = self.reg.eval(self.invProb.curModel)
|
||||
self.f_change = np.abs(self.f_old - phim_new) / self.f_old
|
||||
|
||||
print "Regularization decrease: %6.3e" % (self.f_change)
|
||||
|
||||
# Check for maximum number of IRLS cycles
|
||||
if self.IRLSiter == self.maxIRLSiter:
|
||||
print "Reach maximum number of IRLS cycles: %i" % self.maxIRLSiter
|
||||
self.opt.stopNextIteration = True
|
||||
return
|
||||
|
||||
# Check if the function has changed enough
|
||||
if self.f_change < self.f_min_change and self.IRLSiter > 1:
|
||||
print "Minimum decrease in regularization. End of IRLS"
|
||||
self.opt.stopNextIteration = True
|
||||
return
|
||||
else:
|
||||
self.f_old = phim_new
|
||||
|
||||
# Cool the threshold parameter if required
|
||||
if getattr(self, 'factor', None) is not None:
|
||||
eps = self.reg.eps / self.factor
|
||||
|
||||
if getattr(self, 'eps_min', None) is not None:
|
||||
self.reg.eps = np.max([self.eps_min,eps])
|
||||
else:
|
||||
self.reg.eps = eps
|
||||
|
||||
# Get phi_m at the end of current iteration
|
||||
self.phi_m_last = self.invProb.phi_m_last
|
||||
|
||||
# Reset the regularization matrices so that it is
|
||||
# recalculated for current model
|
||||
self.reg._Wsmall = None
|
||||
self.reg._Wx = None
|
||||
self.reg._Wy = None
|
||||
self.reg._Wz = None
|
||||
|
||||
# Update the model used for the IRLS weights
|
||||
self.reg.curModel = self.invProb.curModel
|
||||
|
||||
# Temporarely set gamma to 1. to get raw phi_m
|
||||
self.reg.gamma = 1.
|
||||
|
||||
# Compute new model objective function value
|
||||
phim_new = self.reg.eval(self.invProb.curModel)
|
||||
|
||||
# Update gamma to scale the regularization between IRLS iterations
|
||||
self.reg.gamma = self.phi_m_last / phim_new
|
||||
|
||||
# Reset the regularization matrices again for new gamma
|
||||
self.reg._Wsmall = None
|
||||
self.reg._Wx = None
|
||||
self.reg._Wy = None
|
||||
self.reg._Wz = None
|
||||
|
||||
# Check if misfit is within the tolerance, otherwise scale beta
|
||||
val = self.invProb.phi_d / (self.survey.nD*0.5)
|
||||
|
||||
if np.abs(1.-val) > self.beta_tol:
|
||||
self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d
|
||||
|
||||
class Update_lin_PreCond(InversionDirective):
|
||||
"""
|
||||
Create a Jacobi preconditioner for the linear problem
|
||||
"""
|
||||
onlyOnStart=False
|
||||
|
||||
def initialize(self):
|
||||
|
||||
if getattr(self.opt, 'approxHinv', None) is None:
|
||||
# Update the pre-conditioner
|
||||
diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2.
|
||||
PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.)
|
||||
self.opt.approxHinv = PC
|
||||
|
||||
def endIter(self):
|
||||
# Cool the threshold parameter
|
||||
if self.onlyOnStart==True:
|
||||
return
|
||||
|
||||
if getattr(self.opt, 'approxHinv', None) is not None:
|
||||
# Update the pre-conditioner
|
||||
diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2.
|
||||
PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.)
|
||||
self.opt.approxHinv = PC
|
||||
|
||||
|
||||
class Update_Wj(InversionDirective):
|
||||
"""
|
||||
Create approx-sensitivity base weighting using the probing method
|
||||
"""
|
||||
k = None # Number of probing cycles
|
||||
itr = None # Iteration number to update Wj, or always update if None
|
||||
|
||||
# class UpdateReferenceModel(Parameter):
|
||||
def endIter(self):
|
||||
|
||||
# mref0 = None
|
||||
if self.itr is None or self.itr == self.opt.iter:
|
||||
|
||||
# def nextIter(self):
|
||||
# mref = getattr(self, 'm_prev', None)
|
||||
# if mref is None:
|
||||
# if self.debug: print 'UpdateReferenceModel is using mref0'
|
||||
# mref = self.mref0
|
||||
# self.m_prev = self.invProb.m_current
|
||||
# return mref
|
||||
m = self.invProb.curModel
|
||||
if self.k is None:
|
||||
self.k = int(self.survey.nD/10)
|
||||
|
||||
def JtJv(v):
|
||||
|
||||
Jv = self.prob.Jvec(m, v)
|
||||
|
||||
return self.prob.Jtvec(m,Jv)
|
||||
|
||||
JtJdiag = Utils.diagEst(JtJv,len(m),k=self.k)
|
||||
JtJdiag = JtJdiag / max(JtJdiag)
|
||||
|
||||
self.reg.wght = JtJdiag
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
import numpy as np
|
||||
from scipy.constants import mu_0, pi
|
||||
from scipy import special
|
||||
|
||||
def DCAnalyticHalf(txloc, rxlocs, sigma, earth_type="wholespace"):
|
||||
"""
|
||||
Analytic solution for electric potential from a postive pole
|
||||
|
||||
:param array txloc: a xyz location of A (+) electrode (np.r_[xa, ya, za])
|
||||
:param list rxlocs: xyz locations of M (+) and N (-) electrodes [M, N]
|
||||
|
||||
e.g.
|
||||
rxlocs = [M, N]
|
||||
M: xyz locations of M (+) electrode (np.c_[xmlocs, ymlocs, zmlocs])
|
||||
N: xyz locations of N (-) electrode (np.c_[xnlocs, ynlocs, znlocs])
|
||||
|
||||
:param float or complex sigma: values of conductivity
|
||||
:param string earth_type: values of conductivity ("wholsespace" or "halfspace")
|
||||
|
||||
"""
|
||||
M = rxlocs[0]
|
||||
N = rxlocs[1]
|
||||
|
||||
rM = np.sqrt( (M[:,0]-txloc[0])**2 + (M[:,1]-txloc[1])**2 + (M[:,2]-txloc[1])**2 )
|
||||
rN = np.sqrt( (N[:,0]-txloc[0])**2 + (N[:,1]-txloc[1])**2 + (N[:,2]-txloc[1])**2 )
|
||||
|
||||
phiM = 1./(4*np.pi*rM*sigma)
|
||||
phiN = 1./(4*np.pi*rN*sigma)
|
||||
phi = phiM - phiN
|
||||
|
||||
if earth_type == "halfspace":
|
||||
phi *= 2
|
||||
|
||||
return phi
|
||||
|
||||
deg2rad = lambda deg: deg/180.*np.pi
|
||||
rad2deg = lambda rad: rad*180./np.pi
|
||||
|
||||
def DCAnalyticSphere(txloc, rxloc, xc, radius, sigma, sigma1, \
|
||||
field_type = "secondary", order=12, halfspace=False):
|
||||
# def DCSpherePointCurrent(txloc, rxloc, xc, radius, rho, rho1, \
|
||||
# field_type = "secondary", order=12):
|
||||
"""
|
||||
|
||||
Parameters:
|
||||
|
||||
:param array txloc: A (+) current electrode location (x,y,z)
|
||||
:param array xc: x center of depressed sphere
|
||||
:param array rxloc: M(+) electrode locations / (Nx3 array, # of electrodes)
|
||||
|
||||
:param float radius: radius (float): radius of the sphere (m)
|
||||
:param float rho: resistivity of the background (ohm-m)
|
||||
:param float rho1: resistivity of the sphere
|
||||
:param string field_type: : "secondary", "total", "primary"
|
||||
(default="secondary")
|
||||
"secondary": secondary potential only due to sphere
|
||||
"primary": primary potential from the point source
|
||||
"total": "secondary"+"primary"
|
||||
:param float order: maximum order of Legendre polynomial (default=12)
|
||||
|
||||
Written by Seogi Kang (skang@eos.ubc.ca)
|
||||
Ph.D. Candidate of University of British Columbia, Canada
|
||||
|
||||
"""
|
||||
|
||||
Pleg = []
|
||||
# Compute Legendre Polynomial
|
||||
for i in range(order):
|
||||
Pleg.append(special.legendre(i, monic=0))
|
||||
|
||||
|
||||
rho = 1./sigma
|
||||
rho1 = 1./sigma1
|
||||
|
||||
# Center of the sphere should be aligned in txloc in y-direction
|
||||
yc = txloc[1]
|
||||
xyz = np.c_[rxloc[:,0]-xc, rxloc[:,1]-yc, rxloc[:,2]]
|
||||
r = np.sqrt( (xyz**2).sum(axis=1) )
|
||||
|
||||
x0 = abs(txloc[0]-xc)
|
||||
|
||||
costheta = xyz[:,0]/r * (txloc[0]-xc)/x0
|
||||
phi = np.zeros_like(r)
|
||||
R = (r**2+x0**2.-2.*r*x0*costheta)**0.5
|
||||
# primary potential in a whole space
|
||||
prim = rho*1./(4*np.pi*R)
|
||||
|
||||
if field_type =="primary":
|
||||
return prim
|
||||
|
||||
sphind = r < radius
|
||||
out = np.zeros_like(r)
|
||||
for n in range(order):
|
||||
An, Bn = AnBnfun(n, radius, x0, rho, rho1)
|
||||
dumout = An*r[~sphind]**(-n-1.)*Pleg[n](costheta[~sphind])
|
||||
out[~sphind] += dumout
|
||||
dumin = Bn*r[sphind]**(n)*Pleg[n](costheta[sphind])
|
||||
out[sphind] += dumin
|
||||
|
||||
out[~sphind] += prim[~sphind]
|
||||
|
||||
if halfspace:
|
||||
scale = 2
|
||||
else:
|
||||
scale = 1
|
||||
|
||||
if field_type == "secondary":
|
||||
return scale*(out-prim)
|
||||
elif field_type == "total":
|
||||
return scale*out
|
||||
|
||||
def AnBnfun(n, radius, x0, rho, rho1, I=1.):
|
||||
const = I*rho/(4*np.pi)
|
||||
bunmo = n*rho + (n+1)*rho1
|
||||
An = const * radius**(2*n+1) / x0 ** (n+1.) * n * \
|
||||
(rho1-rho) / bunmo
|
||||
Bn = const * 1. / x0 ** (n+1.) * (2*n+1) * (rho1) / bunmo
|
||||
return An, Bn
|
||||
@@ -1,3 +1,4 @@
|
||||
from TDEM import hzAnalyticDipoleT
|
||||
from FDEM import hzAnalyticDipoleF
|
||||
from FDEMcasing import *
|
||||
from DC import DCAnalyticHalf, DCAnalyticSphere
|
||||
|
||||
+66
-21
@@ -1,15 +1,16 @@
|
||||
from SimPEG import Survey, Problem, Utils, Models, Maps, PropMaps, np, sp, Solver as SimpegSolver
|
||||
from scipy.constants import mu_0
|
||||
|
||||
|
||||
class EMPropMap(Maps.PropMap):
|
||||
"""
|
||||
"""
|
||||
Property Map for EM Problems. The electrical conductivity (\\(\\sigma\\)) is the default inversion property, and the default value of the magnetic permeability is that of free space (\\(\\mu = 4\\pi\\times 10^{-7} \\) H/m)
|
||||
"""
|
||||
|
||||
sigma = Maps.Property("Electrical Conductivity", defaultInvProp = True, propertyLink=('rho',Maps.ReciprocalMap))
|
||||
mu = Maps.Property("Inverse Magnetic Permeability", defaultVal = mu_0, propertyLink=('mui',Maps.ReciprocalMap))
|
||||
|
||||
rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap))
|
||||
rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap))
|
||||
mui = Maps.Property("Inverse Magnetic Permeability", defaultVal = 1./mu_0, propertyLink=('mu', Maps.ReciprocalMap))
|
||||
|
||||
|
||||
@@ -21,7 +22,7 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
|
||||
surveyPair = Survey.BaseSurvey
|
||||
dataPair = Survey.Data
|
||||
|
||||
|
||||
PropMap = EMPropMap
|
||||
|
||||
Solver = SimpegSolver
|
||||
@@ -51,7 +52,7 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
if self.mapping.muMap is not None or self.mapping.muiMap is not None:
|
||||
toDelete += ['_MeMu', '_MeMuI','_MfMui','_MfMuiI']
|
||||
return toDelete
|
||||
|
||||
|
||||
@property
|
||||
def Me(self):
|
||||
"""
|
||||
@@ -61,6 +62,15 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
self._Me = self.mesh.getEdgeInnerProduct()
|
||||
return self._Me
|
||||
|
||||
@property
|
||||
def MeI(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MeI', None) is None:
|
||||
self._MeI = self.mesh.getEdgeInnerProduct(invMat=True)
|
||||
return self._MeI
|
||||
|
||||
@property
|
||||
def Mf(self):
|
||||
"""
|
||||
@@ -70,8 +80,22 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
self._Mf = self.mesh.getFaceInnerProduct()
|
||||
return self._Mf
|
||||
|
||||
@property
|
||||
def MfI(self):
|
||||
"""
|
||||
Face inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MfI', None) is None:
|
||||
self._MfI = self.mesh.getFaceInnerProduct(invMat=True)
|
||||
return self._MfI
|
||||
|
||||
# ----- Magnetic Permeability ----- #
|
||||
@property
|
||||
def Vol(self):
|
||||
if getattr(self, '_Vol', None) is None:
|
||||
self._Vol = Utils.sdiag(self.mesh.vol)
|
||||
return self._Vol
|
||||
|
||||
# ----- Magnetic Permeability ----- #
|
||||
@property
|
||||
def MfMui(self):
|
||||
"""
|
||||
@@ -109,7 +133,7 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
return self._MeMuI
|
||||
|
||||
|
||||
# ----- Electrical Conductivity ----- #
|
||||
# ----- Electrical Conductivity ----- #
|
||||
#TODO: hardcoded to sigma as the model
|
||||
@property
|
||||
def MeSigma(self):
|
||||
@@ -120,18 +144,17 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
self._MeSigma = self.mesh.getEdgeInnerProduct(self.curModel.sigma)
|
||||
return self._MeSigma
|
||||
|
||||
# TODO: This should take a vector
|
||||
# TODO: This should take a vector
|
||||
def MeSigmaDeriv(self, u):
|
||||
"""
|
||||
Derivative of MeSigma with respect to the model
|
||||
"""
|
||||
"""
|
||||
return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u) * self.curModel.sigmaDeriv
|
||||
|
||||
|
||||
@property
|
||||
def MeSigmaI(self):
|
||||
"""
|
||||
Inverse of the edge inner product matrix for \\(\\sigma\\).
|
||||
Inverse of the edge inner product matrix for \\(\\sigma\\).
|
||||
"""
|
||||
if getattr(self, '_MeSigmaI', None) is None:
|
||||
self._MeSigmaI = self.mesh.getEdgeInnerProduct(self.curModel.sigma, invMat=True)
|
||||
@@ -140,16 +163,13 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
# TODO: This should take a vector
|
||||
def MeSigmaIDeriv(self, u):
|
||||
"""
|
||||
Derivative of :code:`MeSigma` with respect to the model
|
||||
"""
|
||||
Derivative of :code:`MeSigma` with respect to the model
|
||||
"""
|
||||
# TODO: only works for diagonal tensors. getEdgeInnerProductDeriv, invMat=True should be implemented in SimPEG
|
||||
|
||||
dMeSigmaI_dI = -self.MeSigmaI**2
|
||||
dMe_dsig = self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u)
|
||||
dsig_dm = self.curModel.sigmaDeriv
|
||||
return dMeSigmaI_dI * ( dMe_dsig * ( dsig_dm))
|
||||
# return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma, invMat=True)(u)
|
||||
|
||||
return dMeSigmaI_dI * ( dMe_dsig * self.curModel.sigmaDeriv )
|
||||
|
||||
@property
|
||||
def MfRho(self):
|
||||
@@ -163,10 +183,9 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
# TODO: This should take a vector
|
||||
def MfRhoDeriv(self,u):
|
||||
"""
|
||||
Derivative of :code:`MfRho` with respect to the model.
|
||||
Derivative of :code:`MfRho` with respect to the model.
|
||||
"""
|
||||
return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv)
|
||||
# self.curModel.rhoDeriv
|
||||
return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * self.curModel.rhoDeriv
|
||||
|
||||
@property
|
||||
def MfRhoI(self):
|
||||
@@ -181,6 +200,32 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
# TODO: This should take a vector
|
||||
def MfRhoIDeriv(self,u):
|
||||
"""
|
||||
Derivative of :code:`MfRhoI` with respect to the model.
|
||||
Derivative of :code:`MfRhoI` with respect to the model.
|
||||
"""
|
||||
return self.mesh.getFaceInnerProductDeriv(self.curModel.rho, invMat=True)(u) * self.curModel.rhoDeriv
|
||||
|
||||
dMfRhoI_dI = -self.MfRhoI**2
|
||||
dMf_drho = self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u)
|
||||
return dMfRhoI_dI * ( dMf_drho * self.curModel.rhoDeriv )
|
||||
|
||||
class BaseEMSurvey(Survey.BaseSurvey):
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
# Sort these by frequency
|
||||
self.srcList = srcList
|
||||
Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
|
||||
def eval(self, f):
|
||||
"""
|
||||
Project fields to receiver locations
|
||||
:param Fields u: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: data
|
||||
"""
|
||||
data = Survey.Data(self)
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.eval(src, self.mesh, f)
|
||||
return data
|
||||
|
||||
def evalDeriv(self, f):
|
||||
raise Exception('Use Receivers to project fields deriv.')
|
||||
|
||||
+132
-132
@@ -8,7 +8,7 @@ from SimPEG.Utils import Zero, Identity, sdiag
|
||||
|
||||
class Fields(SimPEG.Problem.Fields):
|
||||
"""
|
||||
|
||||
|
||||
Fancy Field Storage for a FDEM survey. Only one field type is stored for
|
||||
each problem, the rest are computed. The fields obejct acts like an array and is indexed by
|
||||
|
||||
@@ -34,56 +34,56 @@ class Fields(SimPEG.Problem.Fields):
|
||||
|
||||
def _e(self, solution, srcList):
|
||||
"""
|
||||
Total electric field is sum of primary and secondary
|
||||
|
||||
Total electric field is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray solution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total electric field
|
||||
"""
|
||||
if getattr(self, '_ePrimary', None) is None or getattr(self, '_eSecondary', None) is None:
|
||||
if getattr(self, '_ePrimary', None) is None or getattr(self, '_eSecondary', None) is None:
|
||||
raise NotImplementedError ('Getting e from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
return self._ePrimary(solution,srcList) + self._eSecondary(solution,srcList)
|
||||
|
||||
def _b(self, solution, srcList):
|
||||
"""
|
||||
Total magnetic flux density is sum of primary and secondary
|
||||
|
||||
Total magnetic flux density is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray solution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total magnetic flux density
|
||||
:return: total magnetic flux density
|
||||
"""
|
||||
if getattr(self, '_bPrimary', None) is None or getattr(self, '_bSecondary', None) is None:
|
||||
if getattr(self, '_bPrimary', None) is None or getattr(self, '_bSecondary', None) is None:
|
||||
raise NotImplementedError ('Getting b from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
return self._bPrimary(solution, srcList) + self._bSecondary(solution, srcList)
|
||||
|
||||
def _h(self, solution, srcList):
|
||||
"""
|
||||
Total magnetic field is sum of primary and secondary
|
||||
|
||||
Total magnetic field is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray solution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total magnetic field
|
||||
"""
|
||||
if getattr(self, '_hPrimary', None) is None or getattr(self, '_hSecondary', None) is None:
|
||||
if getattr(self, '_hPrimary', None) is None or getattr(self, '_hSecondary', None) is None:
|
||||
raise NotImplementedError ('Getting h from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
return self._hPrimary(solution, srcList) + self._hSecondary(solution, srcList)
|
||||
|
||||
def _j(self, solution, srcList):
|
||||
"""
|
||||
Total current density is sum of primary and secondary
|
||||
|
||||
Total current density is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray solution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total current density
|
||||
:return: total current density
|
||||
"""
|
||||
if getattr(self, '_jPrimary', None) is None or getattr(self, '_jSecondary', None) is None:
|
||||
if getattr(self, '_jPrimary', None) is None or getattr(self, '_jSecondary', None) is None:
|
||||
raise NotImplementedError ('Getting j from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
return self._jPrimary(solution, srcList) + self._jSecondary(solution, srcList)
|
||||
@@ -99,7 +99,7 @@ class Fields(SimPEG.Problem.Fields):
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative times a vector (or tuple for adjoint)
|
||||
"""
|
||||
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
|
||||
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
@@ -117,12 +117,12 @@ class Fields(SimPEG.Problem.Fields):
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative times a vector (or tuple for adjoint)
|
||||
"""
|
||||
if getattr(self, '_bDeriv_u', None) is None or getattr(self, '_bDeriv_m', None) is None:
|
||||
if getattr(self, '_bDeriv_u', None) is None or getattr(self, '_bDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting bDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._bDeriv_u(src, v, adjoint), self._bDeriv_m(src, v, adjoint)
|
||||
return np.array(self._bDeriv_u(src, du_dm_v, adjoint) + self._bDeriv_m(src, v, adjoint), dtype = complex)
|
||||
return np.array(self._bDeriv_u(src, du_dm_v, adjoint) + self._bDeriv_m(src, v, adjoint), dtype = complex)
|
||||
|
||||
def _hDeriv(self, src, du_dm_v, v, adjoint = False):
|
||||
"""
|
||||
@@ -135,10 +135,10 @@ class Fields(SimPEG.Problem.Fields):
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative times a vector (or tuple for adjoint)
|
||||
"""
|
||||
if getattr(self, '_hDeriv_u', None) is None or getattr(self, '_hDeriv_m', None) is None:
|
||||
if getattr(self, '_hDeriv_u', None) is None or getattr(self, '_hDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting hDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
if adjoint:
|
||||
return self._hDeriv_u(src, v, adjoint), self._hDeriv_m(src, v, adjoint)
|
||||
return np.array(self._hDeriv_u(src, du_dm_v, adjoint) + self._hDeriv_m(src, v, adjoint), dtype = complex)
|
||||
|
||||
@@ -153,19 +153,19 @@ class Fields(SimPEG.Problem.Fields):
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative times a vector (or tuple for adjoint)
|
||||
"""
|
||||
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
|
||||
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint)
|
||||
return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = complex)
|
||||
|
||||
class Fields_e(Fields):
|
||||
class Fields3D_e(Fields):
|
||||
"""
|
||||
Fields object for Problem_e.
|
||||
Fields object for Problem3D_e.
|
||||
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
:param Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'eSolution':'E'}
|
||||
@@ -181,7 +181,7 @@ class Fields_e(Fields):
|
||||
}
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields.__init__(self,mesh,survey,**kwargs)
|
||||
Fields.__init__(self, mesh, survey, **kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
@@ -233,9 +233,9 @@ class Fields_e(Fields):
|
||||
|
||||
def _eDeriv_u(self, src, v, adjoint = False):
|
||||
"""
|
||||
Partial derivative of the total electric field with respect to the thing we
|
||||
Partial derivative of the total electric field with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -247,8 +247,8 @@ class Fields_e(Fields):
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint = False):
|
||||
"""
|
||||
Partial derivative of the total electric field with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
Partial derivative of the total electric field with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -289,14 +289,14 @@ class Fields_e(Fields):
|
||||
b = (C * eSolution)
|
||||
for i, src in enumerate(srcList):
|
||||
b[:,i] *= - 1./(1j*omega(src.freq))
|
||||
S_m, _ = src.eval(self.prob)
|
||||
b[:,i] = b[:,i]+ 1./(1j*omega(src.freq)) * S_m
|
||||
s_m, _ = src.eval(self.prob)
|
||||
b[:,i] = b[:,i]+ 1./(1j*omega(src.freq)) * s_m
|
||||
return b
|
||||
|
||||
def _bDeriv_u(self, src, du_dm_v, adjoint = False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -312,8 +312,8 @@ class Fields_e(Fields):
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint = False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the inversion model.
|
||||
|
||||
Derivative of the magnetic flux density with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -321,8 +321,8 @@ class Fields_e(Fields):
|
||||
:return: product of the magnetic flux density derivative with respect to the inversion model with a vector
|
||||
"""
|
||||
|
||||
S_mDeriv, _ = src.evalDeriv(self.prob, v, adjoint)
|
||||
return 1./(1j * omega(src.freq)) * S_mDeriv
|
||||
s_mDeriv, _ = src.evalDeriv(self.prob, v, adjoint)
|
||||
return 1./(1j * omega(src.freq)) * s_mDeriv
|
||||
|
||||
def _j(self, eSolution, srcList):
|
||||
"""
|
||||
@@ -341,7 +341,7 @@ class Fields_e(Fields):
|
||||
def _jDeriv_u(self, src, du_dm_v, adjoint = False):
|
||||
"""
|
||||
Derivative of the current density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -351,15 +351,15 @@ class Fields_e(Fields):
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) # number of components (instead of checking if cyl or not)
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
|
||||
if adjoint:
|
||||
if adjoint:
|
||||
return self._eDeriv_u(src, self._MeSigma.T * (self._aveE2CCV.T * (VI.T * du_dm_v) ), adjoint = adjoint)
|
||||
return VI * (self._aveE2CCV * (self._MeSigma * (self._eDeriv_u(src, du_dm_v, adjoint=adjoint) ) ) )
|
||||
|
||||
|
||||
|
||||
def _jDeriv_m(self, src, v, adjoint = False):
|
||||
"""
|
||||
Derivative of the current density with respect to the inversion model.
|
||||
|
||||
Derivative of the current density with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -373,7 +373,7 @@ class Fields_e(Fields):
|
||||
if adjoint:
|
||||
return self._MeSigmaDeriv(e).T * (self._aveE2CCV.T * (VI.T * v)) + self._eDeriv_m(src, self._aveE2CCV.T * (VI.T * v), adjoint=adjoint)
|
||||
return VI * (self._aveE2CCV * ( self._eDeriv_m(src, v, adjoint=adjoint) + self._MeSigmaDeriv(e) * v))
|
||||
|
||||
|
||||
|
||||
|
||||
def _h(self, eSolution, srcList):
|
||||
@@ -393,7 +393,7 @@ class Fields_e(Fields):
|
||||
def _hDeriv_u(self, src, du_dm_v, adjoint = False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -409,8 +409,8 @@ class Fields_e(Fields):
|
||||
|
||||
def _hDeriv_m(self, src, v, adjoint = False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the inversion model.
|
||||
|
||||
Derivative of the magnetic field with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -426,12 +426,12 @@ class Fields_e(Fields):
|
||||
|
||||
|
||||
|
||||
class Fields_b(Fields):
|
||||
class Fields3D_b(Fields):
|
||||
"""
|
||||
Fields object for Problem_b.
|
||||
Fields object for Problem3D_b.
|
||||
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
:param Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'bSolution':'F'}
|
||||
@@ -506,9 +506,9 @@ class Fields_b(Fields):
|
||||
|
||||
def _bDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total magnetic flux density with respect to the thing we
|
||||
Partial derivative of the total magnetic flux density with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -520,8 +520,8 @@ class Fields_b(Fields):
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total magnetic flux density with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
Partial derivative of the total magnetic flux density with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -560,15 +560,15 @@ class Fields_b(Fields):
|
||||
|
||||
e = ( self._edgeCurl.T * ( self._MfMui * bSolution))
|
||||
for i,src in enumerate(srcList):
|
||||
_,S_e = src.eval(self.prob)
|
||||
e[:,i] = e[:,i] + - S_e
|
||||
_,s_e = src.eval(self.prob)
|
||||
e[:,i] = e[:,i] + - s_e
|
||||
|
||||
return self._MeSigmaI * e
|
||||
|
||||
def _eDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -583,8 +583,8 @@ class Fields_b(Fields):
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the inversion model
|
||||
|
||||
Derivative of the electric field with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -593,15 +593,15 @@ class Fields_b(Fields):
|
||||
"""
|
||||
|
||||
bSolution = Utils.mkvc(self[src, 'bSolution'])
|
||||
_,S_e = src.eval(self.prob)
|
||||
_,s_e = src.eval(self.prob)
|
||||
|
||||
w = -S_e + self._edgeCurl.T * (self._MfMui * bSolution)
|
||||
_, S_eDeriv = src.evalDeriv(self.prob, v, adjoint)
|
||||
w = -s_e + self._edgeCurl.T * (self._MfMui * bSolution)
|
||||
_, s_eDeriv = src.evalDeriv(self.prob, v, adjoint)
|
||||
|
||||
|
||||
if adjoint:
|
||||
return self._MeSigmaIDeriv(w).T * v - self._MeSigmaI.T * S_eDeriv
|
||||
return self._MeSigmaIDeriv(w) * v - self._MeSigmaI * S_eDeriv
|
||||
return self._MeSigmaIDeriv(w).T * v - self._MeSigmaI.T * s_eDeriv
|
||||
return self._MeSigmaIDeriv(w) * v - self._MeSigmaI * s_eDeriv
|
||||
|
||||
def _j(self, bSolution, srcList):
|
||||
"""
|
||||
@@ -617,13 +617,13 @@ class Fields_b(Fields):
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
|
||||
return VI * (self._aveE2CCV * ( self._MeSigma * self._e(bSolution,srcList ) ) )
|
||||
|
||||
|
||||
|
||||
def _jDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the current density with respect to the thing we
|
||||
Partial derivative of the current density with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -639,8 +639,8 @@ class Fields_b(Fields):
|
||||
|
||||
def _jDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the current density with respect to the inversion model
|
||||
|
||||
Derivative of the current density with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -664,9 +664,9 @@ class Fields_b(Fields):
|
||||
|
||||
def _hDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the magnetic field with respect to the thing we
|
||||
Partial derivative of the magnetic field with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -682,8 +682,8 @@ class Fields_b(Fields):
|
||||
|
||||
def _hDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the inversion model
|
||||
|
||||
Derivative of the magnetic field with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -693,12 +693,12 @@ class Fields_b(Fields):
|
||||
return Zero()
|
||||
|
||||
|
||||
class Fields_j(Fields):
|
||||
class Fields3D_j(Fields):
|
||||
"""
|
||||
Fields object for Problem_j.
|
||||
Fields object for Problem3D_j.
|
||||
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
:param Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'jSolution':'F'}
|
||||
@@ -769,12 +769,12 @@ class Fields_j(Fields):
|
||||
|
||||
def _j(self, jSolution, srcList):
|
||||
"""
|
||||
Total current density is sum of primary and secondary
|
||||
|
||||
Total current density is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray jSolution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total current density
|
||||
:return: total current density
|
||||
"""
|
||||
|
||||
return self._jPrimary(jSolution, srcList) + self._jSecondary(jSolution, srcList)
|
||||
@@ -782,9 +782,9 @@ class Fields_j(Fields):
|
||||
|
||||
def _jDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total current density with respect to the thing we
|
||||
Partial derivative of the total current density with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -797,8 +797,8 @@ class Fields_j(Fields):
|
||||
|
||||
def _jDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total current density with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
Partial derivative of the total current density with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -837,15 +837,15 @@ class Fields_j(Fields):
|
||||
h = (self._edgeCurl.T * (self._MfRho * jSolution) )
|
||||
for i, src in enumerate(srcList):
|
||||
h[:,i] *= -1./(1j*omega(src.freq))
|
||||
S_m,_ = src.eval(self.prob)
|
||||
h[:,i] = h[:,i] + 1./(1j*omega(src.freq)) * (S_m)
|
||||
s_m,_ = src.eval(self.prob)
|
||||
h[:,i] = h[:,i] + 1./(1j*omega(src.freq)) * (s_m)
|
||||
return self._MeMuI * h
|
||||
|
||||
|
||||
def _hDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -856,13 +856,13 @@ class Fields_j(Fields):
|
||||
if adjoint:
|
||||
return -1./(1j*omega(src.freq)) * self._MfRho.T * (self._edgeCurl * ( self._MeMuI.T * du_dm_v))
|
||||
return -1./(1j*omega(src.freq)) * self._MeMuI * (self._edgeCurl.T * (self._MfRho * du_dm_v) )
|
||||
|
||||
|
||||
|
||||
|
||||
def _hDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the inversion model
|
||||
|
||||
Derivative of the magnetic field with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -875,19 +875,19 @@ class Fields_j(Fields):
|
||||
C = self._edgeCurl
|
||||
MfRho = self._MfRho
|
||||
MfRhoDeriv = self._MfRhoDeriv
|
||||
S_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
|
||||
s_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
|
||||
|
||||
if not adjoint:
|
||||
hDeriv_m = -1./(1j*omega(src.freq)) * MeMuI * (C.T * (MfRhoDeriv(jSolution)*v ) )
|
||||
S_mDeriv = S_mDeriv(v)
|
||||
hDeriv_m = hDeriv_m + 1./(1j*omega(src.freq)) * MeMuI * ( S_mDeriv)
|
||||
s_mDeriv = s_mDeriv(v)
|
||||
hDeriv_m = hDeriv_m + 1./(1j*omega(src.freq)) * MeMuI * ( s_mDeriv)
|
||||
|
||||
elif adjoint:
|
||||
hDeriv_m = -1./(1j*omega(src.freq)) * MfRhoDeriv(jSolution).T * ( C * (MeMuI.T * v ) )
|
||||
|
||||
S_mDeriv = S_mDeriv(MeMuI.T * v)
|
||||
hDeriv_m = hDeriv_m + 1./(1j*omega(src.freq)) * S_mDeriv
|
||||
|
||||
s_mDeriv = s_mDeriv(MeMuI.T * v)
|
||||
hDeriv_m = hDeriv_m + 1./(1j*omega(src.freq)) * s_mDeriv
|
||||
|
||||
return hDeriv_m
|
||||
|
||||
def _e(self, jSolution, srcList):
|
||||
@@ -901,12 +901,12 @@ class Fields_j(Fields):
|
||||
"""
|
||||
n = int(self._aveF2CCV.shape[0] / self._nC) # number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._j(jSolution, srcList)))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._j(jSolution, srcList)))
|
||||
|
||||
def _eDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -921,8 +921,8 @@ class Fields_j(Fields):
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the inversion model
|
||||
|
||||
Derivative of the electric field with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -943,17 +943,17 @@ class Fields_j(Fields):
|
||||
:param numpy.ndarray hSolution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: secondary magnetic flux density
|
||||
:return: secondary magnetic flux density
|
||||
"""
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) # number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
|
||||
return VI * (self._aveE2CCV * ( self._MeMu * self._h(jSolution,srcList)) )
|
||||
return VI * (self._aveE2CCV * ( self._MeMu * self._h(jSolution,srcList)) )
|
||||
|
||||
def _bDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -969,8 +969,8 @@ class Fields_j(Fields):
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the inversion model
|
||||
|
||||
Derivative of the magnetic flux density with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -980,20 +980,20 @@ class Fields_j(Fields):
|
||||
jSolution = self[src,'jSolution']
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) # number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
S_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
|
||||
s_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
|
||||
|
||||
if adjoint:
|
||||
v = self._aveE2CCV.T * ( VI.T * v)
|
||||
return 1./(1j * omega(src.freq)) * ( S_mDeriv(v) - self._MfRhoDeriv(jSolution).T * (self._edgeCurl * v ))
|
||||
return 1./(1j * omega(src.freq)) * VI * (self._aveE2CCV * ( S_mDeriv(v) - self._edgeCurl.T * ( self._MfRhoDeriv(jSolution) * v ) ) )
|
||||
return 1./(1j * omega(src.freq)) * ( s_mDeriv(v) - self._MfRhoDeriv(jSolution).T * (self._edgeCurl * v ))
|
||||
return 1./(1j * omega(src.freq)) * VI * (self._aveE2CCV * ( s_mDeriv(v) - self._edgeCurl.T * ( self._MfRhoDeriv(jSolution) * v ) ) )
|
||||
|
||||
|
||||
class Fields_h(Fields):
|
||||
class Fields3D_h(Fields):
|
||||
"""
|
||||
Fields object for Problem_h.
|
||||
Fields object for Problem3D_h.
|
||||
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
:param Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'hSolution':'E'}
|
||||
@@ -1065,9 +1065,9 @@ class Fields_h(Fields):
|
||||
|
||||
def _hDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total magnetic field with respect to the thing we
|
||||
Partial derivative of the total magnetic field with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1079,8 +1079,8 @@ class Fields_h(Fields):
|
||||
|
||||
def _hDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total magnetic field with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
Partial derivative of the total magnetic field with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1119,14 +1119,14 @@ class Fields_h(Fields):
|
||||
|
||||
j = self._edgeCurl*hSolution
|
||||
for i, src in enumerate(srcList):
|
||||
_,S_e = src.eval(self.prob)
|
||||
j[:,i] = j[:,i]+ -S_e
|
||||
_,s_e = src.eval(self.prob)
|
||||
j[:,i] = j[:,i]+ -s_e
|
||||
return j
|
||||
|
||||
def _jDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the current density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1142,8 +1142,8 @@ class Fields_h(Fields):
|
||||
|
||||
def _jDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the current density with respect to the inversion model.
|
||||
|
||||
Derivative of the current density with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1151,9 +1151,9 @@ class Fields_h(Fields):
|
||||
:return: product of the current density derivative with respect to the inversion model with a vector
|
||||
"""
|
||||
|
||||
_,S_eDeriv = src.evalDeriv(self.prob, v, adjoint)
|
||||
return -S_eDeriv
|
||||
|
||||
_,s_eDeriv = src.evalDeriv(self.prob, v, adjoint)
|
||||
return -s_eDeriv
|
||||
|
||||
def _e(self, hSolution, srcList):
|
||||
"""
|
||||
Electric field from hSolution
|
||||
@@ -1165,12 +1165,12 @@ class Fields_h(Fields):
|
||||
"""
|
||||
n = int(self._aveF2CCV.shape[0] / self._nC) #number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._j(hSolution, srcList)))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._j(hSolution, srcList)))
|
||||
|
||||
def _eDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1181,12 +1181,12 @@ class Fields_h(Fields):
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
if adjoint:
|
||||
return self._edgeCurl.T * ( self._MfRho.T * ( self._aveF2CCV.T * ( VI.T * du_dm_v ) ) )
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._edgeCurl * du_dm_v ))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._edgeCurl * du_dm_v ))
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the inversion model.
|
||||
|
||||
Derivative of the electric field with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1196,7 +1196,7 @@ class Fields_h(Fields):
|
||||
hSolution = Utils.mkvc(self[src,'hSolution'])
|
||||
n = int(self._aveF2CCV.shape[0] / self._nC) #number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
if adjoint:
|
||||
if adjoint:
|
||||
return ( self._MfRhoDeriv(self._edgeCurl * hSolution).T * ( self._aveF2CCV.T * (VI.T * v) ) )
|
||||
return VI * (self._aveF2CCV * (self._MfRhoDeriv(self._edgeCurl * hSolution) * v ))
|
||||
|
||||
@@ -1207,10 +1207,10 @@ class Fields_h(Fields):
|
||||
:param numpy.ndarray hSolution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: magnetic flux density
|
||||
:return: magnetic flux density
|
||||
"""
|
||||
h = self._h(hSolution, srcList)
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) #number of components
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) #number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
|
||||
return VI * (self._aveE2CCV * (self._MeMu * h))
|
||||
@@ -1218,14 +1218,14 @@ class Fields_h(Fields):
|
||||
def _bDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: product of the derivative of the magnetic flux density with respect to the field we solved for with a vector
|
||||
"""
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) #number of components
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) #number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
if adjoint:
|
||||
return self._MeMu.T * (self._aveE2CCV.T * ( VI.T * du_dm_v ))
|
||||
@@ -1233,8 +1233,8 @@ class Fields_h(Fields):
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the inversion model.
|
||||
|
||||
Derivative of the magnetic flux density with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from SimPEG import Problem, Utils, np, sp, Solver as SimpegSolver
|
||||
from scipy.constants import mu_0
|
||||
from SurveyFDEM import Survey as SurveyFDEM
|
||||
from FieldsFDEM import Fields, Fields_e, Fields_b, Fields_h, Fields_j
|
||||
from FieldsFDEM import Fields, Fields3D_e, Fields3D_b, Fields3D_h, Fields3D_j
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SimPEG.EM.Utils import omega
|
||||
|
||||
@@ -17,10 +17,10 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
\mathbf{C} \mathbf{e} + i \omega \mathbf{b} = \mathbf{s_m} \\\\
|
||||
{\mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{M_{\sigma}^e} \mathbf{e} = \mathbf{s_e}}
|
||||
|
||||
if using the E-B formulation (:code:`Problem_e`
|
||||
or :code:`Problem_b`). Note that in this case, :math:`\mathbf{s_e}` is an integrated quantity.
|
||||
if using the E-B formulation (:code:`Problem3D_e`
|
||||
or :code:`Problem3D_b`). Note that in this case, :math:`\mathbf{s_e}` is an integrated quantity.
|
||||
|
||||
If we write Maxwell's equations in terms of
|
||||
If we write Maxwell's equations in terms of
|
||||
\\\(\\\mathbf{h}\\\) and current density \\\(\\\mathbf{j}\\\)
|
||||
|
||||
.. math ::
|
||||
@@ -28,7 +28,7 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{j} + i \omega \mathbf{M_{\mu}^e} \mathbf{h} = \mathbf{s_m} \\\\
|
||||
\mathbf{C} \mathbf{h} - \mathbf{j} = \mathbf{s_e}
|
||||
|
||||
if using the H-J formulation (:code:`Problem_j` or :code:`Problem_h`). Note that here, :math:`\mathbf{s_m}` is an integrated quantity.
|
||||
if using the H-J formulation (:code:`Problem3D_j` or :code:`Problem3D_h`). Note that here, :math:`\mathbf{s_m}` is an integrated quantity.
|
||||
|
||||
The problem performs the elimination so that we are solving the system for \\\(\\\mathbf{e},\\\mathbf{b},\\\mathbf{j} \\\) or \\\(\\\mathbf{h}\\\)
|
||||
"""
|
||||
@@ -36,76 +36,76 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
surveyPair = SurveyFDEM
|
||||
fieldsPair = Fields
|
||||
|
||||
def fields(self, m=None):
|
||||
def fields(self, m):
|
||||
"""
|
||||
Solve the forward problem for the fields.
|
||||
|
||||
|
||||
:param numpy.array m: inversion model (nP,)
|
||||
:rtype numpy.array:
|
||||
:return F: forward solution
|
||||
:return f: forward solution
|
||||
"""
|
||||
|
||||
self.curModel = m
|
||||
F = self.fieldsPair(self.mesh, self.survey)
|
||||
f = self.fieldsPair(self.mesh, self.survey)
|
||||
|
||||
for freq in self.survey.freqs:
|
||||
A = self.getA(freq)
|
||||
rhs = self.getRHS(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
sol = Ainv * rhs
|
||||
u = Ainv * rhs
|
||||
Srcs = self.survey.getSrcByFreq(freq)
|
||||
F[Srcs, self._solutionType] = sol
|
||||
f[Srcs, self._solutionType] = u
|
||||
Ainv.clean()
|
||||
return F
|
||||
return f
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""
|
||||
Sensitivity times a vector.
|
||||
|
||||
:param numpy.array m: inversion model (nP,)
|
||||
:param numpy.array v: vector which we take sensitivity product with (nP,)
|
||||
:param SimPEG.EM.FDEM.Fields u: fields object
|
||||
:param SimPEG.EM.FDEM.Fields u: fields object
|
||||
:rtype numpy.array:
|
||||
:return: Jv (ndata,)
|
||||
:return: Jv (ndata,)
|
||||
"""
|
||||
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey)
|
||||
|
||||
for freq in self.survey.freqs:
|
||||
A = self.getA(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
A = self.getA(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts) # create the concept of Ainv (actually a solve)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
u_src = u[src, self._solutionType]
|
||||
u_src = f[src, self._solutionType]
|
||||
dA_dm_v = self.getADeriv(freq, u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(freq, src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(freq, src, v)
|
||||
du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
|
||||
|
||||
for rx in src.rxList:
|
||||
df_dmFun = getattr(u, '_%sDeriv'%rx.projField, None)
|
||||
df_dmFun = getattr(f, '_{0}Deriv'.format(rx.projField), None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, u, df_dm_v)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
||||
Ainv.clean()
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""
|
||||
Sensitivity transpose times a vector
|
||||
|
||||
:param numpy.array m: inversion model (nP,)
|
||||
:param numpy.array v: vector which we take adjoint product with (nP,)
|
||||
:param SimPEG.EM.FDEM.Fields u: fields object
|
||||
:param SimPEG.EM.FDEM.Fields u: fields object
|
||||
:rtype numpy.array:
|
||||
:return: Jv (ndata,)
|
||||
:return: Jv (ndata,)
|
||||
"""
|
||||
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
@@ -120,12 +120,12 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
ATinv = self.Solver(AT, **self.solverOpts)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
u_src = u[src, self._solutionType]
|
||||
u_src = f[src, self._solutionType]
|
||||
|
||||
for rx in src.rxList:
|
||||
PTv = rx.evalDeriv(src, self.mesh, u, v[src, rx], adjoint=True) # wrt u, need possibility wrt m
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
||||
|
||||
df_duTFun = getattr(u, '_%sDeriv'%rx.projField, None)
|
||||
df_duTFun = getattr(f, '_{0}Deriv'.format(rx.projField), None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
|
||||
ATinvdf_duT = ATinv * df_duT
|
||||
@@ -137,14 +137,13 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
df_dmT = df_dmT + du_dmT
|
||||
|
||||
# TODO: this should be taken care of by the reciever?
|
||||
real_or_imag = rx.projComp
|
||||
if real_or_imag is 'real':
|
||||
if rx.component is 'real':
|
||||
Jtv += np.array(df_dmT, dtype=complex).real
|
||||
elif real_or_imag is 'imag':
|
||||
elif rx.component is 'imag':
|
||||
Jtv += - np.array(df_dmT, dtype=complex).real
|
||||
else:
|
||||
raise Exception('Must be real or imag')
|
||||
|
||||
|
||||
ATinv.clean()
|
||||
|
||||
return Utils.mkvc(Jtv)
|
||||
@@ -154,30 +153,31 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
Evaluates the sources for a given frequency and puts them in matrix form
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: S_m, S_e (nE or nF, nSrc)
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: s_m, s_e (nE or nF, nSrc)
|
||||
"""
|
||||
Srcs = self.survey.getSrcByFreq(freq)
|
||||
if self._formulation is 'EB':
|
||||
S_m = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
||||
S_e = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
||||
s_m = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
||||
s_e = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
||||
elif self._formulation is 'HJ':
|
||||
S_m = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
||||
S_e = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
||||
s_m = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
||||
s_e = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
smi, sei = src.eval(self)
|
||||
S_m[:,i] = S_m[:,i] + smi
|
||||
S_e[:,i] = S_e[:,i] + sei
|
||||
#Why are you adding?
|
||||
s_m[:,i] = s_m[:,i] + smi
|
||||
s_e[:,i] = s_e[:,i] + sei
|
||||
|
||||
return S_m, S_e
|
||||
return s_m, s_e
|
||||
|
||||
|
||||
##########################################################################################
|
||||
################################ E-B Formulation #########################################
|
||||
##########################################################################################
|
||||
|
||||
class Problem_e(BaseFDEMProblem):
|
||||
class Problem3D_e(BaseFDEMProblem):
|
||||
"""
|
||||
By eliminating the magnetic flux density using
|
||||
|
||||
@@ -199,7 +199,7 @@ class Problem_e(BaseFDEMProblem):
|
||||
|
||||
_solutionType = 'eSolution'
|
||||
_formulation = 'EB'
|
||||
fieldsPair = Fields_e
|
||||
fieldsPair = Fields3D_e
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -207,7 +207,7 @@ class Problem_e(BaseFDEMProblem):
|
||||
def getA(self, freq):
|
||||
"""
|
||||
System matrix
|
||||
|
||||
|
||||
.. math ::
|
||||
\mathbf{A} = \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{C} + i \omega \mathbf{M^e_{\sigma}}
|
||||
|
||||
@@ -230,12 +230,12 @@ class Problem_e(BaseFDEMProblem):
|
||||
.. math ::
|
||||
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = i \omega \\frac{d \mathbf{M^e_{\sigma}}\mathbf{v} }{d\mathbf{m}}
|
||||
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nE,)
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nE,)
|
||||
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
"""
|
||||
|
||||
dsig_dm = self.curModel.sigmaDeriv
|
||||
@@ -248,25 +248,25 @@ class Problem_e(BaseFDEMProblem):
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Right hand side for the system
|
||||
Right hand side for the system
|
||||
|
||||
.. math ::
|
||||
\mathbf{RHS} = \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f}\mathbf{s_m} -i\omega\mathbf{M_e}\mathbf{s_e}
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
"""
|
||||
|
||||
S_m, S_e = self.getSourceTerm(freq)
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
C = self.mesh.edgeCurl
|
||||
MfMui = self.MfMui
|
||||
|
||||
return C.T * (MfMui * S_m) -1j * omega(freq) * S_e
|
||||
return C.T * (MfMui * s_m) -1j * omega(freq) * s_e
|
||||
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
@@ -278,17 +278,17 @@ class Problem_e(BaseFDEMProblem):
|
||||
|
||||
C = self.mesh.edgeCurl
|
||||
MfMui = self.MfMui
|
||||
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
|
||||
if adjoint:
|
||||
dRHS = MfMui * (C * v)
|
||||
return S_mDeriv(dRHS) - 1j * omega(freq) * S_eDeriv(v)
|
||||
return s_mDeriv(dRHS) - 1j * omega(freq) * s_eDeriv(v)
|
||||
|
||||
else:
|
||||
return C.T * (MfMui * S_mDeriv(v)) -1j * omega(freq) * S_eDeriv(v)
|
||||
return C.T * (MfMui * s_mDeriv(v)) -1j * omega(freq) * s_eDeriv(v)
|
||||
|
||||
|
||||
class Problem_b(BaseFDEMProblem):
|
||||
class Problem3D_b(BaseFDEMProblem):
|
||||
"""
|
||||
We eliminate :math:`\mathbf{e}` using
|
||||
|
||||
@@ -310,7 +310,7 @@ class Problem_b(BaseFDEMProblem):
|
||||
|
||||
_solutionType = 'bSolution'
|
||||
_formulation = 'EB'
|
||||
fieldsPair = Fields_b
|
||||
fieldsPair = Fields3D_b
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -346,12 +346,12 @@ class Problem_b(BaseFDEMProblem):
|
||||
.. math ::
|
||||
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = \mathbf{C} \\frac{\mathbf{M^e_{\sigma}} \mathbf{v}}{d\mathbf{m}}
|
||||
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nF,)
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nF,)
|
||||
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
"""
|
||||
|
||||
MfMui = self.MfMui
|
||||
@@ -373,21 +373,21 @@ class Problem_b(BaseFDEMProblem):
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Right hand side for the system
|
||||
Right hand side for the system
|
||||
|
||||
.. math ::
|
||||
\mathbf{RHS} = \mathbf{s_m} + \mathbf{M^e_{\sigma}}^{-1}\mathbf{s_e}
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
"""
|
||||
|
||||
S_m, S_e = self.getSourceTerm(freq)
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
C = self.mesh.edgeCurl
|
||||
MeSigmaI = self.MeSigmaI
|
||||
|
||||
RHS = S_m + C * ( MeSigmaI * S_e )
|
||||
RHS = s_m + C * ( MeSigmaI * s_e )
|
||||
|
||||
if self._makeASymmetric is True:
|
||||
MfMui = self.MfMui
|
||||
@@ -408,21 +408,21 @@ class Problem_b(BaseFDEMProblem):
|
||||
"""
|
||||
|
||||
C = self.mesh.edgeCurl
|
||||
S_m, S_e = src.eval(self)
|
||||
s_m, s_e = src.eval(self)
|
||||
MfMui = self.MfMui
|
||||
|
||||
if self._makeASymmetric and adjoint:
|
||||
v = self.MfMui * v
|
||||
|
||||
MeSigmaIDeriv = self.MeSigmaIDeriv(S_e)
|
||||
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
MeSigmaIDeriv = self.MeSigmaIDeriv(s_e)
|
||||
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
|
||||
if not adjoint:
|
||||
RHSderiv = C * (MeSigmaIDeriv * v)
|
||||
SrcDeriv = S_mDeriv(v) + C * (self.MeSigmaI * S_eDeriv(v))
|
||||
SrcDeriv = s_mDeriv(v) + C * (self.MeSigmaI * s_eDeriv(v))
|
||||
elif adjoint:
|
||||
RHSderiv = MeSigmaIDeriv.T * (C.T * v)
|
||||
SrcDeriv = S_mDeriv(v) + self.MeSigmaI.T * (C.T * S_eDeriv(v))
|
||||
SrcDeriv = s_mDeriv(v) + self.MeSigmaI.T * (C.T * s_eDeriv(v))
|
||||
|
||||
if self._makeASymmetric is True and not adjoint:
|
||||
return MfMui.T * (SrcDeriv + RHSderiv)
|
||||
@@ -436,7 +436,7 @@ class Problem_b(BaseFDEMProblem):
|
||||
##########################################################################################
|
||||
|
||||
|
||||
class Problem_j(BaseFDEMProblem):
|
||||
class Problem3D_j(BaseFDEMProblem):
|
||||
"""
|
||||
We eliminate \\\(\\\mathbf{h}\\\) using
|
||||
|
||||
@@ -458,7 +458,7 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
_solutionType = 'jSolution'
|
||||
_formulation = 'HJ'
|
||||
fieldsPair = Fields_j
|
||||
fieldsPair = Fields3D_j
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -497,12 +497,12 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
\\frac{\mathbf{A(\sigma)} \mathbf{v}}{d \mathbf{m}} = \mathbf{C} \mathbf{M^e_{mu^{-1}}} \mathbf{C^{\\top}} \\frac{d \mathbf{M^f_{\sigma^{-1}}}\mathbf{v} }{d \mathbf{m}}
|
||||
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nF,)
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nF,)
|
||||
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
"""
|
||||
|
||||
MeMuI = self.MeMuI
|
||||
@@ -522,7 +522,7 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Right hand side for the system
|
||||
Right hand side for the system
|
||||
|
||||
.. math ::
|
||||
|
||||
@@ -533,11 +533,11 @@ class Problem_j(BaseFDEMProblem):
|
||||
:return: RHS
|
||||
"""
|
||||
|
||||
S_m, S_e = self.getSourceTerm(freq)
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
C = self.mesh.edgeCurl
|
||||
MeMuI = self.MeMuI
|
||||
|
||||
RHS = C * (MeMuI * S_m) - 1j * omega(freq) * S_e
|
||||
RHS = C * (MeMuI * s_m) - 1j * omega(freq) * s_e
|
||||
if self._makeASymmetric is True:
|
||||
MfRho = self.MfRho
|
||||
return MfRho.T*RHS
|
||||
@@ -546,7 +546,7 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
@@ -558,16 +558,16 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
C = self.mesh.edgeCurl
|
||||
MeMuI = self.MeMuI
|
||||
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
|
||||
if adjoint:
|
||||
if self._makeASymmetric:
|
||||
MfRho = self.MfRho
|
||||
v = MfRho*v
|
||||
return S_mDeriv(MeMuI.T * (C.T * v)) - 1j * omega(freq) * S_eDeriv(v)
|
||||
return s_mDeriv(MeMuI.T * (C.T * v)) - 1j * omega(freq) * s_eDeriv(v)
|
||||
|
||||
else:
|
||||
RHSDeriv = C * (MeMuI * S_mDeriv(v)) - 1j * omega(freq) * S_eDeriv(v)
|
||||
RHSDeriv = C * (MeMuI * s_mDeriv(v)) - 1j * omega(freq) * s_eDeriv(v)
|
||||
|
||||
if self._makeASymmetric:
|
||||
MfRho = self.MfRho
|
||||
@@ -577,7 +577,7 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
|
||||
|
||||
class Problem_h(BaseFDEMProblem):
|
||||
class Problem3D_h(BaseFDEMProblem):
|
||||
"""
|
||||
We eliminate \\\(\\\mathbf{j}\\\) using
|
||||
|
||||
@@ -596,7 +596,7 @@ class Problem_h(BaseFDEMProblem):
|
||||
|
||||
_solutionType = 'hSolution'
|
||||
_formulation = 'HJ'
|
||||
fieldsPair = Fields_h
|
||||
fieldsPair = Fields3D_h
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -626,12 +626,12 @@ class Problem_h(BaseFDEMProblem):
|
||||
.. math::
|
||||
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = \mathbf{C}^{\\top}\\frac{d \mathbf{M^f_{\\rho}}\mathbf{v} }{d\mathbf{m}}
|
||||
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nE,)
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nE,)
|
||||
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
"""
|
||||
|
||||
MeMu = self.MeMu
|
||||
@@ -644,26 +644,26 @@ class Problem_h(BaseFDEMProblem):
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Right hand side for the system
|
||||
Right hand side for the system
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{RHS} = \mathbf{M^e} \mathbf{s_m} + \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{s_e}
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
"""
|
||||
|
||||
S_m, S_e = self.getSourceTerm(freq)
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
C = self.mesh.edgeCurl
|
||||
MfRho = self.MfRho
|
||||
|
||||
return S_m + C.T * ( MfRho * S_e )
|
||||
return s_m + C.T * ( MfRho * s_e )
|
||||
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
@@ -673,17 +673,17 @@ class Problem_h(BaseFDEMProblem):
|
||||
:return: product of rhs deriv with a vector
|
||||
"""
|
||||
|
||||
_, S_e = src.eval(self)
|
||||
_, s_e = src.eval(self)
|
||||
C = self.mesh.edgeCurl
|
||||
MfRho = self.MfRho
|
||||
|
||||
MfRhoDeriv = self.MfRhoDeriv(S_e)
|
||||
MfRhoDeriv = self.MfRhoDeriv(s_e)
|
||||
if not adjoint:
|
||||
RHSDeriv = C.T * (MfRhoDeriv * v)
|
||||
elif adjoint:
|
||||
RHSDeriv = MfRhoDeriv.T * (C * v)
|
||||
|
||||
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
|
||||
return RHSDeriv + S_mDeriv(v) + C.T * (MfRho * S_eDeriv(v))
|
||||
return RHSDeriv + s_mDeriv(v) + C.T * (MfRho * s_eDeriv(v))
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import SimPEG
|
||||
from SimPEG import sp
|
||||
|
||||
class BaseRx(SimPEG.Survey.BaseRx):
|
||||
"""
|
||||
Frequency domain receiver base class
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
assert(orientation in ['x','y','z']), "Orientation %s not known. Orientation must be in 'x', 'y', 'z'. Arbitrary orientations have not yet been implemented."%orientation
|
||||
assert(component in ['real', 'imag']), "'component' must be 'real' or 'imag', not %s"%component
|
||||
|
||||
self.projComp = orientation
|
||||
self.component = component
|
||||
|
||||
SimPEG.Survey.BaseRx.__init__(self, locs, rxType=None) #TODO: remove rxType from baseRx
|
||||
|
||||
def projGLoc(self, u):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
return u._GLoc(self.projField) + self.projComp
|
||||
|
||||
def eval(self, src, mesh, f):
|
||||
"""
|
||||
Project fields to recievers to get data.
|
||||
|
||||
:param Source src: FDEM source
|
||||
:param Mesh mesh: mesh used
|
||||
:param Fields f: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
f_part_complex = f[src, self.projField]
|
||||
f_part = getattr(f_part_complex, self.component) # get the real or imag component
|
||||
|
||||
return P*f_part
|
||||
|
||||
def evalDeriv(self, src, mesh, f, v, adjoint=False):
|
||||
"""
|
||||
Derivative of projected fields with respect to the inversion model times a vector.
|
||||
|
||||
:param Source src: FDEM source
|
||||
:param Mesh mesh: mesh used
|
||||
:param Fields f: fields object
|
||||
:param numpy.ndarray v: vector to multiply
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
|
||||
if not adjoint:
|
||||
Pv_complex = P * v
|
||||
Pv = getattr(Pv_complex, self.component)
|
||||
elif adjoint:
|
||||
Pv_real = P.T * v
|
||||
|
||||
if self.component == 'imag':
|
||||
Pv = 1j*Pv_real
|
||||
elif self.component == 'real':
|
||||
Pv = Pv_real.astype(complex)
|
||||
else:
|
||||
raise NotImplementedError('must be real or imag')
|
||||
|
||||
return Pv
|
||||
|
||||
|
||||
class Point_e(BaseRx):
|
||||
"""
|
||||
Electric field FDEM receiver
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
self.projField = 'e'
|
||||
super(Point_e, self).__init__(locs, orientation, component)
|
||||
|
||||
|
||||
class Point_b(BaseRx):
|
||||
"""
|
||||
Magnetic flux FDEM receiver
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
self.projField = 'b'
|
||||
super(Point_b, self).__init__(locs, orientation, component)
|
||||
|
||||
|
||||
class Point_h(BaseRx):
|
||||
"""
|
||||
Magnetic field FDEM receiver
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
self.projField = 'h'
|
||||
super(Point_h, self).__init__(locs, orientation, component)
|
||||
|
||||
|
||||
class Point_j(BaseRx):
|
||||
"""
|
||||
Current density FDEM receiver
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
self.projField = 'j'
|
||||
super(Point_j, self).__init__(locs, orientation, component)
|
||||
+76
-67
@@ -9,28 +9,33 @@ class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
|
||||
freq = None
|
||||
# rxPair = RxFDEM
|
||||
integrate = True
|
||||
integrate = False
|
||||
_ePrimary = None
|
||||
_bPrimary = None
|
||||
_hPrimary = None
|
||||
_jPrimary = None
|
||||
|
||||
def __init__(self, rxList, **kwargs):
|
||||
Survey.BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
"""
|
||||
Evaluate the source terms.
|
||||
- :math:`S_m` : magnetic source term
|
||||
- :math:`S_e` : electric source term
|
||||
- :math:`s_m` : magnetic source term
|
||||
- :math:`s_e` : electric source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: tuple with magnetic source term and electric source term
|
||||
"""
|
||||
S_m = self.S_m(prob)
|
||||
S_e = self.S_e(prob)
|
||||
return S_m, S_e
|
||||
s_m = self.s_m(prob)
|
||||
s_e = self.s_e(prob)
|
||||
return s_m, s_e
|
||||
|
||||
def evalDeriv(self, prob, v=None, adjoint=False):
|
||||
"""
|
||||
Derivatives of the source terms with respect to the inversion model
|
||||
- :code:`S_mDeriv` : derivative of the magnetic source term
|
||||
- :code:`S_eDeriv` : derivative of the electric source term
|
||||
- :code:`s_mDeriv` : derivative of the magnetic source term
|
||||
- :code:`s_eDeriv` : derivative of the electric source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
@@ -39,9 +44,9 @@ class BaseSrc(Survey.BaseSrc):
|
||||
:return: tuple with magnetic source term and electric source term derivatives times a vector
|
||||
"""
|
||||
if v is not None:
|
||||
return self.S_mDeriv(prob, v, adjoint), self.S_eDeriv(prob, v, adjoint)
|
||||
return self.s_mDeriv(prob, v, adjoint), self.s_eDeriv(prob, v, adjoint)
|
||||
else:
|
||||
return lambda v: self.S_mDeriv(prob, v, adjoint), lambda v: self.S_eDeriv(prob, v, adjoint)
|
||||
return lambda v: self.s_mDeriv(prob, v, adjoint), lambda v: self.s_eDeriv(prob, v, adjoint)
|
||||
|
||||
def bPrimary(self, prob):
|
||||
"""
|
||||
@@ -51,7 +56,9 @@ class BaseSrc(Survey.BaseSrc):
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic flux density
|
||||
"""
|
||||
return Zero()
|
||||
if self._bPrimary is None:
|
||||
return Zero()
|
||||
return self._bPrimary
|
||||
|
||||
def hPrimary(self, prob):
|
||||
"""
|
||||
@@ -61,7 +68,9 @@ class BaseSrc(Survey.BaseSrc):
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
return Zero()
|
||||
if self._hPrimary is None:
|
||||
return Zero()
|
||||
return self._hPrimary
|
||||
|
||||
def ePrimary(self, prob):
|
||||
"""
|
||||
@@ -71,7 +80,9 @@ class BaseSrc(Survey.BaseSrc):
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary electric field
|
||||
"""
|
||||
return Zero()
|
||||
if self._ePrimary is None:
|
||||
return Zero()
|
||||
return self._ePrimary
|
||||
|
||||
def jPrimary(self, prob):
|
||||
"""
|
||||
@@ -81,9 +92,11 @@ class BaseSrc(Survey.BaseSrc):
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary current density
|
||||
"""
|
||||
return Zero()
|
||||
if self._jPrimary is None:
|
||||
return Zero()
|
||||
return self._jPrimary
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
@@ -93,7 +106,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
@@ -103,7 +116,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def S_mDeriv(self, prob, v, adjoint = False):
|
||||
def s_mDeriv(self, prob, v, adjoint = False):
|
||||
"""
|
||||
Derivative of magnetic source term with respect to the inversion model
|
||||
|
||||
@@ -116,7 +129,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
return Zero()
|
||||
|
||||
def S_eDeriv(self, prob, v, adjoint = False):
|
||||
def s_eDeriv(self, prob, v, adjoint = False):
|
||||
"""
|
||||
Derivative of electric source term with respect to the inversion model
|
||||
|
||||
@@ -131,22 +144,21 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
class RawVec_e(BaseSrc):
|
||||
"""
|
||||
RawVec electric source. It is defined by the user provided vector S_e
|
||||
RawVec electric source. It is defined by the user provided vector s_e
|
||||
|
||||
:param list rxList: receiver list
|
||||
:param float freq: frequency
|
||||
:param numpy.array S_e: electric source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [True]
|
||||
:param numpy.array s_e: electric source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, S_e, integrate=True): #, ePrimary=None, bPrimary=None, hPrimary=None, jPrimary=None):
|
||||
self._S_e = np.array(S_e, dtype=complex)
|
||||
def __init__(self, rxList, freq, s_e, **kwargs):
|
||||
self._s_e = np.array(s_e, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
|
||||
BaseSrc.__init__(self, rxList)
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
@@ -155,28 +167,27 @@ class RawVec_e(BaseSrc):
|
||||
:return: electric source term on mesh
|
||||
"""
|
||||
if prob._formulation is 'EB' and self.integrate is True:
|
||||
return prob.Me * self._S_e
|
||||
return self._S_e
|
||||
return prob.Me * self._s_e
|
||||
return self._s_e
|
||||
|
||||
|
||||
class RawVec_m(BaseSrc):
|
||||
"""
|
||||
RawVec magnetic source. It is defined by the user provided vector S_m
|
||||
RawVec magnetic source. It is defined by the user provided vector s_m
|
||||
|
||||
:param float freq: frequency
|
||||
:param rxList: receiver list
|
||||
:param numpy.array S_m: magnetic source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [True]
|
||||
:param numpy.array s_m: magnetic source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, S_m, integrate=True): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()):
|
||||
self._S_m = np.array(S_m, dtype=complex)
|
||||
def __init__(self, rxList, freq, s_m, **kwargs): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()):
|
||||
self._s_m = np.array(s_m, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
|
||||
BaseSrc.__init__(self, rxList)
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
@@ -185,28 +196,27 @@ class RawVec_m(BaseSrc):
|
||||
:return: magnetic source term on mesh
|
||||
"""
|
||||
if prob._formulation is 'HJ' and self.integrate is True:
|
||||
return prob.Me * self._S_m
|
||||
return self._S_m
|
||||
return prob.Me * self._s_m
|
||||
return self._s_m
|
||||
|
||||
|
||||
class RawVec(BaseSrc):
|
||||
"""
|
||||
RawVec source. It is defined by the user provided vectors S_m, S_e
|
||||
RawVec source. It is defined by the user provided vectors s_m, s_e
|
||||
|
||||
:param rxList: receiver list
|
||||
:param float freq: frequency
|
||||
:param numpy.array S_m: magnetic source term
|
||||
:param numpy.array S_e: electric source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [True]
|
||||
:param numpy.array s_m: magnetic source term
|
||||
:param numpy.array s_e: electric source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
||||
"""
|
||||
def __init__(self, rxList, freq, S_m, S_e, integrate=True):
|
||||
self._S_m = np.array(S_m, dtype=complex)
|
||||
self._S_e = np.array(S_e, dtype=complex)
|
||||
def __init__(self, rxList, freq, s_m, s_e, **kwargs):
|
||||
self._s_m = np.array(s_m, dtype=complex)
|
||||
self._s_e = np.array(s_e, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
BaseSrc.__init__(self, rxList)
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
@@ -215,10 +225,10 @@ class RawVec(BaseSrc):
|
||||
:return: magnetic source term on mesh
|
||||
"""
|
||||
if prob._formulation is 'HJ' and self.integrate is True:
|
||||
return prob.Me * self._S_m
|
||||
return self._S_m
|
||||
return prob.Me * self._s_m
|
||||
return self._s_m
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
@@ -227,8 +237,8 @@ class RawVec(BaseSrc):
|
||||
:return: electric source term on mesh
|
||||
"""
|
||||
if prob._formulation is 'EB' and self.integrate is True:
|
||||
return prob.Me * self._S_e
|
||||
return self._S_e
|
||||
return prob.Me * self._s_e
|
||||
return self._s_e
|
||||
|
||||
|
||||
class MagDipole(BaseSrc):
|
||||
@@ -278,14 +288,13 @@ class MagDipole(BaseSrc):
|
||||
:param float mu: background magnetic permeability
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu=mu_0):
|
||||
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu=mu_0, **kwargs):
|
||||
self.freq = float(freq)
|
||||
self.loc = loc
|
||||
self.orientation = orientation
|
||||
assert orientation in ['X','Y','Z'], "Orientation (right now) doesn't actually do anything! The methods in SrcUtils should take care of this..."
|
||||
self.moment = moment
|
||||
self.mu = mu
|
||||
self.integrate = False
|
||||
BaseSrc.__init__(self, rxList)
|
||||
|
||||
def bPrimary(self, prob):
|
||||
@@ -335,9 +344,9 @@ class MagDipole(BaseSrc):
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
b = self.bPrimary(prob)
|
||||
return 1./self.mu * b
|
||||
return 1./self.mu * b
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
@@ -348,10 +357,10 @@ class MagDipole(BaseSrc):
|
||||
|
||||
b_p = self.bPrimary(prob)
|
||||
if prob._formulation is 'HJ':
|
||||
b_p = prob.Me * b_p
|
||||
b_p = prob.Me * b_p
|
||||
return -1j*omega(self.freq)*b_p
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
@@ -453,7 +462,7 @@ class MagDipole_Bfield(BaseSrc):
|
||||
b = self.bPrimary(prob)
|
||||
return 1/self.mu * b
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
@@ -466,7 +475,7 @@ class MagDipole_Bfield(BaseSrc):
|
||||
b = prob.Me * b
|
||||
return -1j*omega(self.freq)*b
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
@@ -543,7 +552,7 @@ class CircularLoop(BaseSrc):
|
||||
if not prob.mesh.isSymmetric:
|
||||
# TODO ?
|
||||
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
|
||||
a = MagneticDipoleVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
|
||||
a = MagneticLoopVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
|
||||
|
||||
else:
|
||||
srcfct = MagneticDipoleVectorPotential
|
||||
@@ -565,7 +574,7 @@ class CircularLoop(BaseSrc):
|
||||
b = self.bPrimary(prob)
|
||||
return 1./self.mu*b
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
@@ -578,7 +587,7 @@ class CircularLoop(BaseSrc):
|
||||
b = prob.Me * b
|
||||
return -1j*omega(self.freq)*b
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
@@ -604,6 +613,6 @@ class CircularLoop(BaseSrc):
|
||||
|
||||
return -C.T * (MMui_s * self.bPrimary(prob))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,129 +1,13 @@
|
||||
import SimPEG
|
||||
from SimPEG.EM.Utils import *
|
||||
from SimPEG.EM.Base import BaseEMSurvey
|
||||
from scipy.constants import mu_0
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
import SrcFDEM as Src
|
||||
import RxFDEM as Rx
|
||||
from SimPEG import sp
|
||||
|
||||
|
||||
####################################################
|
||||
# Receivers
|
||||
####################################################
|
||||
|
||||
class Rx(SimPEG.Survey.BaseRx):
|
||||
"""
|
||||
Frequency domain receivers
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string rxType: reciever type from knownRxTypes
|
||||
"""
|
||||
|
||||
knownRxTypes = {
|
||||
'exr':['e', 'x', 'real'],
|
||||
'eyr':['e', 'y', 'real'],
|
||||
'ezr':['e', 'z', 'real'],
|
||||
'exi':['e', 'x', 'imag'],
|
||||
'eyi':['e', 'y', 'imag'],
|
||||
'ezi':['e', 'z', 'imag'],
|
||||
|
||||
'bxr':['b', 'x', 'real'],
|
||||
'byr':['b', 'y', 'real'],
|
||||
'bzr':['b', 'z', 'real'],
|
||||
'bxi':['b', 'x', 'imag'],
|
||||
'byi':['b', 'y', 'imag'],
|
||||
'bzi':['b', 'z', 'imag'],
|
||||
|
||||
'jxr':['j', 'x', 'real'],
|
||||
'jyr':['j', 'y', 'real'],
|
||||
'jzr':['j', 'z', 'real'],
|
||||
'jxi':['j', 'x', 'imag'],
|
||||
'jyi':['j', 'y', 'imag'],
|
||||
'jzi':['j', 'z', 'imag'],
|
||||
|
||||
'hxr':['h', 'x', 'real'],
|
||||
'hyr':['h', 'y', 'real'],
|
||||
'hzr':['h', 'z', 'real'],
|
||||
'hxi':['h', 'x', 'imag'],
|
||||
'hyi':['h', 'y', 'imag'],
|
||||
'hzi':['h', 'z', 'imag'],
|
||||
}
|
||||
radius = None
|
||||
|
||||
def __init__(self, locs, rxType):
|
||||
SimPEG.Survey.BaseRx.__init__(self, locs, rxType)
|
||||
|
||||
@property
|
||||
def projField(self):
|
||||
"""Field Type projection (e.g. e b ...)"""
|
||||
return self.knownRxTypes[self.rxType][0]
|
||||
|
||||
@property
|
||||
def projComp(self):
|
||||
"""Component projection (real/imag)"""
|
||||
return self.knownRxTypes[self.rxType][2]
|
||||
|
||||
def projGLoc(self, u):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
return u._GLoc(self.rxType[0]) + self.knownRxTypes[self.rxType][1]
|
||||
|
||||
def eval(self, src, mesh, u):
|
||||
"""
|
||||
Project fields to recievers to get data.
|
||||
|
||||
:param Source src: FDEM source
|
||||
:param Mesh mesh: mesh used
|
||||
:param Fields f: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
# projGLoc = u._GLoc(self.knownRxTypes[self.rxType][0])
|
||||
# projGLoc += self.knownRxTypes[self.rxType][1]
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(u))
|
||||
u_part_complex = u[src, self.projField]
|
||||
# get the real or imag component
|
||||
real_or_imag = self.projComp
|
||||
u_part = getattr(u_part_complex, real_or_imag)
|
||||
|
||||
return P*u_part
|
||||
|
||||
def evalDeriv(self, src, mesh, u, v, adjoint=False):
|
||||
"""
|
||||
Derivative of projected fields with respect to the inversion model times a vector.
|
||||
|
||||
:param Source src: FDEM source
|
||||
:param Mesh mesh: mesh used
|
||||
:param Fields u: fields object
|
||||
:param numpy.ndarray v: vector to multiply
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(u))
|
||||
|
||||
if not adjoint:
|
||||
Pv_complex = P * v
|
||||
real_or_imag = self.projComp
|
||||
Pv = getattr(Pv_complex, real_or_imag)
|
||||
elif adjoint:
|
||||
Pv_real = P.T * v
|
||||
|
||||
real_or_imag = self.projComp
|
||||
if real_or_imag == 'imag':
|
||||
Pv = 1j*Pv_real
|
||||
elif real_or_imag == 'real':
|
||||
Pv = Pv_real.astype(complex)
|
||||
else:
|
||||
raise NotImplementedError('must be real or imag')
|
||||
|
||||
return Pv
|
||||
|
||||
|
||||
####################################################
|
||||
# Survey
|
||||
####################################################
|
||||
|
||||
class Survey(SimPEG.Survey.BaseSurvey):
|
||||
class Survey(BaseEMSurvey):
|
||||
"""
|
||||
Frequency domain electromagnetic survey
|
||||
|
||||
@@ -131,12 +15,12 @@ class Survey(SimPEG.Survey.BaseSurvey):
|
||||
"""
|
||||
|
||||
srcPair = Src.BaseSrc
|
||||
rxPaair = Rx
|
||||
rxPair = Rx.BaseRx
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
# Sort these by frequency
|
||||
self.srcList = srcList
|
||||
SimPEG.Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
|
||||
_freqDict = {}
|
||||
for src in srcList:
|
||||
@@ -171,24 +55,8 @@ class Survey(SimPEG.Survey.BaseSurvey):
|
||||
Returns the sources associated with a specific frequency.
|
||||
:param float freq: frequency for which we look up sources
|
||||
:rtype: dictionary
|
||||
:return: sources at the sepcified frequency
|
||||
:return: sources at the sepcified frequency
|
||||
"""
|
||||
assert freq in self._freqDict, "The requested frequency is not in this survey."
|
||||
return self._freqDict[freq]
|
||||
|
||||
def eval(self, u):
|
||||
"""
|
||||
Project fields to receiver locations
|
||||
:param Fields u: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: data
|
||||
"""
|
||||
data = SimPEG.Survey.Data(self)
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.eval(src, self.mesh, u)
|
||||
return data
|
||||
|
||||
def evalDeriv(self, u):
|
||||
raise Exception('Use Receivers to project fields deriv.')
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from SurveyFDEM import Rx, Src, Survey
|
||||
from FDEM import BaseFDEMProblem, Problem_e, Problem_b, Problem_j, Problem_h
|
||||
from FieldsFDEM import *
|
||||
from SurveyFDEM import Survey
|
||||
import SrcFDEM as Src
|
||||
import RxFDEM as Rx
|
||||
from ProblemFDEM import Problem3D_e, Problem3D_b, Problem3D_j, Problem3D_h
|
||||
from FieldsFDEM import Fields3D_e, Fields3D_b, Fields3D_j, Fields3D_h
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
import numpy as np
|
||||
|
||||
def getxBCyBC_CC(mesh, alpha, beta, gamma):
|
||||
# def getxBCyBC(mesh, alpha, beta, gamma):
|
||||
"""
|
||||
This is a subfunction generating mixed-boundary condition:
|
||||
|
||||
.. math::
|
||||
|
||||
\nabla \cdot \vec{j} = -\nabla \cdot \vec{j}_s = q
|
||||
|
||||
\rho \vec{j} = -\nabla \phi \phi
|
||||
|
||||
\alpha \phi + \beta \frac{\partial \phi}{\partial r} = \gamma \ at \ r = \partial \Omega
|
||||
|
||||
xBC = f_1(\alpha, \beta, \gamma)
|
||||
yBC = f(\alpha, \beta, \gamma)
|
||||
|
||||
Computes xBC and yBC for cell-centered discretizations
|
||||
"""
|
||||
if mesh.dim == 1: #1D
|
||||
if (len(alpha) != 2 or len(beta) != 2 or len(gamma) != 2):
|
||||
raise Exception("Lenght of list, alpha should be 2")
|
||||
fCCxm,fCCxp = mesh.cellBoundaryInd
|
||||
nBC = fCCxm.sum()+fCCxp.sum()
|
||||
h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp]
|
||||
|
||||
alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0]
|
||||
alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1]
|
||||
|
||||
# h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp]
|
||||
h_xm, h_xp = mesh.hx[0], mesh.hx[-1]
|
||||
|
||||
a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
|
||||
xBC_xm = 0.5*a_xm
|
||||
xBC_xp = 0.5*a_xp/b_xp
|
||||
yBC_xm = 0.5*(1.-b_xm)
|
||||
yBC_xp = 0.5*(1.-1./b_xp)
|
||||
|
||||
xBC = np.r_[xBC_xm, xBC_xp]
|
||||
yBC = np.r_[yBC_xm, yBC_xp]
|
||||
|
||||
elif mesh.dim == 2: #2D
|
||||
if (len(alpha) != 4 or len(beta) != 4 or len(gamma) != 4):
|
||||
raise Exception("Lenght of list, alpha should be 4")
|
||||
|
||||
fxm,fxp,fym,fyp = mesh.faceBoundaryInd
|
||||
nBC = fxm.sum()+fxp.sum()+fxm.sum()+fxp.sum()
|
||||
|
||||
alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0]
|
||||
alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1]
|
||||
alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2]
|
||||
alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3]
|
||||
|
||||
# h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0]
|
||||
# h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1]
|
||||
|
||||
h_xm, h_xp = mesh.hx[0]*np.ones_like(alpha_xm), mesh.hx[-1]*np.ones_like(alpha_xp)
|
||||
h_ym, h_yp = mesh.hy[0]*np.ones_like(alpha_ym), mesh.hy[-1]*np.ones_like(alpha_yp)
|
||||
|
||||
a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
|
||||
a_ym = gamma_ym/(0.5*alpha_ym-beta_ym/h_ym)
|
||||
b_ym = (0.5*alpha_ym+beta_ym/h_ym)/(0.5*alpha_ym-beta_ym/h_ym)
|
||||
a_yp = gamma_yp/(0.5*alpha_yp-beta_yp/h_yp)
|
||||
b_yp = (0.5*alpha_yp+beta_yp/h_yp)/(0.5*alpha_yp-beta_yp/h_yp)
|
||||
|
||||
xBC_xm = 0.5*a_xm
|
||||
xBC_xp = 0.5*a_xp/b_xp
|
||||
yBC_xm = 0.5*(1.-b_xm)
|
||||
yBC_xp = 0.5*(1.-1./b_xp)
|
||||
xBC_ym = 0.5*a_ym
|
||||
xBC_yp = 0.5*a_yp/b_yp
|
||||
yBC_ym = 0.5*(1.-b_ym)
|
||||
yBC_yp = 0.5*(1.-1./b_yp)
|
||||
|
||||
sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]])
|
||||
sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]])
|
||||
|
||||
xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx]
|
||||
xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy]
|
||||
yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx]
|
||||
yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy]
|
||||
|
||||
xBC = np.r_[xBC_x, xBC_y]
|
||||
yBC = np.r_[yBC_x, yBC_y]
|
||||
|
||||
elif mesh.dim == 3: #3D
|
||||
if (len(alpha) != 6 or len(beta) != 6 or len(gamma) != 6):
|
||||
raise Exception("Lenght of list, alpha should be 6")
|
||||
# fCCxm,fCCxp,fCCym,fCCyp,fCCzm,fCCzp = mesh.cellBoundaryInd
|
||||
fxm,fxp,fym,fyp,fzm,fzp = mesh.faceBoundaryInd
|
||||
nBC = fxm.sum()+fxp.sum()+fxm.sum()+fxp.sum()
|
||||
|
||||
alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0]
|
||||
alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1]
|
||||
alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2]
|
||||
alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3]
|
||||
alpha_zm, beta_zm, gamma_zm = alpha[4], beta[4], gamma[4]
|
||||
alpha_zp, beta_zp, gamma_zp = alpha[5], beta[5], gamma[5]
|
||||
|
||||
# h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0]
|
||||
# h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1]
|
||||
# h_zm, h_zp = mesh.gridCC[fCCzm,2], mesh.gridCC[fCCzp,2]
|
||||
|
||||
h_xm, h_xp = mesh.hx[0]*np.ones_like(alpha_xm), mesh.hx[-1]*np.ones_like(alpha_xp)
|
||||
h_ym, h_yp = mesh.hy[0]*np.ones_like(alpha_ym), mesh.hy[-1]*np.ones_like(alpha_yp)
|
||||
h_zm, h_zp = mesh.hz[0]*np.ones_like(alpha_zm), mesh.hz[-1]*np.ones_like(alpha_zp)
|
||||
|
||||
a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
|
||||
a_ym = gamma_ym/(0.5*alpha_ym-beta_ym/h_ym)
|
||||
b_ym = (0.5*alpha_ym+beta_ym/h_ym)/(0.5*alpha_ym-beta_ym/h_ym)
|
||||
a_yp = gamma_yp/(0.5*alpha_yp-beta_yp/h_yp)
|
||||
b_yp = (0.5*alpha_yp+beta_yp/h_yp)/(0.5*alpha_yp-beta_yp/h_yp)
|
||||
|
||||
a_zm = gamma_zm/(0.5*alpha_zm-beta_zm/h_zm)
|
||||
b_zm = (0.5*alpha_zm+beta_zm/h_zm)/(0.5*alpha_zm-beta_zm/h_zm)
|
||||
a_zp = gamma_zp/(0.5*alpha_zp-beta_zp/h_zp)
|
||||
b_zp = (0.5*alpha_zp+beta_zp/h_zp)/(0.5*alpha_zp-beta_zp/h_zp)
|
||||
|
||||
xBC_xm = 0.5*a_xm
|
||||
xBC_xp = 0.5*a_xp/b_xp
|
||||
yBC_xm = 0.5*(1.-b_xm)
|
||||
yBC_xp = 0.5*(1.-1./b_xp)
|
||||
xBC_ym = 0.5*a_ym
|
||||
xBC_yp = 0.5*a_yp/b_yp
|
||||
yBC_ym = 0.5*(1.-b_ym)
|
||||
yBC_yp = 0.5*(1.-1./b_yp)
|
||||
xBC_zm = 0.5*a_zm
|
||||
xBC_zp = 0.5*a_zp/b_zp
|
||||
yBC_zm = 0.5*(1.-b_zm)
|
||||
yBC_zp = 0.5*(1.-1./b_zp)
|
||||
|
||||
sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]])
|
||||
sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]])
|
||||
sortindsfz = np.argsort(np.r_[np.arange(mesh.nFz)[fzm], np.arange(mesh.nFz)[fzp]])
|
||||
|
||||
xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx]
|
||||
xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy]
|
||||
xBC_z = np.r_[xBC_zm, xBC_zp][sortindsfz]
|
||||
|
||||
yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx]
|
||||
yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy]
|
||||
yBC_z = np.r_[yBC_zm, yBC_zp][sortindsfz]
|
||||
|
||||
xBC = np.r_[xBC_x, xBC_y, xBC_z]
|
||||
yBC = np.r_[yBC_x, yBC_y, yBC_z]
|
||||
|
||||
return xBC, yBC
|
||||
@@ -0,0 +1,148 @@
|
||||
import SimPEG
|
||||
from SimPEG.Utils import Identity, Zero
|
||||
import numpy as np
|
||||
from scipy.constants import epsilon_0
|
||||
|
||||
class Fields(SimPEG.Problem.Fields):
|
||||
knownFields = {}
|
||||
dtype = float
|
||||
|
||||
def _phiDeriv(self, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_phiDeriv_u', None) is None or getattr(self, '_phiDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting phiDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._phiDeriv_u(src, v, adjoint=adjoint), self._phiDeriv_m(src, v, adjoint=adjoint)
|
||||
|
||||
return np.array(self._phiDeriv_u(src, du_dm_v, adjoint) + self._phiDeriv_m(src, v, adjoint), dtype = float)
|
||||
|
||||
def _eDeriv(self, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._eDeriv_u(src, v, adjoint), self._eDeriv_m(src, v, adjoint)
|
||||
return np.array(self._eDeriv_u(src, du_dm_v, adjoint) + self._eDeriv_m(src, v, adjoint), dtype = float)
|
||||
|
||||
def _jDeriv(self, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint)
|
||||
return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = float)
|
||||
|
||||
|
||||
class Fields_CC(Fields):
|
||||
knownFields = {'phiSolution':'CC'}
|
||||
aliasFields = {
|
||||
'phi': ['phiSolution','CC','_phi'],
|
||||
'j' : ['phiSolution','F','_j'],
|
||||
'e' : ['phiSolution','F','_e'],
|
||||
'charge' : ['phiSolution','CC','_charge'],
|
||||
}
|
||||
# primary - secondary
|
||||
# CC variables
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields.__init__(self, mesh, survey, **kwargs)
|
||||
mesh.setCellGradBC("neumann")
|
||||
cellGrad = mesh.cellGrad
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
|
||||
def _GLoc(self, fieldType):
|
||||
if fieldType == 'phi':
|
||||
return 'CC'
|
||||
elif fieldType == 'e' or fieldType == 'j':
|
||||
return 'F'
|
||||
else:
|
||||
raise Exception('Field type must be phi, e, j')
|
||||
|
||||
def _phi(self, phiSolution, srcList):
|
||||
return phiSolution
|
||||
|
||||
def _phiDeriv_u(self, src, v, adjoint = False):
|
||||
return Identity()*v
|
||||
|
||||
def _phiDeriv_m(self, src, v, adjoint = False):
|
||||
return Zero()
|
||||
|
||||
def _j(self, phiSolution, srcList):
|
||||
"""
|
||||
.. math::
|
||||
\mathbf{j} = \mathbf{M}^{f \ -1}_{\rho} \mathbf{G} \phi
|
||||
"""
|
||||
return self.prob.MfRhoI*self.prob.Grad*phiSolution
|
||||
|
||||
def _e(self, phiSolution, srcList):
|
||||
"""
|
||||
In HJ formulation e is not well-defined!!
|
||||
.. math::
|
||||
\vec{e} = -\nabla \phi
|
||||
"""
|
||||
return -self.mesh.cellGrad*phiSolution
|
||||
|
||||
def _charge(self, phiSolution, srcList):
|
||||
"""
|
||||
.. math::
|
||||
\int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0}
|
||||
"""
|
||||
return epsilon_0*self.prob.Vol*(self.mesh.faceDiv*self._e(phiSolution, srcList))
|
||||
|
||||
class Fields_N(Fields):
|
||||
knownFields = {'phiSolution':'N'}
|
||||
aliasFields = {
|
||||
'phi': ['phiSolution','N','_phi'],
|
||||
'j' : ['phiSolution','E','_j'],
|
||||
'e' : ['phiSolution','E','_e'],
|
||||
'charge' : ['phiSolution','N','_charge'],
|
||||
}
|
||||
# primary - secondary
|
||||
# N variables
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields.__init__(self, mesh, survey, **kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
|
||||
def _GLoc(self, fieldType):
|
||||
if fieldType == 'phi':
|
||||
return 'N'
|
||||
elif fieldType == 'e' or fieldType == 'j':
|
||||
return 'E'
|
||||
else:
|
||||
raise Exception('Field type must be phi, e, j')
|
||||
|
||||
def _phi(self, phiSolution, srcList):
|
||||
return phiSolution
|
||||
|
||||
def _phiDeriv_u(self, src, v, adjoint = False):
|
||||
return Identity()*v
|
||||
|
||||
def _phiDeriv_m(self, src, v, adjoint = False):
|
||||
return Zero()
|
||||
|
||||
def _j(self, phiSolution, srcList):
|
||||
"""
|
||||
In EB formulation j is not well-defined!!
|
||||
.. math::
|
||||
\mathbf{j} = - \mathbf{M}^{e}_{\sigma} \mathbf{G} \phi
|
||||
"""
|
||||
return self.prob.MeSigma * self._e(phiSolution, srcList)
|
||||
|
||||
def _e(self, phiSolution, srcList):
|
||||
"""
|
||||
In HJ formulation e is not well-defined!!
|
||||
.. math::
|
||||
\vec{e} = -\nabla \phi
|
||||
"""
|
||||
return -self.mesh.nodalGrad * phiSolution
|
||||
|
||||
def _charge(self, phiSolution, srcList):
|
||||
"""
|
||||
.. math::
|
||||
\int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0}
|
||||
"""
|
||||
return - epsilon_0*(self.mesh.nodalGrad.T*self.mesh.getEdgeInnerProduct()*self._e(phiSolution, srcList))
|
||||
@@ -0,0 +1,146 @@
|
||||
import SimPEG
|
||||
from SimPEG.Utils import Identity, Zero
|
||||
import numpy as np
|
||||
|
||||
class Fields_ky(SimPEG.Problem.TimeFields):
|
||||
|
||||
"""
|
||||
|
||||
Fancy Field Storage for a 2.5D code.
|
||||
|
||||
u[:,'phi', kyInd] = phi
|
||||
print u[src0,'phi']
|
||||
|
||||
Only one field type is stored for
|
||||
each problem, the rest are computed. The fields obejct acts like an array and is indexed by
|
||||
.. code-block:: python
|
||||
f = problem.fields(m)
|
||||
e = f[srcList,'e']
|
||||
j = f[srcList,'j']
|
||||
|
||||
If accessing all sources for a given field, use the :code:`:`
|
||||
.. code-block:: python
|
||||
f = problem.fields(m)
|
||||
phi = f[:,'phi']
|
||||
e = f[:,'e']
|
||||
b = f[:,'b']
|
||||
The array returned will be size (nE or nF, nSrcs :math:`\\times` nFrequencies)
|
||||
"""
|
||||
|
||||
knownFields = {}
|
||||
dtype = float
|
||||
|
||||
def _phiDeriv(self,kyInd, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_phiDeriv_u', None) is None or getattr(self, '_phiDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting phiDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._phiDeriv_u(kyInd, src, v, adjoint=adjoint), self._phiDeriv_m(kyInd, src, v, adjoint=adjoint)
|
||||
|
||||
return np.array(self._phiDeriv_u(kyInd, src, du_dm_v, adjoint) + self._phiDeriv_m(kyInd, src, v, adjoint), dtype = float)
|
||||
|
||||
def _eDeriv(self,kyInd, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._eDeriv_u(kyInd, src, v, adjoint), self._eDeriv_m(kyInd, src, v, adjoint)
|
||||
return np.array(self._eDeriv_u(kyInd, src, du_dm_v, adjoint) + self._eDeriv_m(kyInd, src, v, adjoint), dtype = float)
|
||||
|
||||
def _jDeriv(self,kyInd, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._jDeriv_u(kyInd, src, v, adjoint), self._jDeriv_m(kyInd, src, v, adjoint)
|
||||
return np.array(self._jDeriv_u(kyInd, src, du_dm_v, adjoint) + self._jDeriv_m(kyInd, src, v, adjoint), dtype = float)
|
||||
|
||||
|
||||
# def _eDeriv(self, tInd, src, dun_dm_v, v, adjoint=False):
|
||||
# if adjoint is True:
|
||||
# return self._eDeriv_u(tInd, src, v, adjoint), self._eDeriv_m(tInd, src, v, adjoint)
|
||||
# return self._eDeriv_u(tInd, src, dun_dm_v) + self._eDeriv_m(tInd, src, v)
|
||||
|
||||
# def _bDeriv(self, tInd, src, dun_dm_v, v, adjoint=False):
|
||||
# if adjoint is True:
|
||||
# return self._bDeriv_u(tInd, src, v, adjoint), self._bDeriv_m(tInd, src, v, adjoint)
|
||||
# return self._bDeriv_u(tInd, src, dun_dm_v) + self._bDeriv_m(tInd, src, v)
|
||||
|
||||
|
||||
class Fields_ky_CC(Fields_ky):
|
||||
knownFields = {'phiSolution':'CC'}
|
||||
aliasFields = {
|
||||
'phi': ['phiSolution','CC','_phi'],
|
||||
'j' : ['phiSolution','F','_j'],
|
||||
'e' : ['phiSolution','F','_e'],
|
||||
}
|
||||
# primary - secondary
|
||||
# CC variables
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields_ky.__init__(self, mesh, survey, **kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
|
||||
def _GLoc(self, fieldType):
|
||||
if fieldType == 'phi':
|
||||
return 'CC'
|
||||
elif fieldType == 'e' or fieldType == 'j':
|
||||
return 'F'
|
||||
else:
|
||||
raise Exception('Field type must be phi, e, j')
|
||||
|
||||
def _phi(self, phiSolution, src, kyInd):
|
||||
return phiSolution
|
||||
|
||||
def _phiDeriv_u(self, kyInd, src, v, adjoint = False):
|
||||
return Identity()*v
|
||||
|
||||
def _phiDeriv_m(self, kyInd, src, v, adjoint = False):
|
||||
return Zero()
|
||||
|
||||
def _j(self, phiSolution, srcList):
|
||||
raise NotImplementedError
|
||||
|
||||
def _e(self, phiSolution, srcList):
|
||||
raise NotImplementedError
|
||||
|
||||
class Fields_ky_N(Fields_ky):
|
||||
knownFields = {'phiSolution':'N'}
|
||||
aliasFields = {
|
||||
'phi': ['phiSolution','N','_phi'],
|
||||
'j' : ['phiSolution','E','_j'],
|
||||
'e' : ['phiSolution','E','_e'],
|
||||
}
|
||||
# primary - secondary
|
||||
# CC variables
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields_ky.__init__(self, mesh, survey, **kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
|
||||
def _GLoc(self, fieldType):
|
||||
if fieldType == 'phi':
|
||||
return 'N'
|
||||
elif fieldType == 'e' or fieldType == 'j':
|
||||
return 'E'
|
||||
else:
|
||||
raise Exception('Field type must be phi, e, j')
|
||||
|
||||
def _phi(self, phiSolution, src, kyInd):
|
||||
return phiSolution
|
||||
|
||||
def _phiDeriv_u(self, kyInd, src, v, adjoint = False):
|
||||
return Identity()*v
|
||||
|
||||
def _phiDeriv_m(self, kyInd, src, v, adjoint = False):
|
||||
return Zero()
|
||||
|
||||
def _j(self, phiSolution, srcList):
|
||||
raise NotImplementedError
|
||||
|
||||
def _e(self, phiSolution, srcList):
|
||||
raise NotImplementedError
|
||||
@@ -0,0 +1,296 @@
|
||||
from SimPEG import Problem, Utils
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SurveyDC import Survey
|
||||
from FieldsDC import Fields, Fields_CC, Fields_N
|
||||
from SimPEG.Utils import sdiag
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero
|
||||
from BoundaryUtils import getxBCyBC_CC
|
||||
|
||||
class BaseDCProblem(BaseEMProblem):
|
||||
|
||||
surveyPair = Survey
|
||||
fieldsPair = Fields
|
||||
Ainv = None
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
|
||||
if not self.Ainv == None:
|
||||
self.Ainv.clean()
|
||||
|
||||
f = self.fieldsPair(self.mesh, self.survey)
|
||||
A = self.getA()
|
||||
self.Ainv = self.Solver(A, **self.solverOpts)
|
||||
RHS = self.getRHS()
|
||||
u = self.Ainv * RHS
|
||||
Srcs = self.survey.srcList
|
||||
f[Srcs, self._solutionType] = u
|
||||
return f
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
|
||||
A = self.getA()
|
||||
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType] # solution vector
|
||||
dA_dm_v = self.getADeriv(u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(src, v)
|
||||
du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
|
||||
for rx in src.rxList:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv = np.zeros(m.size)
|
||||
AT = self.getA()
|
||||
|
||||
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType]
|
||||
for rx in src.rxList:
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
||||
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
|
||||
ATinvdf_duT = self.Ainv * df_duT
|
||||
|
||||
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
Jtv += (df_dmT + du_dmT).astype(float)
|
||||
|
||||
return Utils.mkvc(Jtv)
|
||||
|
||||
def getSourceTerm(self):
|
||||
"""
|
||||
takes concept of source and turns it into a matrix
|
||||
"""
|
||||
"""
|
||||
Evaluates the sources, and puts them in matrix form
|
||||
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: q (nC or nN, nSrc)
|
||||
"""
|
||||
|
||||
Srcs = self.survey.srcList
|
||||
|
||||
if self._formulation is 'EB':
|
||||
n = self.mesh.nN
|
||||
# return NotImplementedError
|
||||
|
||||
elif self._formulation is 'HJ':
|
||||
n = self.mesh.nC
|
||||
|
||||
q = np.zeros((n, len(Srcs)))
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
q[:,i] = src.eval(self)
|
||||
return q
|
||||
|
||||
class Problem3D_CC(BaseDCProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'HJ' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_CC
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseDCProblem.__init__(self, mesh, **kwargs)
|
||||
self.setBC()
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoI = self.MfRhoI
|
||||
A = D * MfRhoI * G
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * A
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint= False):
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoIDeriv = self.MfRhoIDeriv
|
||||
|
||||
if adjoint:
|
||||
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
|
||||
|
||||
return D * (MfRhoIDeriv( G * u ) * v)
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
def setBC(self):
|
||||
if self.mesh.dim==3:
|
||||
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
gBFzm = self.mesh.gridFz[fzm,:]
|
||||
gBFzp = self.mesh.gridFz[fzp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
beta_zm, beta_zp = temp_zm, temp_zp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
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]
|
||||
|
||||
elif self.mesh.dim==2:
|
||||
|
||||
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
||||
|
||||
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
||||
V = self.Vol
|
||||
self.Div = V * self.mesh.faceDiv
|
||||
P_BC, B = self.mesh.getBCProjWF_simple()
|
||||
M = B*self.mesh.aveCC2F
|
||||
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
||||
|
||||
|
||||
class Problem3D_N(BaseDCProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'EB' # N potentials means B is on faces
|
||||
fieldsPair = Fields_N
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseDCProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = G.T MeSigma G
|
||||
|
||||
"""
|
||||
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
A = Grad.T * MeSigma * Grad
|
||||
|
||||
# Handling Null space of A
|
||||
A[0,0] = A[0,0] + 1.
|
||||
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint=False):
|
||||
"""
|
||||
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
"""
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
if not adjoint:
|
||||
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
|
||||
elif adjoint:
|
||||
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
|
||||
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
from SimPEG import Problem, Utils
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SurveyDC import Survey, Survey_ky
|
||||
from FieldsDC_2D import Fields_ky, Fields_ky_CC, Fields_ky_N
|
||||
from SimPEG.Utils import sdiag
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero
|
||||
from BoundaryUtils import getxBCyBC_CC
|
||||
|
||||
class BaseDCProblem_2D(BaseEMProblem):
|
||||
|
||||
surveyPair = Survey_ky
|
||||
fieldsPair = Fields_ky
|
||||
nky = 15
|
||||
kys = np.logspace(-4, 1, nky)
|
||||
Ainv = [None for i in range(nky)]
|
||||
nT = nky # Only for using TimeFields
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
|
||||
if not self.Ainv[0] == None:
|
||||
for i in range(self.nky):
|
||||
self.Ainv[i].clean()
|
||||
|
||||
f = self.fieldsPair(self.mesh, self.survey)
|
||||
Srcs = self.survey.srcList
|
||||
for iky in range(self.nky):
|
||||
ky = self.kys[iky]
|
||||
A = self.getA(ky)
|
||||
self.Ainv[iky] = self.Solver(A, **self.solverOpts)
|
||||
RHS = self.getRHS(ky)
|
||||
u = self.Ainv[iky] * RHS
|
||||
f[Srcs, self._solutionType, iky] = u
|
||||
return f
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
Jv0 = self.dataPair(self.survey)
|
||||
|
||||
# Assume y=0.
|
||||
# This needs some thoughts to implement in general when src is dipole
|
||||
dky = np.diff(self.kys)
|
||||
dky = np.r_[dky[0], dky]
|
||||
y = 0.
|
||||
|
||||
#TODO: this loop is pretty slow .. (Parellize)
|
||||
for iky in range(self.nky):
|
||||
ky = self.kys[iky]
|
||||
A = self.getA(ky)
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType, iky] # solution vector
|
||||
dA_dm_v = self.getADeriv(ky, u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(ky, src, v)
|
||||
du_dm_v = self.Ainv[iky] * ( - dA_dm_v + dRHS_dm_v )
|
||||
for rx in src.rxList:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(iky, src, du_dm_v, v, adjoint=False)
|
||||
# Trapezoidal intergration
|
||||
Jv1_temp = 1./np.pi*rx.evalDeriv(ky, src, self.mesh, f, df_dm_v)
|
||||
if iky==0:
|
||||
#First assigment
|
||||
Jv[src, rx] = Jv1_temp*dky[iky]*np.cos(ky*y)
|
||||
else:
|
||||
Jv[src, rx] += Jv1_temp*dky[iky] /2.*np.cos(ky*y)
|
||||
Jv[src, rx] += Jv0[src, rx]*dky[iky]/2.*np.cos(ky*y)
|
||||
Jv0[src, rx] = Jv1_temp.copy()
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv = np.zeros(m.size, dtype=float)
|
||||
|
||||
# Assume y=0.
|
||||
# This needs some thoughts to implement in general when src is dipole
|
||||
dky = np.diff(self.kys)
|
||||
dky = np.r_[dky[0], dky]
|
||||
y = 0.
|
||||
|
||||
for src in self.survey.srcList:
|
||||
for rx in src.rxList:
|
||||
Jtv_temp1 = np.zeros(m.size, dtype=float)
|
||||
Jtv_temp0 = np.zeros(m.size, dtype=float)
|
||||
#TODO: this loop is pretty slow .. (Parellize)
|
||||
for iky in range(self.nky):
|
||||
u_src = f[src, self._solutionType, iky]
|
||||
ky = self.kys[iky]
|
||||
AT = self.getA(ky)
|
||||
PTv = rx.evalDeriv(ky, src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
||||
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(iky, src, None, PTv, adjoint=True)
|
||||
|
||||
ATinvdf_duT = self.Ainv[iky] * df_duT
|
||||
|
||||
dA_dmT = self.getADeriv(ky, u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv(ky, src, ATinvdf_duT, adjoint=True)
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
Jtv_temp1 = 1./np.pi*(df_dmT + du_dmT).astype(float)
|
||||
# Trapezoidal intergration
|
||||
if iky==0:
|
||||
#First assigment
|
||||
Jtv += Jtv_temp1*dky[iky]*np.cos(ky*y)
|
||||
else:
|
||||
Jtv += Jtv_temp1*dky[iky]/2.*np.cos(ky*y)
|
||||
Jtv += Jtv_temp0*dky[iky]/2.*np.cos(ky*y)
|
||||
Jtv_temp0 = Jtv_temp1.copy()
|
||||
return Utils.mkvc(Jtv)
|
||||
|
||||
def getSourceTerm(self, ky):
|
||||
"""
|
||||
takes concept of source and turns it into a matrix
|
||||
"""
|
||||
"""
|
||||
Evaluates the sources, and puts them in matrix form
|
||||
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: q (nC or nN, nSrc)
|
||||
"""
|
||||
|
||||
Srcs = self.survey.srcList
|
||||
|
||||
if self._formulation is 'EB':
|
||||
n = self.mesh.nN
|
||||
# return NotImplementedError
|
||||
|
||||
elif self._formulation is 'HJ':
|
||||
n = self.mesh.nC
|
||||
|
||||
q = np.zeros((n, len(Srcs)))
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
q[:,i] = src.eval(self)
|
||||
return q
|
||||
|
||||
class Problem2D_CC(BaseDCProblem_2D):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'HJ' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_ky_CC
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseDCProblem_2D.__init__(self, mesh, **kwargs)
|
||||
self.setBC()
|
||||
|
||||
def getA(self, ky):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
vol = self.mesh.vol
|
||||
MfRhoI = self.MfRhoI
|
||||
# Get resistivity rho
|
||||
rho = self.curModel.rho
|
||||
A = D * MfRhoI * G + Utils.sdiag(ky**2*vol/rho)
|
||||
return A
|
||||
|
||||
def getADeriv(self, ky, u, v, adjoint= False):
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
vol = self.mesh.vol
|
||||
MfRhoIDeriv = self.MfRhoIDeriv
|
||||
rho = self.curModel.rho
|
||||
if adjoint:
|
||||
return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v
|
||||
return D * ((MfRhoIDeriv( G * u )) * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v
|
||||
|
||||
def getRHS(self, ky):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm(ky)
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, ky, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, ky, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
def setBC(self):
|
||||
if self.mesh.dim==3:
|
||||
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
gBFzm = self.mesh.gridFz[fzm,:]
|
||||
gBFzp = self.mesh.gridFz[fzp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
beta_zm, beta_zp = temp_zm, temp_zp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
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]
|
||||
|
||||
elif self.mesh.dim==2:
|
||||
|
||||
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
||||
|
||||
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
||||
V = self.Vol
|
||||
self.Div = V * self.mesh.faceDiv
|
||||
P_BC, B = self.mesh.getBCProjWF_simple()
|
||||
M = B*self.mesh.aveCC2F
|
||||
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
||||
|
||||
class Problem2D_N(BaseDCProblem_2D):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'EB' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_ky_N
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseDCProblem_2D.__init__(self, mesh, **kwargs)
|
||||
# self.setBC()
|
||||
|
||||
@property
|
||||
def MnSigma(self):
|
||||
"""
|
||||
Node inner product matrix for \\(\\sigma\\). Used in the E-B formulation
|
||||
"""
|
||||
# TODO: only works isotropic sigma
|
||||
sigma = self.curModel.sigma
|
||||
vol = self.mesh.vol
|
||||
MnSigma = Utils.sdiag(self.mesh.aveN2CC.T*(Utils.sdiag(vol)*sigma))
|
||||
|
||||
return MnSigma
|
||||
|
||||
def MnSigmaDeriv(self, u):
|
||||
"""
|
||||
Derivative of MnSigma with respect to the model
|
||||
"""
|
||||
sigma = self.curModel.sigma
|
||||
sigmaderiv = self.curModel.sigmaDeriv
|
||||
vol = self.mesh.vol
|
||||
return Utils.sdiag(u)*self.mesh.aveN2CC.T*Utils.sdiag(vol) * self.curModel.sigmaDeriv
|
||||
|
||||
def getA(self, ky):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
MeSigma = self.MeSigma
|
||||
MnSigma = self.MnSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
# Get conductivity sigma
|
||||
sigma = self.curModel.sigma
|
||||
A = Grad.T * MeSigma * Grad + ky**2*MnSigma
|
||||
|
||||
# Handling Null space of A
|
||||
A[0,0] = A[0,0] + 1.
|
||||
return A
|
||||
|
||||
def getADeriv(self, ky, u, v, adjoint= False):
|
||||
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
sigma = self.curModel.sigma
|
||||
vol = self.mesh.vol
|
||||
|
||||
if adjoint:
|
||||
return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + ky**2*self.MnSigmaDeriv(u).T*v
|
||||
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + ky**2*self.MnSigmaDeriv(u)*v
|
||||
|
||||
def getRHS(self, ky):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm(ky)
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, ky, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, ky, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
@@ -0,0 +1,129 @@
|
||||
import SimPEG
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero, closestPoints
|
||||
|
||||
class BaseRx(SimPEG.Survey.BaseRx):
|
||||
locs = None
|
||||
rxType = None
|
||||
|
||||
knownRxTypes = {
|
||||
'phi':['phi',None],
|
||||
'ex':['e','x'],
|
||||
'ey':['e','y'],
|
||||
'ez':['e','z'],
|
||||
'jx':['j','x'],
|
||||
'jy':['j','y'],
|
||||
'jz':['j','z'],
|
||||
}
|
||||
|
||||
def __init__(self, locs, rxType, **kwargs):
|
||||
SimPEG.Survey.BaseRx.__init__(self, locs, rxType, **kwargs)
|
||||
|
||||
|
||||
@property
|
||||
def projField(self):
|
||||
"""Field Type projection (e.g. e b ...)"""
|
||||
return self.knownRxTypes[self.rxType][0]
|
||||
|
||||
def projGLoc(self, f):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
comp = self.knownRxTypes[self.rxType][1]
|
||||
if comp is not None:
|
||||
return f._GLoc(self.rxType) + comp
|
||||
return f._GLoc(self.rxType)
|
||||
|
||||
def eval(self, src, mesh, f):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
return P*f[src, self.projField]
|
||||
|
||||
def evalDeriv(self, src, mesh, f, v, adjoint=False):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
if not adjoint:
|
||||
return P*v
|
||||
elif adjoint:
|
||||
return P.T*v
|
||||
|
||||
# DC.Rx.Dipole(locs)
|
||||
class Dipole(BaseRx):
|
||||
|
||||
def __init__(self, locsM, locsN, rxType = 'phi', **kwargs):
|
||||
assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size'
|
||||
locs = [locsM, locsN]
|
||||
# We may not need this ...
|
||||
BaseRx.__init__(self, locs, rxType)
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data in the receiver."""
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
# Not sure why ...
|
||||
# return int(self.locs[0].size / 2)
|
||||
|
||||
|
||||
def getP(self, mesh, Gloc):
|
||||
if mesh in self._Ps:
|
||||
return self._Ps[mesh]
|
||||
|
||||
P0 = mesh.getInterpolationMat(self.locs[0], Gloc)
|
||||
P1 = mesh.getInterpolationMat(self.locs[1], Gloc)
|
||||
P = P0 - P1
|
||||
|
||||
if self.storeProjections:
|
||||
self._Ps[mesh] = P
|
||||
|
||||
return P
|
||||
|
||||
|
||||
class Dipole_ky(BaseRx):
|
||||
|
||||
def __init__(self, locsM, locsN, rxType = 'phi', **kwargs):
|
||||
assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size'
|
||||
locs = [locsM, locsN]
|
||||
# We may not need this ...
|
||||
BaseRx.__init__(self, locs, rxType)
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data in the receiver."""
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
# Not sure why ...
|
||||
# return int(self.locs[0].size / 2)
|
||||
|
||||
def getP(self, mesh, Gloc):
|
||||
if mesh in self._Ps:
|
||||
return self._Ps[mesh]
|
||||
|
||||
P0 = mesh.getInterpolationMat(self.locs[0], Gloc)
|
||||
P1 = mesh.getInterpolationMat(self.locs[1], Gloc)
|
||||
P = P0 - P1
|
||||
if self.storeProjections:
|
||||
self._Ps[mesh] = P
|
||||
return P
|
||||
|
||||
def eval(self, kys, src, mesh, f):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
Pf = P*f[src, self.projField,:]
|
||||
return self.IntTrapezoidal(kys, Pf, y=0.)
|
||||
|
||||
def evalDeriv(self, ky, src, mesh, f, v, adjoint=False):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
if not adjoint:
|
||||
return P*v
|
||||
elif adjoint:
|
||||
return P.T*v
|
||||
|
||||
def IntTrapezoidal(self, kys, Pf, y=0.):
|
||||
phi = np.zeros(Pf.shape[0])
|
||||
nky = kys.size
|
||||
dky = np.diff(kys)
|
||||
dky = np.r_[dky[0], dky]
|
||||
phi0 = 1./np.pi*Pf[:,0]
|
||||
for iky in range(nky):
|
||||
phi1 = 1./np.pi*Pf[:,iky]
|
||||
phi += phi1*dky[iky]/2.*np.cos(kys[iky]*y)
|
||||
phi += phi0*dky[iky]/2.*np.cos(kys[iky]*y)
|
||||
phi0 = phi1.copy()
|
||||
return phi
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import SimPEG
|
||||
# from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG.Utils import Zero, closestPoints, mkvc
|
||||
import numpy as np
|
||||
|
||||
class BaseSrc(SimPEG.Survey.BaseSrc):
|
||||
|
||||
current = 1.0
|
||||
loc = None
|
||||
|
||||
def __init__(self, rxList, **kwargs):
|
||||
SimPEG.Survey.BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
raise NotImplementedError
|
||||
|
||||
def evalDeriv(self, prob):
|
||||
return Zero()
|
||||
|
||||
|
||||
class Dipole(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, locA, locB, **kwargs):
|
||||
assert locA.shape == locB.shape, 'Shape of locA and locB should be the same'
|
||||
self.loc = [locA, locB]
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
if prob._formulation == 'HJ':
|
||||
inds = closestPoints(prob.mesh, self.loc, gridLoc='CC')
|
||||
q = np.zeros(prob.mesh.nC)
|
||||
q[inds] = self.current * np.r_[1., -1.]
|
||||
elif prob._formulation == 'EB':
|
||||
qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense()
|
||||
qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense()
|
||||
q = self.current * mkvc(qa+qb)
|
||||
return q
|
||||
|
||||
class Pole(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, loc, **kwargs):
|
||||
BaseSrc.__init__(self, rxList, loc=loc, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
if prob._formulation == 'HJ':
|
||||
inds = closestPoints(prob.mesh, self.loc)
|
||||
q = np.zeros(prob.mesh.nC)
|
||||
q[inds] = self.current * np.r_[1.]
|
||||
elif prob._formulation == 'EB':
|
||||
q = prob.mesh.getInterpolationMat(self.loc, locType='N').todense()
|
||||
q = self.current * mkvc(q)
|
||||
return q
|
||||
|
||||
|
||||
# class Dipole_ky(BaseSrc):
|
||||
|
||||
# def __init__(self, rxList, locA, locB, **kwargs):
|
||||
# assert locA.shape == locB.shape, 'Shape of locA and locB should be the same'
|
||||
# self.loc = [locA[[0,2]], locB[[0,2]]]
|
||||
# BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
# def eval(self, prob):
|
||||
# if prob._formulation == 'HJ':
|
||||
# inds = closestPoints(prob.mesh, self.loc, gridLoc='CC')
|
||||
# q = np.zeros(prob.mesh.nC)
|
||||
# q[inds] = self.current * np.r_[1., -1.]
|
||||
# elif prob._formulation == 'EB':
|
||||
# qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense()
|
||||
# qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense()
|
||||
# q = self.current * mkvc(qa+qb)
|
||||
# return q
|
||||
|
||||
# class Pole_ky(BaseSrc):
|
||||
|
||||
# def __init__(self, rxList, loc, **kwargs):
|
||||
# BaseSrc.__init__(self, rxList, loc=loc, **kwargs)
|
||||
|
||||
# def eval(self, prob):
|
||||
# if prob._formulation == 'HJ':
|
||||
# inds = closestPoints(prob.mesh, self.loc[[0,2]])
|
||||
# q = np.zeros(prob.mesh.nC)
|
||||
# q[inds] = self.current * np.r_[1.]
|
||||
# elif prob._formulation == 'EB':
|
||||
# q = prob.mesh.getInterpolationMat(self.loc[[0,2]], locType='N').todense()
|
||||
# q = self.current * mkvc(q)
|
||||
# return q
|
||||
@@ -0,0 +1,38 @@
|
||||
import SimPEG
|
||||
from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG import sp, Survey
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
from RxDC import BaseRx
|
||||
from SrcDC import BaseSrc
|
||||
|
||||
class Survey(BaseEMSurvey):
|
||||
rxPair = BaseRx
|
||||
srcPair = BaseSrc
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
self.srcList = srcList
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
|
||||
class Survey_ky(BaseEMSurvey):
|
||||
rxPair = BaseRx
|
||||
srcPair = BaseSrc
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
self.srcList = srcList
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
|
||||
def eval(self, f):
|
||||
"""
|
||||
Project fields to receiver locations
|
||||
:param Fields u: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: data
|
||||
"""
|
||||
data = SimPEG.Survey.Data(self)
|
||||
kys = self.prob.kys
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.eval(kys, src, self.mesh, f)
|
||||
return data
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import numpy as np
|
||||
|
||||
def WennerSrcList(nElecs, aSpacing, in2D=False, plotIt=False):
|
||||
|
||||
import SimPEG.EM.Static.DC as DC
|
||||
|
||||
elocs = np.arange(0,aSpacing*nElecs,aSpacing)
|
||||
elocs -= (nElecs*aSpacing - aSpacing)/2
|
||||
space = 1
|
||||
WENNER = np.zeros((0,),dtype=int)
|
||||
for ii in range(nElecs):
|
||||
for jj in range(nElecs):
|
||||
test = np.r_[jj,jj+space,jj+space*2,jj+space*3]
|
||||
if np.any(test >= nElecs):
|
||||
break
|
||||
WENNER = np.r_[WENNER, test]
|
||||
space += 1
|
||||
WENNER = WENNER.reshape((-1,4))
|
||||
|
||||
|
||||
if plotIt:
|
||||
for i, s in enumerate('rbkg'):
|
||||
plt.plot(elocs[WENNER[:,i]],s+'.')
|
||||
plt.show()
|
||||
|
||||
# Create sources and receivers
|
||||
i = 0
|
||||
if in2D:
|
||||
getLoc = lambda ii, abmn: np.r_[elocs[WENNER[ii,abmn]],0]
|
||||
else:
|
||||
getLoc = lambda ii, abmn: np.r_[elocs[WENNER[ii,abmn]],0, 0]
|
||||
srcList = []
|
||||
for i in range(WENNER.shape[0]):
|
||||
rx = DC.Rx.Dipole(getLoc(i,1).reshape([1,-1]),getLoc(i,2).reshape([1,-1]))
|
||||
src = DC.Src.Dipole([rx], getLoc(i,0),getLoc(i,3))
|
||||
srcList += [src]
|
||||
|
||||
return srcList
|
||||
@@ -0,0 +1,8 @@
|
||||
from ProblemDC import Problem3D_CC, Problem3D_N
|
||||
from ProblemDC_2D import Problem2D_CC, Problem2D_N
|
||||
from SurveyDC import Survey, Survey_ky
|
||||
import SrcDC as Src #Pole
|
||||
import RxDC as Rx
|
||||
from FieldsDC import Fields_CC
|
||||
from BoundaryUtils import getxBCyBC_CC
|
||||
import Utils
|
||||
@@ -0,0 +1,372 @@
|
||||
from SimPEG import Problem, Utils, Maps, Mesh
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SimPEG.EM.Static.DC.FieldsDC import Fields, Fields_CC, Fields_N
|
||||
from SimPEG.Utils import sdiag
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero
|
||||
from SimPEG.EM.Static.DC import getxBCyBC_CC
|
||||
from SurveyIP import Survey
|
||||
|
||||
class IPPropMap(Maps.PropMap):
|
||||
"""
|
||||
Property Map for IP Problems. The electrical chargeability,
|
||||
(\\(\\eta\\)) is the default inversion property
|
||||
"""
|
||||
eta = Maps.Property("Electrical Chargeability", defaultInvProp = True)
|
||||
|
||||
class BaseIPProblem(BaseEMProblem):
|
||||
|
||||
surveyPair = Survey
|
||||
fieldsPair = Fields
|
||||
PropMap = IPPropMap
|
||||
Ainv = None
|
||||
sigma = None
|
||||
rho = None
|
||||
f = None
|
||||
Ainv = None
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
if self.f is None:
|
||||
self.f = self.fieldsPair(self.mesh, self.survey)
|
||||
if self.Ainv == None:
|
||||
A = self.getA()
|
||||
self.Ainv = self.Solver(A, **self.solverOpts)
|
||||
RHS = self.getRHS()
|
||||
u = self.Ainv * RHS
|
||||
Srcs = self.survey.srcList
|
||||
self.f[Srcs, self._solutionType] = u
|
||||
return self.f
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
|
||||
A = self.getA()
|
||||
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType] # solution vector
|
||||
dA_dm_v = self.getADeriv(u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(src, v)
|
||||
du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
|
||||
for rx in src.rxList:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
||||
# Conductivity (d u / d log sigma)
|
||||
if self._formulation is 'EB':
|
||||
return -Utils.mkvc(Jv)
|
||||
# Conductivity (d u / d log rho)
|
||||
if self._formulation is 'HJ':
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv = np.zeros(m.size)
|
||||
AT = self.getA()
|
||||
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType]
|
||||
for rx in src.rxList:
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
||||
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
ATinvdf_duT = self.Ainv * df_duT
|
||||
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
Jtv += (df_dmT + du_dmT).astype(float)
|
||||
# Conductivity ((d u / d log sigma).T)
|
||||
if self._formulation is 'EB':
|
||||
return -Utils.mkvc(Jtv)
|
||||
# Conductivity ((d u / d log rho).T)
|
||||
if self._formulation is 'HJ':
|
||||
return Utils.mkvc(Jtv)
|
||||
|
||||
def getSourceTerm(self):
|
||||
"""
|
||||
takes concept of source and turns it into a matrix
|
||||
"""
|
||||
"""
|
||||
Evaluates the sources, and puts them in matrix form
|
||||
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: q (nC or nN, nSrc)
|
||||
"""
|
||||
|
||||
Srcs = self.survey.srcList
|
||||
|
||||
if self._formulation is 'EB':
|
||||
n = self.mesh.nN
|
||||
# return NotImplementedError
|
||||
|
||||
elif self._formulation is 'HJ':
|
||||
n = self.mesh.nC
|
||||
|
||||
q = np.zeros((n, len(Srcs)))
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
q[:,i] = src.eval(self)
|
||||
return q
|
||||
|
||||
@property
|
||||
def deleteTheseOnModelUpdate(self):
|
||||
toDelete = []
|
||||
return toDelete
|
||||
|
||||
# assume log rho or log cond
|
||||
@property
|
||||
def MeSigma(self):
|
||||
"""
|
||||
Edge inner product matrix for \\(\\sigma\\). Used in the E-B formulation
|
||||
"""
|
||||
if getattr(self, '_MeSigma', None) is None:
|
||||
self._MeSigma = self.mesh.getEdgeInnerProduct(self.sigma)
|
||||
return self._MeSigma
|
||||
|
||||
@property
|
||||
def MfRhoI(self):
|
||||
"""
|
||||
Inverse of :code:`MfRho`
|
||||
"""
|
||||
if getattr(self, '_MfRhoI', None) is None:
|
||||
self._MfRhoI = self.mesh.getFaceInnerProduct(self.rho, invMat=True)
|
||||
return self._MfRhoI
|
||||
|
||||
def MfRhoIDeriv(self,u):
|
||||
"""
|
||||
Derivative of :code:`MfRhoI` with respect to the model.
|
||||
"""
|
||||
|
||||
dMfRhoI_dI = -self.MfRhoI**2
|
||||
dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u)
|
||||
drho_dlogrho = Utils.sdiag(self.rho)*self.curModel.etaDeriv
|
||||
return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho))
|
||||
|
||||
# TODO: This should take a vector
|
||||
def MeSigmaDeriv(self, u):
|
||||
"""
|
||||
Derivative of MeSigma with respect to the model
|
||||
"""
|
||||
dsigma_dlogsigma = Utils.sdiag(self.sigma)*self.curModel.etaDeriv
|
||||
return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma
|
||||
|
||||
class Problem3D_CC(BaseIPProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'HJ' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_CC
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseIPProblem.__init__(self, mesh, **kwargs)
|
||||
self.setBC()
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoI = self.MfRhoI
|
||||
A = D * MfRhoI * G
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * A
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint= False):
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoIDeriv = self.MfRhoIDeriv
|
||||
|
||||
if adjoint:
|
||||
# if self._makeASymmetric is True:
|
||||
# v = V * v
|
||||
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) )
|
||||
return D * (MfRhoIDeriv( G * u ) * v)
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return self.Vol.T * RHS
|
||||
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
def setBC(self):
|
||||
if self.mesh.dim==3:
|
||||
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
gBFzm = self.mesh.gridFz[fzm,:]
|
||||
gBFzp = self.mesh.gridFz[fzp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
beta_zm, beta_zp = temp_zm, temp_zp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
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]
|
||||
|
||||
elif self.mesh.dim==2:
|
||||
|
||||
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
||||
|
||||
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
||||
V = self.Vol
|
||||
self.Div = V * self.mesh.faceDiv
|
||||
P_BC, B = self.mesh.getBCProjWF_simple()
|
||||
M = B*self.mesh.aveCC2F
|
||||
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
||||
|
||||
|
||||
class Problem3D_N(BaseIPProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'EB' # N potentials means B is on faces
|
||||
fieldsPair = Fields_N
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseIPProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = G.T MeSigma G
|
||||
|
||||
"""
|
||||
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
A = Grad.T * MeSigma * Grad
|
||||
|
||||
# Handling Null space of A
|
||||
A[0,0] = A[0,0] + 1.
|
||||
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint=False):
|
||||
"""
|
||||
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
"""
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
if not adjoint:
|
||||
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
|
||||
elif adjoint:
|
||||
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
|
||||
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
||||
cs = 12.5
|
||||
hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hz = [(cs,7, -1.3),(cs,20)]
|
||||
mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN")
|
||||
sigma = np.ones(mesh.nC)
|
||||
prob = BaseIPProblem(mesh, sigma=sigma)
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import SimPEG
|
||||
from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG import sp, Survey
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
from SimPEG.EM.Static.DC.SrcDC import BaseSrc
|
||||
from SimPEG.EM.Static.DC.RxDC import BaseRx
|
||||
|
||||
class Survey(BaseEMSurvey):
|
||||
rxPair = BaseRx
|
||||
srcPair = BaseSrc
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
self.srcList = srcList
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
|
||||
def dpred(self, m, f=None):
|
||||
"""
|
||||
Predicted data.
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = Pf(m)
|
||||
"""
|
||||
return self.prob.Jvec(m, m, f=f)
|
||||
@@ -0,0 +1,2 @@
|
||||
from ProblemIP import Problem3D_CC, Problem3D_N
|
||||
from SurveyIP import Survey
|
||||
@@ -0,0 +1,445 @@
|
||||
from SimPEG import Problem, Utils, Maps, Mesh
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SimPEG.EM.Static.DC.FieldsDC import Fields, Fields_CC, Fields_N
|
||||
from SimPEG.Utils import sdiag
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero
|
||||
from SimPEG.EM.Static.DC import getxBCyBC_CC
|
||||
from SurveySIP import Survey, Data
|
||||
|
||||
class ColeColePropMap(Maps.PropMap):
|
||||
"""
|
||||
Property Map for EM Problems. The electrical conductivity (\\(\\sigma\\)) is the default inversion property, and the default value of the magnetic permeability is that of free space (\\(\\mu = 4\\pi\\times 10^{-7} \\) H/m)
|
||||
"""
|
||||
|
||||
eta = Maps.Property("Electrical Conductivity", defaultInvProp=True)
|
||||
tau = Maps.Property("Electrical Conductivity", defaultVal=0.1, propertyLink=('taui', Maps.ReciprocalMap))
|
||||
taui = Maps.Property("Electrical Conductivity", defaultVal=1., propertyLink=('tau', Maps.ReciprocalMap))
|
||||
c = Maps.Property("Electrical Conductivity", defaultVal=1.)
|
||||
|
||||
|
||||
class BaseSIPProblem(BaseEMProblem):
|
||||
|
||||
surveyPair = Survey
|
||||
fieldsPair = Fields
|
||||
dataPair = Data
|
||||
PropMap = ColeColePropMap
|
||||
Ainv = None
|
||||
sigma = None
|
||||
rho = None
|
||||
f = None
|
||||
Ainv = None
|
||||
|
||||
def DebyeTime(self, t):
|
||||
peta = self.curModel.eta*np.exp(-self.curModel.taui*t)
|
||||
return peta
|
||||
|
||||
def EtaDeriv(self, t, v, adjoint=False):
|
||||
v = np.array(v, dtype=float)
|
||||
if adjoint:
|
||||
return self.curModel.etaDeriv.T * (np.exp(-self.curModel.taui*t)*v)
|
||||
else:
|
||||
return np.exp(-self.curModel.taui*t) * (self.curModel.etaDeriv*v)
|
||||
|
||||
|
||||
def TauiDeriv(self, t, v, adjoint=False):
|
||||
v = np.array(v, dtype=float)
|
||||
if adjoint:
|
||||
return -self.curModel.tauiDeriv.T * (self.curModel.eta*t*np.exp(-self.curModel.taui*t)*v)
|
||||
else:
|
||||
return -self.curModel.eta*t*np.exp(-self.curModel.taui*t) * (self.curModel.tauiDeriv*v)
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
if self.f is None:
|
||||
self.f = self.fieldsPair(self.mesh, self.survey)
|
||||
if self.Ainv == None:
|
||||
A = self.getA()
|
||||
self.Ainv = self.Solver(A, **self.solverOpts)
|
||||
RHS = self.getRHS()
|
||||
u = self.Ainv * RHS
|
||||
Srcs = self.survey.srcList
|
||||
self.f[Srcs, self._solutionType] = u
|
||||
return self.f
|
||||
|
||||
def forward(self, m, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
# A = self.getA()
|
||||
JvAll = []
|
||||
for tind in range(len(self.survey.times)):
|
||||
#Pseudo-chareability
|
||||
t = self.survey.times[tind]
|
||||
v = self.DebyeTime(t)
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType] # solution vector
|
||||
dA_dm_v = self.getADeriv(u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(src, v)
|
||||
du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
for rx in src.rxList:
|
||||
timeindex = rx.getTimeP(self.survey.times)
|
||||
if timeindex[tind]:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx, t] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
||||
|
||||
# Conductivity (d u / d log sigma)
|
||||
if self._formulation is 'EB':
|
||||
return -Utils.mkvc(Jv)
|
||||
# Resistivity (d u / d log rho)
|
||||
if self._formulation is 'HJ':
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
# A = self.getA()
|
||||
JvAll = []
|
||||
#Assume only eta and tau (eta first then tau)
|
||||
# v = [2*Mx1]
|
||||
v = v.reshape((int(v.size/2), 2), order='F')
|
||||
|
||||
for tind in range(len(self.survey.times)):
|
||||
t = self.survey.times[tind]
|
||||
v0 = self.EtaDeriv(t, v[:,0])
|
||||
v1 = self.TauiDeriv(t, v[:,1])
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType] # solution vector
|
||||
dA_dm_v0 = self.getADeriv(u_src, v0)
|
||||
dRHS_dm_v0 = self.getRHSDeriv(src, v0)
|
||||
du_dm_v0 = self.Ainv * ( - dA_dm_v0 + dRHS_dm_v0 )
|
||||
dA_dm_v1 = self.getADeriv(u_src, v1)
|
||||
dRHS_dm_v1 = self.getRHSDeriv(src, v1)
|
||||
du_dm_v1 = self.Ainv * ( - dA_dm_v1 + dRHS_dm_v1 )
|
||||
for rx in src.rxList:
|
||||
timeindex = rx.getTimeP(self.survey.times)
|
||||
if timeindex[tind]:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v0 = df_dmFun(src, du_dm_v0, v0, adjoint=False)
|
||||
df_dm_v1 = df_dmFun(src, du_dm_v1, v1, adjoint=False)
|
||||
Jv[src, rx, t] = rx.evalDeriv(src, self.mesh, f, df_dm_v0)
|
||||
Jv[src, rx, t] += rx.evalDeriv(src, self.mesh, f, df_dm_v1)
|
||||
# Conductivity (d u / d log sigma)
|
||||
if self._formulation is 'EB':
|
||||
return -Jv.tovec()
|
||||
# Resistivity (d u / d log rho)
|
||||
if self._formulation is 'HJ':
|
||||
return Jv.tovec()
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv= np.zeros(m.size)
|
||||
for tind in range(len(self.survey.times)):
|
||||
t = self.survey.times[tind]
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType]
|
||||
for rx in src.rxList:
|
||||
timeindex = rx.getTimeP(self.survey.times)
|
||||
if timeindex[tind]:
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx, t], adjoint=True) # wrt f, need possibility wrt m
|
||||
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
ATinvdf_duT = self.Ainv * df_duT
|
||||
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
Jtv += np.r_[self.EtaDeriv(self.survey.times[tind], du_dmT, adjoint=True), self.TauiDeriv(self.survey.times[tind], du_dmT, adjoint=True)]
|
||||
|
||||
# Conductivity ((d u / d log sigma).T)
|
||||
if self._formulation is 'EB':
|
||||
return -Jtv
|
||||
# Conductivity ((d u / d log rho).T)
|
||||
if self._formulation is 'HJ':
|
||||
return Jtv
|
||||
|
||||
def getSourceTerm(self):
|
||||
"""
|
||||
takes concept of source and turns it into a matrix
|
||||
"""
|
||||
"""
|
||||
Evaluates the sources, and puts them in matrix form
|
||||
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: q (nC or nN, nSrc)
|
||||
"""
|
||||
|
||||
Srcs = self.survey.srcList
|
||||
|
||||
if self._formulation is 'EB':
|
||||
n = self.mesh.nN
|
||||
# return NotImplementedError
|
||||
|
||||
elif self._formulation is 'HJ':
|
||||
n = self.mesh.nC
|
||||
|
||||
q = np.zeros((n, len(Srcs)))
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
q[:,i] = src.eval(self)
|
||||
return q
|
||||
|
||||
@property
|
||||
def deleteTheseOnModelUpdate(self):
|
||||
toDelete = []
|
||||
return toDelete
|
||||
|
||||
# assume log rho or log cond
|
||||
@property
|
||||
def MeSigma(self):
|
||||
"""
|
||||
Edge inner product matrix for \\(\\sigma\\). Used in the E-B formulation
|
||||
"""
|
||||
if getattr(self, '_MeSigma', None) is None:
|
||||
self._MeSigma = self.mesh.getEdgeInnerProduct(self.sigma)
|
||||
return self._MeSigma
|
||||
|
||||
@property
|
||||
def MfRhoI(self):
|
||||
"""
|
||||
Inverse of :code:`MfRho`
|
||||
"""
|
||||
if getattr(self, '_MfRhoI', None) is None:
|
||||
self._MfRhoI = self.mesh.getFaceInnerProduct(self.rho, invMat=True)
|
||||
return self._MfRhoI
|
||||
|
||||
def MfRhoIDeriv(self,u):
|
||||
"""
|
||||
Derivative of :code:`MfRhoI` with respect to the model.
|
||||
"""
|
||||
|
||||
dMfRhoI_dI = -self.MfRhoI**2
|
||||
dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u)
|
||||
drho_dlogrho = Utils.sdiag(self.rho)
|
||||
return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho))
|
||||
|
||||
# TODO: This should take a vector
|
||||
def MeSigmaDeriv(self, u):
|
||||
"""
|
||||
Derivative of MeSigma with respect to the model
|
||||
"""
|
||||
dsigma_dlogsigma = Utils.sdiag(self.sigma)
|
||||
return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma
|
||||
|
||||
class Problem3D_CC(BaseSIPProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'HJ' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_CC
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseSIPProblem.__init__(self, mesh, **kwargs)
|
||||
self.setBC()
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
# TODO: this won't work for full anisotropy
|
||||
MfRhoI = self.MfRhoI
|
||||
A = D * MfRhoI * G
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * A
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint= False):
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoIDeriv = self.MfRhoIDeriv
|
||||
|
||||
if adjoint:
|
||||
# if self._makeASymmetric is True:
|
||||
# v = V * v
|
||||
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) )
|
||||
return D * (MfRhoIDeriv( G * u ) * v)
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return self.Vol.T * RHS
|
||||
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
def setBC(self):
|
||||
if self.mesh.dim==3:
|
||||
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
gBFzm = self.mesh.gridFz[fzm,:]
|
||||
gBFzp = self.mesh.gridFz[fzp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
beta_zm, beta_zp = temp_zm, temp_zp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
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]
|
||||
|
||||
elif self.mesh.dim==2:
|
||||
|
||||
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
||||
|
||||
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
||||
V = self.Vol
|
||||
self.Div = V * self.mesh.faceDiv
|
||||
P_BC, B = self.mesh.getBCProjWF_simple()
|
||||
M = B*self.mesh.aveCC2F
|
||||
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
||||
|
||||
|
||||
class Problem3D_N(BaseSIPProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'EB' # N potentials means B is on faces
|
||||
fieldsPair = Fields_N
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseSIPProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = G.T MeSigma G
|
||||
|
||||
"""
|
||||
|
||||
# TODO: this won't work for full anisotropy
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
A = Grad.T * MeSigma * Grad
|
||||
|
||||
# Handling Null space of A
|
||||
A[0,0] = A[0,0] + 1.
|
||||
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint=False):
|
||||
"""
|
||||
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
"""
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
if not adjoint:
|
||||
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
|
||||
elif adjoint:
|
||||
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
|
||||
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
||||
cs = 12.5
|
||||
hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hz = [(cs,7, -1.3),(cs,20)]
|
||||
mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN")
|
||||
sigma = np.ones(mesh.nC)
|
||||
prob = BaseSIPProblem(mesh, sigma=sigma)
|
||||
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
from SimPEG import Utils, Maps, Mesh, sp, np
|
||||
from SimPEG.Regularization import BaseRegularization, Simple
|
||||
|
||||
class MultiRegularization(Simple):
|
||||
"""
|
||||
**MultiRegularization Class**
|
||||
|
||||
This is used to regularize the model space
|
||||
having multiple models [m1, m2, m3, ...] ::
|
||||
|
||||
reg = Regularization(mesh)
|
||||
|
||||
"""
|
||||
nModels = None # Number of models
|
||||
ratios = None # Ratio for different models
|
||||
crossgrad = False # Use cross gradient or not
|
||||
betacross = 1.
|
||||
wx = []
|
||||
wy = []
|
||||
wz = []
|
||||
|
||||
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
|
||||
BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
|
||||
if self.nModels == None:
|
||||
raise Exception("Put nModels as a initial input!")
|
||||
if self.ratios == None:
|
||||
self.ratios = [1. for imodel in range(self.nModels)]
|
||||
|
||||
@property
|
||||
def Wsmall(self):
|
||||
"""Regularization matrix Wsmall"""
|
||||
if getattr(self,'_Wsmall', None) is None:
|
||||
vecs = []
|
||||
for imodel in range(self.nModels):
|
||||
vecs.append((self.regmesh.vol*self.alpha_s*self.wght*self.ratios[imodel])**0.5)
|
||||
self._Wsmall = Utils.sdiag(np.hstack(vecs))
|
||||
return self._Wsmall
|
||||
|
||||
@property
|
||||
def Wx(self):
|
||||
"""Regularization matrix Wx"""
|
||||
if getattr(self, '_Wx', None) is None:
|
||||
mats = []
|
||||
for imodel in range(self.nModels):
|
||||
self.wx.append(Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*self.ratios[imodel]*(self.regmesh.aveCC2Fx*self.wght))**0.5))
|
||||
mats.append(self.wx[imodel]*self.regmesh.cellDiffxStencil)
|
||||
self._Wx = sp.block_diag(mats)
|
||||
return self._Wx
|
||||
|
||||
@property
|
||||
def Wy(self):
|
||||
"""Regularization matrix Wy"""
|
||||
if getattr(self, '_Wy', None) is None:
|
||||
mats = []
|
||||
for imodel in range(self.nModels):
|
||||
self.wy.append(Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol*self.alpha_y*self.ratios[imodel]*(self.regmesh.aveCC2Fy*self.wght))**0.5))
|
||||
mats.append(self.wy[imodel]*self.regmesh.cellDiffyStencil)
|
||||
self._Wy = sp.block_diag(mats)
|
||||
return self._Wy
|
||||
|
||||
@property
|
||||
def Wz(self):
|
||||
"""Regularization matrix Wz"""
|
||||
if getattr(self, '_Wz', None) is None:
|
||||
mats = []
|
||||
for imodel in range(self.nModels):
|
||||
self.wz.append(Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*self.ratios[imodel]*(self.regmesh.aveCC2Fz*self.wght))**0.5))
|
||||
mats.append(self.wz[imodel]*self.regmesh.cellDiffzStencil)
|
||||
self._Wz = sp.block_diag(mats)
|
||||
return self._Wz
|
||||
|
||||
@property
|
||||
def Wsmooth(self):
|
||||
"""Full smoothness regularization matrix W"""
|
||||
if getattr(self, '_Wsmooth', None) is None:
|
||||
wlist = (self.Wx,)
|
||||
if self.regmesh.dim > 1:
|
||||
wlist += (self.Wy,)
|
||||
if self.regmesh.dim > 2:
|
||||
wlist += (self.Wz,)
|
||||
self._Wsmooth = sp.vstack(wlist)
|
||||
return self._Wsmooth
|
||||
|
||||
@property
|
||||
def W(self):
|
||||
"""Full regularization matrix W"""
|
||||
if getattr(self, '_W', None) is None:
|
||||
wlist = (self.Wsmall, self.Wsmooth)
|
||||
self._W = sp.vstack(wlist)
|
||||
return self._W
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m):
|
||||
return self._evalSmall(m) + self._evalSmooth(m)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmall(self, m):
|
||||
r = self.Wsmall * ( self.mapping * (m - self.mref) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmooth(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wsmooth * ( self.mapping * (m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wsmooth * ( self.mapping * m)
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
def cross(a,b):
|
||||
ax, ay, az = a[0], a[1], a[2]
|
||||
bx, by, bz = b[0], b[1], b[2]
|
||||
cx = ay*bz - az*by
|
||||
cy = az*bx - ax*bz
|
||||
cz = ax*by - ay*bx
|
||||
return [cx, cy, cz]
|
||||
|
||||
# TODO: Implement Cross Gradients..
|
||||
@Utils.timeIt
|
||||
def _evalCross(self, m):
|
||||
if self.crossgrad == False:
|
||||
return 0.
|
||||
elif self.crossgrad == True:
|
||||
M = (self.mapping * m).reshape((self.regmesh.nC, self.nModels), order="F")
|
||||
|
||||
ax = self.regmesh.aveFx2CC*self.regmesh.wx[0]*M[:,0]
|
||||
ay = self.regmesh.aveFy2CC*self.regmesh.wy[0]*M[:,0]
|
||||
az = self.regmesh.aveFz2CC*self.regmesh.wz[0]*M[:,0]
|
||||
bx = self.regmesh.aveFx2CC*self.regmesh.wx[1]*M[:,1]
|
||||
by = self.regmesh.aveFy2CC*self.regmesh.wy[1]*M[:,1]
|
||||
bz = self.regmesh.aveFz2CC*self.regmesh.wz[1]*M[:,1]
|
||||
#ab
|
||||
out_ab = cross([ax, ay, az], [bx, by, bz])
|
||||
r = np.r_[out_ab[0], out_ab[1], out_ab[2]]*np.sqrt(self.betacross)
|
||||
|
||||
if self.nModels == 3:
|
||||
cx = self.regmesh.aveFx2CC*self.regmesh.wx[1]*M[:,1]
|
||||
cy = self.regmesh.aveFy2CC*self.regmesh.wy[1]*M[:,1]
|
||||
cz = self.regmesh.aveFz2CC*self.regmesh.wz[1]*M[:,1]
|
||||
#ac
|
||||
out_ac = cross([ax, ay, az], [cx, cy, cz])
|
||||
#bc
|
||||
out_bc = cross([bx, by, bz], [cx, cy, cz])
|
||||
r = np.r_[r, np.hstack(out_ac)*np.sqrt(self.betacross), np.hstack(out_bc)*np.sqrt(self.betacross)]
|
||||
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def evalDeriv(self, m):
|
||||
"""
|
||||
The regularization is:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})}
|
||||
|
||||
So the derivative is straight forward:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \mathbf{W^\\top W (m-m_\\text{ref})}
|
||||
|
||||
"""
|
||||
deriv = self._evalSmallDeriv(m) + self._evalSmoothDeriv(m)
|
||||
if self.crossgrad==True:
|
||||
deriv += self._evalCrossDeriv(m)
|
||||
return deriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalCrossDeriv(self,m):
|
||||
r = self.Wsmall * ( self.mapping * (m - self.mref) )
|
||||
return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) )
|
||||
|
||||
@Utils.timeIt
|
||||
def eval2Deriv(self, m, v=None):
|
||||
"""
|
||||
Second derivative
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array v: vector to multiply
|
||||
:rtype: scipy.sparse.csr_matrix or numpy.ndarray
|
||||
:return: WtW or WtW*v
|
||||
|
||||
The regularization is:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})}
|
||||
|
||||
So the second derivative is straight forward:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \mathbf{W^\\top W}
|
||||
|
||||
"""
|
||||
mD = self.mapping.deriv(m - self.mref)
|
||||
if v is None:
|
||||
return mD.T * self.W.T * self.W * mD
|
||||
|
||||
return mD.T * ( self.W.T * ( self.W * ( mD * v) ) )
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import SimPEG
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero, closestPoints
|
||||
|
||||
class BaseRx(SimPEG.Survey.BaseTimeRx):
|
||||
locs = None
|
||||
rxType = None
|
||||
|
||||
knownRxTypes = {
|
||||
'phi':['phi',None],
|
||||
'ex':['e','x'],
|
||||
'ey':['e','y'],
|
||||
'ez':['e','z'],
|
||||
'jx':['j','x'],
|
||||
'jy':['j','y'],
|
||||
'jz':['j','z'],
|
||||
}
|
||||
|
||||
def __init__(self, locs, times, rxType, **kwargs):
|
||||
SimPEG.Survey.BaseTimeRx.__init__(self, locs, times, rxType, **kwargs)
|
||||
|
||||
@property
|
||||
def projField(self):
|
||||
"""Field Type projection (e.g. e b ...)"""
|
||||
return self.knownRxTypes[self.rxType][0]
|
||||
|
||||
def projGLoc(self, f):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
comp = self.knownRxTypes[self.rxType][1]
|
||||
if comp is not None:
|
||||
return f._GLoc(self.rxType) + comp
|
||||
return f._GLoc(self.rxType)
|
||||
|
||||
def getTimeP(self, timesall):
|
||||
"""
|
||||
Returns the time projection matrix.
|
||||
|
||||
.. note::
|
||||
|
||||
This is not stored in memory, but is created on demand.
|
||||
"""
|
||||
time_inds = np.in1d(timesall, self.times)
|
||||
return time_inds
|
||||
|
||||
def evalDeriv(self, src, mesh, f, v, adjoint=False):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
if not adjoint:
|
||||
return P*v
|
||||
elif adjoint:
|
||||
return P.T*v
|
||||
|
||||
|
||||
# DC.Rx.Dipole(locs)
|
||||
class Dipole(BaseRx):
|
||||
|
||||
def __init__(self, locsM, locsN, times, rxType = 'phi', **kwargs):
|
||||
assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size'
|
||||
locs = [locsM, locsN]
|
||||
# We may not need this ...
|
||||
BaseRx.__init__(self, locs, times, rxType)
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data in the receiver."""
|
||||
# return self.locs[0].shape[0] * len(self.times)
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
@property
|
||||
def nRx(self):
|
||||
"""Number of data in the receiver."""
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
# Not sure why ...
|
||||
# return int(self.locs[0].size / 2)
|
||||
|
||||
|
||||
def getP(self, mesh, Gloc):
|
||||
if mesh in self._Ps:
|
||||
return self._Ps[mesh]
|
||||
|
||||
P0 = mesh.getInterpolationMat(self.locs[0], Gloc)
|
||||
P1 = mesh.getInterpolationMat(self.locs[1], Gloc)
|
||||
P = P0 - P1
|
||||
|
||||
if self.storeProjections:
|
||||
self._Ps[mesh] = P
|
||||
|
||||
return P
|
||||
@@ -0,0 +1,64 @@
|
||||
import SimPEG
|
||||
# from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG.Utils import Zero, closestPoints, mkvc
|
||||
import numpy as np
|
||||
|
||||
class BaseSrc(SimPEG.Survey.BaseSrc):
|
||||
|
||||
current = 1.0
|
||||
loc = None
|
||||
|
||||
def __init__(self, rxList, **kwargs):
|
||||
SimPEG.Survey.BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
raise NotImplementedError
|
||||
|
||||
def evalDeriv(self, prob):
|
||||
return Zero()
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data"""
|
||||
return self.vnD.sum()
|
||||
|
||||
@property
|
||||
def vnD(self):
|
||||
"""Vector number of data"""
|
||||
return np.array([rx.nD*len(rx.times) for rx in self.rxList])
|
||||
|
||||
|
||||
|
||||
class Dipole(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, locA, locB, **kwargs):
|
||||
assert locA.shape == locB.shape, 'Shape of locA and locB should be the same'
|
||||
self.loc = [locA, locB]
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
if prob._formulation == 'HJ':
|
||||
inds = closestPoints(prob.mesh, self.loc, gridLoc='CC')
|
||||
q = np.zeros(prob.mesh.nC)
|
||||
q[inds] = self.current * np.r_[1., -1.]
|
||||
elif prob._formulation == 'EB':
|
||||
qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense()
|
||||
qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense()
|
||||
q = self.current * mkvc(qa+qb)
|
||||
return q
|
||||
|
||||
class Pole(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, loc, **kwargs):
|
||||
BaseSrc.__init__(self, rxList, loc=loc, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
if prob._formulation == 'HJ':
|
||||
inds = closestPoints(prob.mesh, self.loc)
|
||||
q = np.zeros(prob.mesh.nC)
|
||||
q[inds] = self.current * np.r_[1.]
|
||||
elif prob._formulation == 'EB':
|
||||
q = prob.mesh.getInterpolationMat(self.loc, locType='N').todense()
|
||||
q = self.current * mkvc(q)
|
||||
return q
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import SimPEG
|
||||
from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG import np, sp, Survey, Utils
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
from SimPEG.EM.Static.SIP.SrcSIP import BaseSrc
|
||||
from SimPEG.EM.Static.SIP.RxSIP import BaseRx
|
||||
import uuid
|
||||
|
||||
|
||||
class Survey(BaseEMSurvey):
|
||||
rxPair = BaseRx
|
||||
srcPair = BaseSrc
|
||||
times = None
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
self.srcList = srcList
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
self.getUniqueTimes()
|
||||
|
||||
def getUniqueTimes(self):
|
||||
time_rx = []
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
time_rx.append(rx.times)
|
||||
self.times = np.unique(np.hstack(time_rx))
|
||||
|
||||
def dpred(self, m, f=None):
|
||||
"""
|
||||
Predicted data.
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = Pf(m)
|
||||
"""
|
||||
return self.prob.forward(m, f=f)
|
||||
|
||||
|
||||
class Data(SimPEG.Survey.Data):
|
||||
"""Fancy data storage by Src and Rx"""
|
||||
|
||||
def __init__(self, survey, v=None):
|
||||
self.uid = str(uuid.uuid4())
|
||||
self.survey = survey
|
||||
self._dataDict = {}
|
||||
for src in self.survey.srcList:
|
||||
self._dataDict[src] = {}
|
||||
for rx in src.rxList:
|
||||
self._dataDict[src][rx] = {}
|
||||
|
||||
if v is not None:
|
||||
self.fromvec(v)
|
||||
|
||||
def _ensureCorrectKey(self, key):
|
||||
if type(key) is tuple:
|
||||
if len(key) is not 3:
|
||||
raise KeyError('Key must be [Src, Rx, tInd]')
|
||||
if key[0] not in self.survey.srcList:
|
||||
raise KeyError('Src Key must be a source in the survey.')
|
||||
if key[1] not in key[0].rxList:
|
||||
raise KeyError('Rx Key must be a receiver for the source.')
|
||||
return key
|
||||
elif isinstance(key, self.survey.srcPair):
|
||||
if key not in self.survey.srcList:
|
||||
raise KeyError('Key must be a source in the survey.')
|
||||
return key, None, None
|
||||
else:
|
||||
raise KeyError('Key must be [Src] or [Src,Rx] or [Src, Rx, tInd]')
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
src, rx, t = self._ensureCorrectKey(key)
|
||||
assert rx is not None, 'set data using [Src, Rx]'
|
||||
assert isinstance(value, np.ndarray), 'value must by ndarray'
|
||||
assert value.size == rx.nD, "value must have the same number of data as the source."
|
||||
self._dataDict[src][rx][t] = Utils.mkvc(value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
src, rx, t = self._ensureCorrectKey(key)
|
||||
if rx is not None:
|
||||
if rx not in self._dataDict[src]:
|
||||
raise Exception('Data for receiver has not yet been set.')
|
||||
return self._dataDict[src][rx][t]
|
||||
|
||||
return np.concatenate([self[src,rx, t] for rx in src.rxList])
|
||||
|
||||
def tovec(self):
|
||||
val = []
|
||||
for src in self.survey.srcList:
|
||||
for rx in src.rxList:
|
||||
for t in rx.times:
|
||||
val.append(self[src, rx, t])
|
||||
return np.concatenate(val)
|
||||
|
||||
|
||||
def fromvec(self, v):
|
||||
v = Utils.mkvc(v)
|
||||
assert v.size == self.survey.nD, 'v must have the correct number of data.'
|
||||
indBot, indTop = 0, 0
|
||||
for src in self.survey.srcList:
|
||||
for rx in src.rxList:
|
||||
for t in rx.times:
|
||||
indTop += rx.nRx
|
||||
self[src, rx, t] = v[indBot:indTop]
|
||||
indBot += rx.nRx
|
||||
@@ -0,0 +1,5 @@
|
||||
from ProblemSIP import Problem3D_CC, Problem3D_N
|
||||
from SurveySIP import Survey, Data
|
||||
import SrcSIP as Src #Pole
|
||||
import RxSIP as Rx
|
||||
from Regularization import MultiRegularization
|
||||
@@ -0,0 +1,317 @@
|
||||
from SimPEG import np
|
||||
from SimPEG.EM.Static import DC, IP
|
||||
|
||||
def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None):
|
||||
"""
|
||||
Read list of 2D tx-rx location and plot a speudo-section of apparent
|
||||
resistivity.
|
||||
|
||||
Assumes flat topo for now...
|
||||
|
||||
Input:
|
||||
:param d2D, z0
|
||||
:switch stype -> Either 'pdp' (pole-dipole) | 'dpdp' (dipole-dipole)
|
||||
:switch dtype=-> Either 'appr' (app. res) | 'appc' (app. con) | 'volt' (potential)
|
||||
Output:
|
||||
:figure scatter plot overlayed on image
|
||||
|
||||
Edited Feb 17th, 2016
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
"""
|
||||
from SimPEG import np
|
||||
from scipy.interpolate import griddata
|
||||
import pylab as plt
|
||||
|
||||
# Set depth to 0 for now
|
||||
z0 = 0.
|
||||
|
||||
# Pre-allocate
|
||||
midx = []
|
||||
midz = []
|
||||
rho = []
|
||||
LEG = []
|
||||
count = 0 # Counter for data
|
||||
for ii in range(DCsurvey.nSrc):
|
||||
|
||||
Tx = DCsurvey.srcList[ii].loc
|
||||
Rx = DCsurvey.srcList[ii].rxList[0].locs
|
||||
|
||||
nD = DCsurvey.srcList[ii].rxList[0].nD
|
||||
|
||||
data = DCsurvey.dobs[count:count+nD]
|
||||
count += nD
|
||||
|
||||
# Get distances between each poles A-B-M-N
|
||||
if stype == 'pdp':
|
||||
MA = np.abs(Tx[0] - Rx[0][:,0])
|
||||
NA = np.abs(Tx[0] - Rx[1][:,0])
|
||||
MN = np.abs(Rx[1][:,0] - Rx[0][:,0])
|
||||
|
||||
# Create mid-point location
|
||||
Cmid = Tx[0]
|
||||
Pmid = (Rx[0][:,0] + Rx[1][:,0])/2
|
||||
if DCsurvey.mesh.dim == 2:
|
||||
zsrc = Tx[1]
|
||||
elif DCsurvey.mesh.dim ==3:
|
||||
zsrc = Tx[2]
|
||||
|
||||
elif stype == 'dpdp':
|
||||
MA = np.abs(Tx[0][0] - Rx[0][:,0])
|
||||
MB = np.abs(Tx[1][0] - Rx[0][:,0])
|
||||
NA = np.abs(Tx[0][0] - Rx[1][:,0])
|
||||
NB = np.abs(Tx[1][0] - Rx[1][:,0])
|
||||
|
||||
# Create mid-point location
|
||||
Cmid = (Tx[0][0] + Tx[1][0])/2
|
||||
Pmid = (Rx[0][:,0] + Rx[1][:,0])/2
|
||||
if DCsurvey.mesh.dim == 2:
|
||||
zsrc = (Tx[0][1] + Tx[1][1])/2
|
||||
elif DCsurvey.mesh.dim ==3:
|
||||
zsrc = (Tx[0][2] + Tx[1][2])/2
|
||||
|
||||
# Change output for dtype
|
||||
if dtype == 'volt':
|
||||
|
||||
rho = np.hstack([rho,data])
|
||||
|
||||
else:
|
||||
|
||||
# Compute pant leg of apparent rho
|
||||
if stype == 'pdp':
|
||||
|
||||
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
|
||||
|
||||
elif stype == 'dpdp':
|
||||
|
||||
leg = data * 2*np.pi / ( 1/MA - 1/MB + 1/NB - 1/NA )
|
||||
LEG.append(1./(2*np.pi) *( 1/MA - 1/MB + 1/NB - 1/NA ))
|
||||
else:
|
||||
print """dtype must be 'pdp'(pole-dipole) | 'dpdp' (dipole-dipole) """
|
||||
break
|
||||
|
||||
|
||||
if dtype == 'appc':
|
||||
|
||||
leg = np.log10(abs(1./leg))
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
elif dtype == 'appr':
|
||||
|
||||
leg = np.log10(abs(leg))
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
else:
|
||||
print """dtype must be 'appr' | 'appc' | 'volt' """
|
||||
break
|
||||
|
||||
|
||||
midx = np.hstack([midx, ( Cmid + Pmid )/2 ])
|
||||
if DCsurvey.mesh.dim==3:
|
||||
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + zsrc ])
|
||||
elif DCsurvey.mesh.dim==2:
|
||||
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + zsrc ])
|
||||
ax = axs
|
||||
|
||||
# Grid points
|
||||
grid_x, grid_z = np.mgrid[np.min(midx):np.max(midx), np.min(midz):np.max(midz)]
|
||||
grid_rho = griddata(np.c_[midx,midz], rho.T, (grid_x, grid_z), method='linear')
|
||||
|
||||
if clim == None:
|
||||
vmin, vmax = rho.min(), rho.max()
|
||||
else:
|
||||
vmin, vmax = clim[0], clim[1]
|
||||
|
||||
grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho)
|
||||
ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, clim=(vmin, vmax), vmin=vmin, vmax=vmax)
|
||||
cbar = plt.colorbar(format="$10^{%.1f}$",fraction=0.04,orientation="horizontal")
|
||||
|
||||
cmin,cmax = cbar.get_clim()
|
||||
ticks = np.linspace(cmin,cmax,3)
|
||||
cbar.set_ticks(ticks)
|
||||
cbar.ax.tick_params(labelsize=10)
|
||||
|
||||
if dtype == 'appc':
|
||||
cbar.set_label("App.Cond",size=12)
|
||||
elif dtype == 'appr':
|
||||
cbar.set_label("App.Res.",size=12)
|
||||
elif dtype == 'volt':
|
||||
cbar.set_label("Potential (V)",size=12)
|
||||
|
||||
# Plot apparent resistivity
|
||||
ax.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax))
|
||||
|
||||
#ax.set_xticklabels([])
|
||||
#ax.set_yticklabels([])
|
||||
|
||||
plt.gca().set_aspect('equal', adjustable='box')
|
||||
|
||||
|
||||
|
||||
return ph, LEG
|
||||
|
||||
def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
"""
|
||||
Load in endpoints and survey specifications to generate Tx, Rx location
|
||||
stations.
|
||||
|
||||
Assumes flat topo for now...
|
||||
|
||||
Input:
|
||||
:param endl -> input endpoints [x1, y1, z1, x2, y2, z2]
|
||||
:object mesh -> SimPEG mesh object
|
||||
:switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient'
|
||||
: param a, n -> pole seperation, number of rx dipoles per tx
|
||||
|
||||
Output:
|
||||
:param Tx, Rx -> List objects for each tx location
|
||||
Lines: P1x, P1y, P1z, P2x, P2y, P2z
|
||||
|
||||
Created on Wed December 9th, 2015
|
||||
|
||||
@author: dominiquef
|
||||
!! Require clean up to deal with DCsurvey
|
||||
"""
|
||||
|
||||
from SimPEG import np
|
||||
|
||||
def xy_2_r(x1,x2,y1,y2):
|
||||
r = np.sqrt( np.sum((x2 - x1)**2 + (y2 - y1)**2) )
|
||||
return r
|
||||
|
||||
## Evenly distribute electrodes and put on surface
|
||||
# Mesure survey length and direction
|
||||
dl_len = xy_2_r(endl[0,0],endl[1,0],endl[0,1],endl[1,1])
|
||||
|
||||
dl_x = ( endl[1,0] - endl[0,0] ) / dl_len
|
||||
dl_y = ( endl[1,1] - endl[0,1] ) / dl_len
|
||||
|
||||
nstn = np.floor( dl_len / a )
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a
|
||||
|
||||
if mesh.dim==2:
|
||||
ztop = mesh.vectorNy[-1]
|
||||
# Create line of P1 locations
|
||||
M = np.c_[stn_x, np.ones(nstn).T*ztop]
|
||||
# Create line of P2 locations
|
||||
N = np.c_[stn_x+a*dl_x, np.ones(nstn).T*ztop]
|
||||
|
||||
elif mesh.dim==3:
|
||||
ztop = mesh.vectorNz[-1]
|
||||
# Create line of P1 locations
|
||||
M = np.c_[stn_x, stn_y, np.ones(nstn).T*ztop]
|
||||
# Create line of P2 locations
|
||||
N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*ztop]
|
||||
|
||||
|
||||
## Build list of Tx-Rx locations depending on survey type
|
||||
# Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn]
|
||||
# Pole-dipole: Moving pole on one end -> [A a MN1 a MN2 ... MNn a B]
|
||||
SrcList = []
|
||||
|
||||
|
||||
if stype != 'gradient':
|
||||
|
||||
for ii in range(0, int(nstn)-1):
|
||||
|
||||
|
||||
if stype == 'dpdp':
|
||||
tx = np.c_[M[ii,:],N[ii,:]]
|
||||
elif stype == 'pdp':
|
||||
tx = np.c_[M[ii,:],M[ii,:]]
|
||||
|
||||
# Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]])
|
||||
|
||||
# Current elctrode seperation
|
||||
AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1])
|
||||
|
||||
# Number of receivers to fit
|
||||
nstn = np.min([np.floor( (AB - b) / a ) , n])
|
||||
|
||||
# Check if there is enough space, else break the loop
|
||||
if nstn <= 0:
|
||||
continue
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a
|
||||
|
||||
# Create receiver poles
|
||||
|
||||
if mesh.dim==3:
|
||||
# Create line of P1 locations
|
||||
P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*ztop]
|
||||
# Create line of P2 locations
|
||||
P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*ztop]
|
||||
rxClass = DC.Rx.Dipole(P1, P2)
|
||||
|
||||
elif mesh.dim==2:
|
||||
# Create line of P1 locations
|
||||
P1 = np.c_[stn_x, np.ones(nstn).T*ztop]
|
||||
# Create line of P2 locations
|
||||
P2 = np.c_[stn_x+a*dl_x, np.ones(nstn).T*ztop]
|
||||
rxClass = DC.Rx.Dipole_ky(P1, P2)
|
||||
|
||||
if stype == 'dpdp':
|
||||
srcClass = DC.Src.Dipole([rxClass], M[ii,:],N[ii,:])
|
||||
elif stype == 'pdp':
|
||||
srcClass = DC.Src.Pole([rxClass], M[ii,:])
|
||||
SrcList.append(srcClass)
|
||||
|
||||
elif stype == 'gradient':
|
||||
|
||||
# Gradient survey only requires Tx at end of line and creates a square
|
||||
# grid of receivers at in the middle at a pre-set minimum distance
|
||||
|
||||
# Get the edge limit of survey area
|
||||
min_x = endl[0,0] + dl_x * b
|
||||
min_y = endl[0,1] + dl_y * b
|
||||
|
||||
max_x = endl[1,0] - dl_x * b
|
||||
max_y = endl[1,1] - dl_y * b
|
||||
|
||||
box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 )
|
||||
box_w = box_l/2.
|
||||
|
||||
nstn = np.floor( box_l / a )
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = min_x + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = min_y + np.array(range(int(nstn)))*dl_y*a
|
||||
|
||||
# Define number of cross lines
|
||||
nlin = int(np.floor( box_w / a ))
|
||||
lind = range(-nlin,nlin+1)
|
||||
|
||||
ngrad = nstn * len(lind)
|
||||
|
||||
rx = np.zeros([ngrad,6])
|
||||
for ii in range( len(lind) ):
|
||||
|
||||
# Move line in perpendicular direction by dipole spacing
|
||||
lxx = stn_x - lind[ii]*a*dl_y
|
||||
lyy = stn_y + lind[ii]*a*dl_x
|
||||
|
||||
|
||||
M = np.c_[ lxx, lyy , np.ones(nstn).T*ztop]
|
||||
N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*ztop]
|
||||
rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N]
|
||||
|
||||
if mesh.dim==3:
|
||||
rxClass = DC.Rx.Dipole(rx[:,:3], rx[:,3:])
|
||||
elif mesh.dim==2:
|
||||
M = M[:,[0,2]]
|
||||
N = N[:,[0,2]]
|
||||
rxClass = DC.Rx.Dipole_ky(rx[:,[0,2]], rx[:,[3,5]])
|
||||
srcClass = DC.Src.Dipole([rxClass], M[0,:], N[-1,:])
|
||||
SrcList.append(srcClass)
|
||||
else:
|
||||
print """stype must be either 'pdp', 'dpdp' or 'gradient'. """
|
||||
|
||||
|
||||
return SrcList
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from StaticUtils import *
|
||||
@@ -0,0 +1,3 @@
|
||||
import DC
|
||||
import IP
|
||||
import SIP
|
||||
+11
-11
@@ -108,11 +108,11 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
Ainv.clean()
|
||||
return F
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param numpy.ndarray v: vector (model object)
|
||||
:param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m
|
||||
:param simpegEM.TDEM.FieldsTDEM f: Fields resulting from m
|
||||
:rtype: numpy.ndarray
|
||||
:return: w (data object)
|
||||
|
||||
@@ -125,15 +125,15 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
"""
|
||||
if self.verbose: print '%s\nCalculating J(v)\n%s'%('*'*50,'*'*50)
|
||||
self.curModel = m
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
p = self.Gvec(m, v, u)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
p = self.Gvec(m, v, f)
|
||||
y = self.solveAh(m, p)
|
||||
Jv = self.survey.evalDeriv(u, v=y)
|
||||
Jv = self.survey.evalDeriv(f, v=y)
|
||||
if self.verbose: print '%s\nDone calculating J(v)\n%s'%('*'*50,'*'*50)
|
||||
return - mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param numpy.ndarray,SimPEG.Survey.Data v: vector (data object)
|
||||
@@ -150,15 +150,15 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
"""
|
||||
if self.verbose: print '%s\nCalculating J^T(v)\n%s'%('*'*50,'*'*50)
|
||||
self.curModel = m
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
p = self.survey.evalDeriv(u, v=v, adjoint=True)
|
||||
p = self.survey.evalDeriv(f, v=v, adjoint=True)
|
||||
y = self.solveAht(m, p)
|
||||
w = self.Gtvec(m, y, u)
|
||||
w = self.Gtvec(m, y, f)
|
||||
if self.verbose: print '%s\nDone calculating J^T(v)\n%s'%('*'*50,'*'*50)
|
||||
return - mkvc(w)
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class SrcTDEM_VMD_MVP(SrcTDEM):
|
||||
def getInitialFields(self, mesh):
|
||||
"""Vertical magnetic dipole, magnetic vector potential"""
|
||||
if self.waveformType == "STEPOFF":
|
||||
print ">> Step waveform: Non-zero initial condition"
|
||||
print ">> Step waveform: Non-zero initial condition"
|
||||
if mesh._meshType is 'CYL':
|
||||
if mesh.isSymmetric:
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, 'Ey')
|
||||
@@ -96,8 +96,8 @@ class SrcTDEM_VMD_MVP(SrcTDEM):
|
||||
elif mesh._meshType is 'TENSOR':
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'])
|
||||
else:
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
return {"b": mesh.edgeCurl*MVP}
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
return {"b": mesh.edgeCurl*MVP}
|
||||
elif self.waveformType == "GENERAL":
|
||||
print ">> General waveform: Zero initial condition"
|
||||
return {"b": np.zeros(mesh.nF)}
|
||||
@@ -113,7 +113,7 @@ class SrcTDEM_VMD_MVP(SrcTDEM):
|
||||
elif mesh._meshType is 'TENSOR':
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'])
|
||||
else:
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
return mesh.edgeCurl.T*MfMui*mesh.edgeCurl*MVP
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ class SrcTDEM_CircularLoop_MVP(SrcTDEM):
|
||||
self.loc = loc
|
||||
self.radius = radius
|
||||
self.waveformType = waveformType
|
||||
SrcTDEM.__init__(self,rxList)
|
||||
SrcTDEM.__init__(self,rxList)
|
||||
|
||||
def getInitialFields(self, mesh):
|
||||
"""Circular Loop, magnetic vector potential"""
|
||||
@@ -153,7 +153,7 @@ class SrcTDEM_CircularLoop_MVP(SrcTDEM):
|
||||
elif mesh._meshType is 'TENSOR':
|
||||
MVP = MagneticLoopVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'], self.radius)
|
||||
else:
|
||||
raise Exception('Unknown mesh for CircularLoop')
|
||||
raise Exception('Unknown mesh for CircularLoop')
|
||||
return mesh.edgeCurl.T*MfMui*mesh.edgeCurl*MVP
|
||||
|
||||
|
||||
|
||||
@@ -20,56 +20,61 @@ def getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False):
|
||||
mesh = Mesh.TensorMesh([hx,hy,hz],['C','C','C'])
|
||||
|
||||
if useMu is True:
|
||||
mapping = [('sigma', Maps.ExpMap(mesh)), ('mu', Maps.IdentityMap(mesh))]
|
||||
mapping = [('sigma', Maps.ExpMap(mesh)), ('mu', Maps.IdentityMap(mesh))]
|
||||
else:
|
||||
mapping = Maps.ExpMap(mesh)
|
||||
|
||||
x = np.array([np.linspace(-5.*cs,-2.*cs,3),np.linspace(5.*cs,2.*cs,3)]) + cs/4. #don't sample right by the source, slightly off alignment from either staggered grid
|
||||
XYZ = Utils.ndgrid(x,x,np.linspace(-2.*cs,2.*cs,5))
|
||||
Rx0 = EM.FDEM.Rx(XYZ, comp)
|
||||
Rx0 = getattr(EM.FDEM.Rx, 'Point_' + comp[0])
|
||||
if comp[2] == 'r':
|
||||
real_or_imag = 'real'
|
||||
elif comp[2] == 'i':
|
||||
real_or_imag = 'imag'
|
||||
rx0 = Rx0(XYZ, comp[1], 'imag')
|
||||
|
||||
Src = []
|
||||
|
||||
for SrcType in SrcList:
|
||||
if SrcType is 'MagDipole':
|
||||
Src.append(EM.FDEM.Src.MagDipole([Rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
Src.append(EM.FDEM.Src.MagDipole([rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
elif SrcType is 'MagDipole_Bfield':
|
||||
Src.append(EM.FDEM.Src.MagDipole_Bfield([Rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
Src.append(EM.FDEM.Src.MagDipole_Bfield([rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
elif SrcType is 'CircularLoop':
|
||||
Src.append(EM.FDEM.Src.CircularLoop([Rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
Src.append(EM.FDEM.Src.CircularLoop([rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
elif SrcType is 'RawVec':
|
||||
if fdemType is 'e' or fdemType is 'b':
|
||||
S_m = np.zeros(mesh.nF)
|
||||
S_e = np.zeros(mesh.nE)
|
||||
S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1e-3
|
||||
S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1e-3
|
||||
Src.append(EM.FDEM.Src.RawVec([Rx0], freq, S_m, S_e))
|
||||
Src.append(EM.FDEM.Src.RawVec([rx0], freq, S_m, mesh.getEdgeInnerProduct()*S_e))
|
||||
|
||||
elif fdemType is 'h' or fdemType is 'j':
|
||||
S_m = np.zeros(mesh.nE)
|
||||
S_e = np.zeros(mesh.nF)
|
||||
S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1e-3
|
||||
S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1e-3
|
||||
Src.append(EM.FDEM.Src.RawVec([Rx0], freq, S_m, S_e))
|
||||
Src.append(EM.FDEM.Src.RawVec([rx0], freq, mesh.getEdgeInnerProduct()*S_m, S_e))
|
||||
|
||||
if verbose:
|
||||
print ' Fetching %s problem' % (fdemType)
|
||||
|
||||
if fdemType == 'e':
|
||||
survey = EM.FDEM.Survey(Src)
|
||||
prb = EM.FDEM.Problem_e(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_e(mesh, mapping=mapping)
|
||||
|
||||
elif fdemType == 'b':
|
||||
survey = EM.FDEM.Survey(Src)
|
||||
prb = EM.FDEM.Problem_b(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping)
|
||||
|
||||
elif fdemType == 'j':
|
||||
survey = EM.FDEM.Survey(Src)
|
||||
prb = EM.FDEM.Problem_j(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_j(mesh, mapping=mapping)
|
||||
|
||||
elif fdemType == 'h':
|
||||
survey = EM.FDEM.Survey(Src)
|
||||
prb = EM.FDEM.Problem_h(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_h(mesh, mapping=mapping)
|
||||
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
@@ -90,7 +95,7 @@ def crossCheckTest(SrcList, fdemType1, fdemType2, comp, addrandoms = False, useM
|
||||
prb1 = getFDEMProblem(fdemType1, comp, SrcList, freq, useMu, verbose)
|
||||
mesh = prb1.mesh
|
||||
print 'Cross Checking Forward: %s, %s formulations - %s' % (fdemType1, fdemType2, comp)
|
||||
|
||||
|
||||
logsig = np.log(np.ones(mesh.nC)*CONDUCTIVITY)
|
||||
mu = np.ones(mesh.nC)*MU
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import TDEM
|
||||
import FDEM
|
||||
import Static
|
||||
import Base
|
||||
import Analytics
|
||||
import Utils
|
||||
|
||||
@@ -2,19 +2,27 @@ from SimPEG import Mesh, Utils, np, sp
|
||||
import SimPEG.DCIP as DC
|
||||
import time
|
||||
|
||||
def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
def run(loc=None, sig=None, radi=None, param=None, surveyType='dipole-dipole', unitType='appConductivity', plotIt=True):
|
||||
"""
|
||||
DC Forward Simulation
|
||||
=====================
|
||||
|
||||
Forward model conductive spheres in a half-space and plot a pseudo-section
|
||||
Forward model two conductive spheres in a half-space and plot a
|
||||
pseudo-section. Assumes an infinite line source and measures along the
|
||||
center of the spheres.
|
||||
|
||||
Created by @fourndo on Mon Feb 01 19:28:06 2016
|
||||
INPUT:
|
||||
loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]]
|
||||
radi = Radius of spheres [r1,r2]
|
||||
param = Conductivity of background and two spheres [m0,m1,m2]
|
||||
surveyType = survey type 'pole-dipole' or 'dipole-dipole'
|
||||
unitType = Data type "appResistivity" | "appConductivity" | "volt"
|
||||
Created by @fourndo
|
||||
|
||||
"""
|
||||
|
||||
assert stype in ['pdp', 'dpdp'], "Source type (stype) must be pdp or dpdp (pole dipole or dipole dipole)"
|
||||
|
||||
assert surveyType in ['pole-dipole', 'dipole-dipole'], "Source type (surveyType) must be pdp or dpdp (pole dipole or dipole dipole)"
|
||||
assert unitType in ['appResistivity', 'appConductivity', 'volt'], "Unit type (unitType) must be appResistivity or appConductivity or volt (potential)"
|
||||
|
||||
if loc is None:
|
||||
loc = np.c_[[-50.,0.,-50.],[50.,0.,-50.]]
|
||||
@@ -27,7 +35,6 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
|
||||
|
||||
# First we need to create a mesh and a model.
|
||||
|
||||
# This is our mesh
|
||||
dx = 5.
|
||||
|
||||
@@ -52,14 +59,10 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
# Get index of the center
|
||||
indy = int(mesh.nCy/2)
|
||||
|
||||
|
||||
# Plot the model for reference
|
||||
# Define core mesh extent
|
||||
xlim = 200
|
||||
zlim = 125
|
||||
|
||||
# Specify the survey type: "pdp" | "dpdp"
|
||||
|
||||
zlim = 100
|
||||
|
||||
# Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh
|
||||
ends = [(-175,0),(175,0)]
|
||||
@@ -70,19 +73,20 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
locs = np.c_[mesh.gridCC[indx,0],mesh.gridCC[indx,1],np.ones(2).T*mesh.vectorNz[-1]]
|
||||
|
||||
# We will handle the geometry of the survey for you and create all the combination of tx-rx along line
|
||||
# [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2])
|
||||
survey, Tx, Rx = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2])
|
||||
# [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, surveyType, param[0], param[1], param[2])
|
||||
survey, Tx, Rx = DC.gen_DCIPsurvey(locs, mesh, surveyType, param[0], param[1], param[2])
|
||||
|
||||
# Define some global geometry
|
||||
dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) )
|
||||
dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len
|
||||
dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len
|
||||
azm = np.arctan(dl_y/dl_x)
|
||||
#azm = np.arctan(dl_y/dl_x)
|
||||
|
||||
#Set boundary conditions
|
||||
mesh.setCellGradBC('neumann')
|
||||
|
||||
# Define the differential operators needed for the DC problem
|
||||
# Define the linear system needed for the DC problem. We assume an infitite
|
||||
# line source for simplicity.
|
||||
Div = mesh.faceDiv
|
||||
Grad = mesh.cellGrad
|
||||
Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model)))
|
||||
@@ -114,8 +118,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
rxloc_N = np.asarray(Rx[ii][:,3:])
|
||||
|
||||
|
||||
# For usual cases "dpdp" or "gradient"
|
||||
if stype == 'pdp':
|
||||
# For usual cases 'dipole-dipole' or "gradient"
|
||||
if surveyType == 'pole-dipole':
|
||||
# Create an "inifinity" pole
|
||||
tx = np.squeeze(Tx[ii][:,0:1])
|
||||
tinf = tx + np.array([dl_x,dl_y,0])*dl_len*2
|
||||
@@ -145,16 +149,23 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
print 'Forward completed'
|
||||
|
||||
# Let's just convert the 3D format into 2D (distance along line) and plot
|
||||
# [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc))
|
||||
survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc))
|
||||
survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc) , 'Xloc')
|
||||
survey2D.dobs =np.hstack(data)
|
||||
# Here is an example for the first tx-rx array
|
||||
|
||||
if plotIt:
|
||||
import matplotlib.pyplot as plt
|
||||
fig = plt.figure()
|
||||
fig = plt.figure(figsize=(7,7))
|
||||
ax = plt.subplot(2,1,1, aspect='equal')
|
||||
mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True)
|
||||
ax.set_title('E-W section at '+str(mesh.vectorCCy[indy])+' m')
|
||||
# Plot the location of the spheres for reference
|
||||
circle1=plt.Circle((loc[0,0], loc[2,0]), radi[0], color='w', fill=False, lw=3)
|
||||
circle2=plt.Circle((loc[0,1], loc[2,1]), radi[1], color='k', fill=False, lw=3)
|
||||
ax.add_artist(circle1)
|
||||
ax.add_artist(circle2)
|
||||
|
||||
dat = mesh.plotSlice(np.log10(model), ax = ax, normal = 'Y',
|
||||
ind = indy,grid=True, clim = np.log10([sig.min(),sig.max()]))
|
||||
|
||||
ax.set_title('3-D model')
|
||||
plt.gca().set_aspect('equal', adjustable='box')
|
||||
|
||||
plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v')
|
||||
@@ -163,22 +174,32 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
|
||||
|
||||
|
||||
ax = plt.subplot(2,1,2, aspect='equal')
|
||||
pos = ax.get_position()
|
||||
ax.set_position([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height])
|
||||
pos = ax.get_position()
|
||||
cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set
|
||||
cb = fig.colorbar(dat[0],cax=cbarax, orientation="horizontal",
|
||||
ax = ax, ticks=np.linspace(np.log10(sig.min()),
|
||||
np.log10(sig.max()), 3), format="$10^{%.1f}$")
|
||||
cb.set_label("Conductivity (S/m)",size=12)
|
||||
cb.ax.tick_params(labelsize=12)
|
||||
|
||||
# Second plot for the predicted apparent resistivity data
|
||||
ax2 = plt.subplot(2,1,2, aspect='equal')
|
||||
|
||||
# Plot the location of the spheres for reference
|
||||
circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3)
|
||||
circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3)
|
||||
ax.add_artist(circle1)
|
||||
ax.add_artist(circle2)
|
||||
circle1=plt.Circle((loc[0,0], loc[2,0]), radi[0], color='w', fill=False, lw=3)
|
||||
circle2=plt.Circle((loc[0,1], loc[2,1]), radi[1], color='k', fill=False, lw=3)
|
||||
ax2.add_artist(circle1)
|
||||
ax2.add_artist(circle2)
|
||||
|
||||
# Add the speudo section
|
||||
DC.plot_pseudoSection(survey2D,ax,stype)
|
||||
|
||||
# plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v')
|
||||
dat = DC.plot_pseudoSection(survey2D, ax2, surveyType=surveyType, unitType=unitType) # plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v')
|
||||
# plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y')
|
||||
# plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k')
|
||||
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
|
||||
ax2.set_title('Apparent Conductivity data')
|
||||
|
||||
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
|
||||
plt.show()
|
||||
|
||||
return fig, ax
|
||||
|
||||
@@ -42,17 +42,16 @@ def run(plotIt=True):
|
||||
ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5)
|
||||
|
||||
|
||||
rxOffset=10.
|
||||
bzi = EM.FDEM.Rx(np.array([[rxOffset, 0., 1e-3]]), 'bzi')
|
||||
rxOffset=10.
|
||||
bzi = EM.FDEM.Rx.Point_b(np.array([[rxOffset, 0., 1e-3]]), orientation='z', component='imag')
|
||||
|
||||
freqs = np.logspace(1,3,10)
|
||||
srcLoc = np.array([0., 0., 10.])
|
||||
|
||||
srcList = []
|
||||
[srcList.append(EM.FDEM.Src.MagDipole([bzi],freq, srcLoc,orientation='Z')) for freq in freqs]
|
||||
srcList = [EM.FDEM.Src.MagDipole([bzi],freq, srcLoc,orientation='Z') for freq in freqs]
|
||||
|
||||
survey = EM.FDEM.Survey(srcList)
|
||||
prb = EM.FDEM.Problem_b(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping)
|
||||
|
||||
try:
|
||||
from pymatsolver import MumpsSolver
|
||||
|
||||
@@ -0,0 +1,275 @@
|
||||
from SimPEG import *
|
||||
from SimPEG.EM import FDEM, Analytics, mu_0
|
||||
import time
|
||||
|
||||
try:
|
||||
from pymatsolver import MumpsSolver
|
||||
solver = MumpsSolver
|
||||
except Exception:
|
||||
solver = SolverLU
|
||||
pass
|
||||
|
||||
def run(plotIt=True):
|
||||
"""
|
||||
EM: Schenkel and Morrison Casing Model
|
||||
======================================
|
||||
|
||||
Here we create and run a FDEM forward simulation to calculate the vertical
|
||||
current inside a steel-cased. The model is based on the Schenkel and
|
||||
Morrison Casing Model, and the results are used in a 2016 SEG abstract by
|
||||
Yang et al.
|
||||
|
||||
- Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686.
|
||||
|
||||
|
||||
The model consists of:
|
||||
- Air: Conductivity 1e-8 S/m, above z = 0
|
||||
- Background: conductivity 1e-2 S/m, below z = 0
|
||||
- Casing: conductivity 1e6 S/m
|
||||
- 300m long
|
||||
- radius of 0.1m
|
||||
- thickness of 6e-3m
|
||||
|
||||
Inside the casing, we take the same conductivity as the background.
|
||||
|
||||
We are using an EM code to simulate DC, so we use frequency low enough
|
||||
that the skin depth inside the casing is longer than the casing length (f
|
||||
= 1e-6 Hz). The plot produced is of the current inside the casing.
|
||||
|
||||
These results are shown in the SEG abstract by Yang et al., 2016: 3D DC
|
||||
resistivity modeling of steel casing for reservoir monitoring using
|
||||
equivalent resistor network. The solver used to produce these results and
|
||||
achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_
|
||||
|
||||
.. _pymatsolver: https://github.com/rowanc1/pymatsolver
|
||||
|
||||
This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1
|
||||
|
||||
If you would use this example for a code comparison, or build upon it, a
|
||||
citation would be much appreciated!
|
||||
|
||||
"""
|
||||
|
||||
if plotIt:
|
||||
import matplotlib.pylab as plt
|
||||
|
||||
# ------------------ MODEL ------------------
|
||||
sigmaair = 1e-8 # air
|
||||
sigmaback = 1e-2 # background
|
||||
sigmacasing = 1e6 # casing
|
||||
sigmainside = sigmaback # inside the casing
|
||||
|
||||
|
||||
casing_t = 0.006 # 1cm thickness
|
||||
casing_l = 300 # length of the casing
|
||||
|
||||
casing_r = 0.1
|
||||
casing_a = casing_r - casing_t/2. # inner radius
|
||||
casing_b = casing_r + casing_t/2. # outer radius
|
||||
casing_z = np.r_[-casing_l,0.]
|
||||
|
||||
|
||||
# ------------------ SURVEY PARAMETERS ------------------
|
||||
freqs = np.r_[1e-6] #[1e-1, 1, 5] # frequencies
|
||||
dsz = -300 # down-hole z source location
|
||||
src_loc = np.r_[0.,0.,dsz]
|
||||
inf_loc = np.r_[0.,0.,1e4]
|
||||
|
||||
print 'Skin Depth: ', [(500./np.sqrt(sigmaback*_)) for _ in freqs]
|
||||
|
||||
|
||||
# ------------------ MESH ------------------
|
||||
# fine cells near well bore
|
||||
csx1, csx2 = 2e-3, 60.
|
||||
pfx1, pfx2 = 1.3, 1.3
|
||||
ncx1 = np.ceil(casing_b/csx1+2)
|
||||
|
||||
# pad nicely to second cell size
|
||||
npadx1 = np.floor(np.log(csx2/csx1) / np.log(pfx1))
|
||||
hx1a,hx1b = Utils.meshTensor([(csx1,ncx1)]),Utils.meshTensor([(csx1,npadx1,pfx1)])
|
||||
dx1 = sum(hx1a)+sum(hx1b)
|
||||
dx1 = np.floor(dx1/csx2)
|
||||
hx1b *= (dx1*csx2 - sum(hx1a))/sum(hx1b)
|
||||
|
||||
# second chunk of mesh
|
||||
dx2 = 300. # uniform mesh out to here
|
||||
ncx2 = np.ceil((dx2 - dx1)/csx2)
|
||||
npadx2 = 45
|
||||
hx2a, hx2b = Utils.meshTensor([(csx2,ncx2)]), Utils.meshTensor([(csx2,npadx2,pfx2)])
|
||||
hx = np.hstack([hx1a,hx1b,hx2a,hx2b])
|
||||
|
||||
# z-direction
|
||||
csz = 0.05
|
||||
nza = 10
|
||||
ncz, npadzu, npadzd = np.int(np.ceil(np.diff(casing_z)[0]/csz))+10, 68, 68 # cell size, number of core cells, number of padding cells in the x- direction
|
||||
hz = Utils.meshTensor([(csz,npadzd,-1.3), (csz,ncz), (csz,npadzu,1.3)]) # vector of cell widths in the z-direction
|
||||
|
||||
# Mesh
|
||||
mesh = Mesh.CylMesh([hx,1.,hz], [0.,0.,-np.sum(hz[:npadzu+ncz-nza])])
|
||||
|
||||
print 'Mesh Extent xmax: %f,: zmin: %f, zmax: %f'%(mesh.vectorCCx.max(), mesh.vectorCCz.min(), mesh.vectorCCz.max())
|
||||
print 'Number of cells', mesh.nC
|
||||
|
||||
if plotIt is True:
|
||||
fig, ax = plt.subplots(1, 1, figsize=(6, 4))
|
||||
ax.set_title('Simulation Mesh')
|
||||
mesh.plotGrid(ax=ax)
|
||||
plt.show()
|
||||
|
||||
# Put the model on the mesh
|
||||
sigWholespace = sigmaback*np.ones((mesh.nC))
|
||||
|
||||
sigBack = sigWholespace.copy()
|
||||
sigBack[mesh.gridCC[:,2] > 0.] = sigmaair
|
||||
|
||||
sigCasing = sigBack.copy()
|
||||
iCasingZ = (mesh.gridCC[:,2] <= casing_z[1]) & (mesh.gridCC[:,2] >= casing_z[0])
|
||||
iCasingX = (mesh.gridCC[:,0] >= casing_a) & (mesh.gridCC[:,0] <= casing_b)
|
||||
iCasing = iCasingX & iCasingZ
|
||||
sigCasing[iCasing] = sigmacasing
|
||||
|
||||
|
||||
if plotIt is True:
|
||||
|
||||
# plotting parameters
|
||||
xlim = np.r_[0., 0.2]
|
||||
zlim = np.r_[-350., 10.]
|
||||
clim_sig = np.r_[-8,6]
|
||||
|
||||
# plot models
|
||||
fig, ax = plt.subplots(1,1,figsize=(4,4))
|
||||
|
||||
f = plt.colorbar(mesh.plotImage(np.log10(sigCasing),ax=ax)[0], ax=ax)
|
||||
ax.grid(which='both')
|
||||
ax.set_title('Log_10 (Sigma)')
|
||||
ax.set_xlim(xlim)
|
||||
ax.set_ylim(zlim)
|
||||
f.set_clim(clim_sig)
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
# -------------- Sources --------------------
|
||||
# Define Custom Current Sources
|
||||
|
||||
# surface source
|
||||
sg_x = np.zeros(mesh.vnF[0],dtype=complex)
|
||||
sg_y = np.zeros(mesh.vnF[1],dtype=complex)
|
||||
sg_z = np.zeros(mesh.vnF[2],dtype=complex)
|
||||
|
||||
nza = 2 # put the wire two cells above the surface
|
||||
ncin = 2
|
||||
|
||||
# vertically directed wire
|
||||
sgv_indx = (mesh.gridFz[:,0] > casing_a) & (mesh.gridFz[:,0] < casing_a + csx1) # hook it up to casing at the surface
|
||||
sgv_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] >= -csz*2)
|
||||
sgv_ind = sgv_indx & sgv_indz
|
||||
sg_z[sgv_ind] = -1.
|
||||
|
||||
# horizontally directed wire
|
||||
sgh_indx = (mesh.gridFx[:,0] > casing_a) & (mesh.gridFx[:,0] <= inf_loc[2])
|
||||
sgh_indz = (mesh.gridFx[:,2] > csz*(nza-0.5)) & (mesh.gridFx[:,2] < csz*(nza+0.5))
|
||||
sgh_ind = sgh_indx & sgh_indz
|
||||
sg_x[sgh_ind] = -1.
|
||||
|
||||
sgv2_indx = (mesh.gridFz[:,0] >= mesh.gridFx[sgh_ind,0].max()) & (mesh.gridFz[:,0] <= inf_loc[2]*1.2) # hook it up to casing at the surface
|
||||
sgv2_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] >= -csz*2)
|
||||
sgv2_ind = sgv2_indx & sgv2_indz
|
||||
sg_z[sgv2_ind] = 1.
|
||||
|
||||
# assemble the source
|
||||
sg = np.hstack([sg_x,sg_y,sg_z])
|
||||
sg_p = [FDEM.Src.RawVec_e([],_,sg/mesh.area) for _ in freqs]
|
||||
|
||||
# downhole source
|
||||
dg_x = np.zeros(mesh.vnF[0],dtype=complex)
|
||||
dg_y = np.zeros(mesh.vnF[1],dtype=complex)
|
||||
dg_z = np.zeros(mesh.vnF[2],dtype=complex)
|
||||
|
||||
# vertically directed wire
|
||||
dgv_indx = (mesh.gridFz[:,0] < csx1) # go through the center of the well
|
||||
dgv_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] > dsz + csz/2.)
|
||||
dgv_ind = dgv_indx & dgv_indz
|
||||
dg_z[dgv_ind] = -1.
|
||||
|
||||
# couple to the casing downhole
|
||||
dgh_indx = mesh.gridFx[:,0] < casing_a + csx1
|
||||
dgh_indz = (mesh.gridFx[:,2] < dsz + csz) & (mesh.gridFx[:,2] >= dsz)
|
||||
dgh_ind = dgh_indx & dgh_indz
|
||||
dg_x[dgh_ind] = 1.
|
||||
|
||||
# horizontal part at surface
|
||||
dgh2_indx = mesh.gridFx[:,0] <= inf_loc[2]*1.2
|
||||
dgh2_indz = sgh_indz.copy()
|
||||
dgh2_ind = dgh2_indx & dgh2_indz
|
||||
dg_x[dgh2_ind] = -1.
|
||||
|
||||
# vertical part at surface
|
||||
dgv2_ind = sgv2_ind.copy()
|
||||
dg_z[dgv2_ind] = 1.
|
||||
|
||||
# assemble the source
|
||||
dg = np.hstack([dg_x,dg_y,dg_z])
|
||||
dg_p = [FDEM.Src.RawVec_e([],_,dg/mesh.area) for _ in freqs]
|
||||
|
||||
# ------------ Problem and Survey ---------------
|
||||
survey = FDEM.Survey(sg_p + dg_p)
|
||||
mapping = [('sigma', Maps.IdentityMap(mesh))]
|
||||
problem = FDEM.Problem3D_h(mesh, mapping=mapping)
|
||||
problem.pair(survey)
|
||||
|
||||
# ------------- Solve ---------------------------
|
||||
t0 = time.time()
|
||||
fieldsCasing = problem.fields(sigCasing)
|
||||
print 'Time to solve 2 sources', time.time() - t0
|
||||
|
||||
# Plot current
|
||||
|
||||
# current density
|
||||
jn0 = fieldsCasing[dg_p,'j']
|
||||
jn1 = fieldsCasing[sg_p,'j']
|
||||
|
||||
# current
|
||||
in0 = [mesh.area*fieldsCasing[dg_p,'j'][:,i] for i in range(len(freqs))]
|
||||
in1 = [mesh.area*fieldsCasing[sg_p,'j'][:,i] for i in range(len(freqs))]
|
||||
|
||||
in0 = np.vstack(in0).T
|
||||
in1 = np.vstack(in1).T
|
||||
|
||||
# integrate to get z-current inside casing
|
||||
inds_inx = (mesh.gridFz[:,0] >= casing_a) & (mesh.gridFz[:,0] <= casing_b)
|
||||
inds_inz = (mesh.gridFz[:,2] >= dsz ) & (mesh.gridFz[:,2] <= 0)
|
||||
inds_fz = inds_inx & inds_inz
|
||||
|
||||
indsx = [False]*mesh.nFx
|
||||
inds = list(indsx) + list(inds_fz)
|
||||
|
||||
in0_in = in0[np.r_[inds]]
|
||||
in1_in = in1[np.r_[inds]]
|
||||
z_in = mesh.gridFz[inds_fz,2]
|
||||
|
||||
in0_in = in0_in.reshape([in0_in.shape[0]/3,3])
|
||||
in1_in = in1_in.reshape([in1_in.shape[0]/3,3])
|
||||
z_in = z_in.reshape([z_in.shape[0]/3,3])
|
||||
|
||||
I0 = in0_in.sum(1).real
|
||||
I1 = in1_in.sum(1).real
|
||||
z_in = z_in[:,0]
|
||||
|
||||
if plotIt is True:
|
||||
fig, ax = plt.subplots(1,2,figsize=(12,4))
|
||||
|
||||
ax[0].plot(z_in,np.absolute(I0), z_in,np.absolute(I1))
|
||||
ax[0].legend(['top casing', 'bottom casing'],loc='best')
|
||||
ax[0].set_title('Magnitude of Vertical Current in Casing')
|
||||
|
||||
ax[1].semilogy(z_in,np.absolute(I0), z_in,np.absolute(I1))
|
||||
ax[1].legend(['top casing', 'bottom casing'],loc='best')
|
||||
ax[1].set_title('Magnitude of Vertical Current in Casing')
|
||||
ax[1].set_ylim([1e-2, 1.])
|
||||
|
||||
plt.show()
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
from SimPEG import *
|
||||
|
||||
|
||||
def run(N=100, plotIt=True):
|
||||
"""
|
||||
Inversion: Linear Problem
|
||||
=========================
|
||||
|
||||
Here we go over the basics of creating a linear problem and inversion.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
np.random.seed(1)
|
||||
|
||||
std_noise = 1e-2
|
||||
|
||||
mesh = Mesh.TensorMesh([N])
|
||||
|
||||
m0 = np.ones(mesh.nC) * 1e-4
|
||||
mref = np.zeros(mesh.nC)
|
||||
|
||||
nk = 10
|
||||
jk = np.linspace(1.,nk,nk)
|
||||
p = -2.
|
||||
q = 1.
|
||||
|
||||
g = lambda k: np.exp(p*jk[k]*mesh.vectorCCx)*np.cos(np.pi*q*jk[k]*mesh.vectorCCx)
|
||||
|
||||
G = np.empty((nk, mesh.nC))
|
||||
|
||||
for i in range(nk):
|
||||
G[i,:] = g(i)
|
||||
|
||||
mtrue = np.zeros(mesh.nC)
|
||||
mtrue[mesh.vectorCCx > 0.3] = 1.
|
||||
mtrue[mesh.vectorCCx > 0.45] = -0.5
|
||||
mtrue[mesh.vectorCCx > 0.6] = 0
|
||||
|
||||
|
||||
prob = Problem.LinearProblem(mesh, G)
|
||||
survey = Survey.LinearSurvey()
|
||||
survey.pair(prob)
|
||||
survey.dobs = prob.fields(mtrue) + std_noise * np.random.randn(nk)
|
||||
#survey.makeSyntheticData(mtrue, std=std_noise)
|
||||
|
||||
wd = np.ones(nk) * std_noise
|
||||
|
||||
#print survey.std[0]
|
||||
#M = prob.mesh
|
||||
# Distance weighting
|
||||
wr = np.sum(prob.G**2.,axis=0)**0.5
|
||||
wr = ( wr/np.max(wr) )
|
||||
|
||||
# reg = Regularization.Simple(mesh)
|
||||
# reg.mref = mref
|
||||
# reg.cell_weights = wr
|
||||
#
|
||||
dmis = DataMisfit.l2_DataMisfit(survey)
|
||||
dmis.Wd = 1./wd
|
||||
#
|
||||
# opt = Optimization.ProjectedGNCG(maxIter=20,lower=-2.,upper=2., maxIterCG= 10, tolCG = 1e-4)
|
||||
# invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
|
||||
# invProb.curModel = m0
|
||||
#
|
||||
# beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1)
|
||||
# target = Directives.TargetMisfit()
|
||||
#
|
||||
betaest = Directives.BetaEstimate_ByEig()
|
||||
# inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target])
|
||||
#
|
||||
#
|
||||
# mrec = inv.run(m0)
|
||||
# ml2 = mrec
|
||||
# print "Final misfit:" + str(invProb.dmisfit.eval(mrec))
|
||||
#
|
||||
# # Switch regularization to sparse
|
||||
# phim = invProb.phi_m_last
|
||||
# phid = invProb.phi_d
|
||||
|
||||
reg = Regularization.Sparse(mesh)
|
||||
reg.mref = mref
|
||||
reg.cell_weights = wr
|
||||
|
||||
reg.mref = np.zeros(mesh.nC)
|
||||
eps_p = 5e-2
|
||||
eps_q = 5e-2
|
||||
norms = [0., 0., 2., 2.]
|
||||
|
||||
opt = Optimization.ProjectedGNCG(maxIter=100 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3)
|
||||
invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
|
||||
update_Jacobi = Directives.Update_lin_PreCond()
|
||||
IRLS = Directives.Update_IRLS( norms=norms, eps_p=eps_p, eps_q=eps_q)
|
||||
|
||||
inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest,update_Jacobi])
|
||||
|
||||
# Run inversion
|
||||
mrec = inv.run(m0)
|
||||
|
||||
print "Final misfit:" + str(invProb.dmisfit.eval(mrec))
|
||||
|
||||
|
||||
if plotIt:
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2))
|
||||
for i in range(prob.G.shape[0]):
|
||||
axes[0].plot(prob.G[i,:])
|
||||
axes[0].set_title('Columns of matrix G')
|
||||
|
||||
axes[1].plot(mesh.vectorCCx, mtrue, 'b-')
|
||||
axes[1].plot(mesh.vectorCCx, reg.l2model, 'r-')
|
||||
#axes[1].legend(('True Model', 'Recovered Model'))
|
||||
axes[1].set_ylim(-1.0,1.25)
|
||||
|
||||
axes[1].plot(mesh.vectorCCx, mrec, 'k-',lw = 2)
|
||||
axes[1].legend(('True Model', 'Smooth l2-l2',
|
||||
'Sparse lp:' + str(reg.norms[0]) + ', lqx:' + str(reg.norms[1]) ), fontsize = 12)
|
||||
plt.show()
|
||||
|
||||
return prob, survey, mesh, mrec
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
@@ -1,9 +1,11 @@
|
||||
import SimPEG as simpeg
|
||||
import numpy as np
|
||||
import SimPEG.MT as MT
|
||||
from SimPEG import NSEM
|
||||
from scipy.constants import mu_0
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
np.random.seed(1983)
|
||||
|
||||
def run(plotIt=True):
|
||||
"""
|
||||
MT: 1D: Inversion
|
||||
@@ -17,13 +19,13 @@ def run(plotIt=True):
|
||||
## Setup the forward modeling
|
||||
# Setting up 1D mesh and conductivity models to forward model data.
|
||||
# Frequency
|
||||
nFreq = 31
|
||||
freqs = np.logspace(3,-3,nFreq)
|
||||
nFreq = 26
|
||||
freqs = np.logspace(2,-3,nFreq)
|
||||
# Set mesh parameters
|
||||
ct = 20
|
||||
air = simpeg.Utils.meshTensor([(ct,16,1.4)])
|
||||
ct = 10
|
||||
air = simpeg.Utils.meshTensor([(ct,25,1.4)])
|
||||
core = np.concatenate( ( np.kron(simpeg.Utils.meshTensor([(ct,10,-1.3)]),np.ones((5,))) , simpeg.Utils.meshTensor([(ct,5)]) ) )
|
||||
bot = simpeg.Utils.meshTensor([(core[0],10,-1.4)])
|
||||
bot = simpeg.Utils.meshTensor([(core[0],25,-1.4)])
|
||||
x0 = -np.array([np.sum(np.concatenate((core,bot)))])
|
||||
# Make the model
|
||||
m1d = simpeg.Mesh.TensorMesh([np.concatenate((bot,core,air))], x0=x0)
|
||||
@@ -33,7 +35,7 @@ def run(plotIt=True):
|
||||
layer1 = (m1d.vectorCCx<-500.) & (m1d.vectorCCx>=-800.)
|
||||
layer2 = (m1d.vectorCCx<-3500.) & (m1d.vectorCCx>=-5000.)
|
||||
# Set the conductivity values
|
||||
sig_half = 2e-3
|
||||
sig_half = 1e-2
|
||||
sig_air = 1e-8
|
||||
sig_layer1 = .2
|
||||
sig_layer2 = .2
|
||||
@@ -50,38 +52,38 @@ def run(plotIt=True):
|
||||
m_0 = np.log(sigma_0[active])
|
||||
|
||||
# Set the mapping
|
||||
actMap = simpeg.Maps.ActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx)
|
||||
actMap = simpeg.Maps.InjectActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx)
|
||||
mappingExpAct = simpeg.Maps.ExpMap(m1d) * actMap
|
||||
|
||||
## Setup the layout of the survey, set the sources and the connected receivers
|
||||
# Receivers
|
||||
rxList = []
|
||||
for rxType in ['z1dr','z1di']:
|
||||
rxList.append(MT.Rx(simpeg.mkvc(np.array([0.0]),2).T,rxType))
|
||||
rxList.append(NSEM.Rx(simpeg.mkvc(np.array([-0.5]),2).T,rxType))
|
||||
# Source list
|
||||
srcList =[]
|
||||
for freq in freqs:
|
||||
srcList.append(MT.SrcMT.polxy_1Dprimary(rxList,freq))
|
||||
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,freq))
|
||||
# Make the survey
|
||||
survey = MT.Survey(srcList)
|
||||
survey = NSEM.Survey(srcList)
|
||||
survey.mtrue = m_true
|
||||
|
||||
## Set the problem
|
||||
problem = MT.Problem1D.eForm_psField(m1d,sigmaPrimary=sigma_0,mapping=mappingExpAct)
|
||||
problem = NSEM.Problem1D_ePrimSec(m1d,sigmaPrimary=sigma_0,mapping=mappingExpAct)
|
||||
problem.pair(survey)
|
||||
|
||||
## Forward model data
|
||||
# Project the data
|
||||
survey.dtrue = survey.dpred(m_true)
|
||||
survey.dobs = survey.dtrue + 0.025*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
|
||||
survey.dobs = survey.dtrue + 0.01*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
|
||||
|
||||
if plotIt:
|
||||
fig = MT.Utils.dataUtils.plotMT1DModelData(problem)
|
||||
fig = NSEM.Utils.dataUtils.plotMT1DModelData(problem,[])
|
||||
fig.suptitle('Target - smooth true')
|
||||
|
||||
|
||||
# Assign uncertainties
|
||||
std = 0.05 # 5% std
|
||||
std = 0.025 # 5% std
|
||||
survey.std = np.abs(survey.dobs*std)
|
||||
# Assign the data weight
|
||||
Wd = 1./survey.std
|
||||
@@ -90,30 +92,33 @@ def run(plotIt=True):
|
||||
# Define a counter
|
||||
C = simpeg.Utils.Counter()
|
||||
# Set the optimization
|
||||
opt = simpeg.Optimization.InexactGaussNewton(maxIter = 30)
|
||||
opt = simpeg.Optimization.ProjectedGNCG(maxIter = 25)
|
||||
opt.counter = C
|
||||
opt.LSshorten = 0.5
|
||||
opt.lower = np.log(1e-4)
|
||||
opt.upper = np.log(5)
|
||||
opt.LSshorten = 0.1
|
||||
opt.remember('xc')
|
||||
# Data misfit
|
||||
dmis = simpeg.DataMisfit.l2_DataMisfit(survey)
|
||||
dmis.Wd = Wd
|
||||
# Regularization - with a regularization mesh
|
||||
regMesh = simpeg.Mesh.TensorMesh([m1d.hx[problem.mapping.sigmaMap.maps[-1].indActive]],m1d.x0)
|
||||
regMesh = simpeg.Mesh.TensorMesh([m1d.hx[active]],m1d.x0)
|
||||
reg = simpeg.Regularization.Tikhonov(regMesh)
|
||||
reg.smoothModel = True
|
||||
reg.alpha_s = 1e-7
|
||||
reg.mrefInSmooth = True
|
||||
reg.alpha_s = 1e-1
|
||||
reg.alpha_x = 1.
|
||||
|
||||
# Inversion problem
|
||||
invProb = simpeg.InvProblem.BaseInvProblem(dmis, reg, opt)
|
||||
invProb.counter = C
|
||||
# Beta cooling
|
||||
beta = simpeg.Directives.BetaSchedule()
|
||||
beta.coolingRate = 4
|
||||
betaest = simpeg.Directives.BetaEstimate_ByEig(beta0_ratio=0.75)
|
||||
beta.coolingRate = 4.
|
||||
beta.coolingFactor = 4.
|
||||
betaest = simpeg.Directives.BetaEstimate_ByEig(beta0_ratio=1.)
|
||||
betaest.beta0 = 1.
|
||||
targmis = simpeg.Directives.TargetMisfit()
|
||||
targmis.target = survey.nD
|
||||
saveModel = simpeg.Directives.SaveModelEveryIteration()
|
||||
saveModel.fileName = 'Inversion_TargMisEqnD_smoothTrue'
|
||||
# Create an inversion object
|
||||
inv = simpeg.Inversion.BaseInversion(invProb, directiveList=[beta,betaest,targmis])
|
||||
|
||||
@@ -121,8 +126,9 @@ def run(plotIt=True):
|
||||
mopt = inv.run(m_0)
|
||||
|
||||
if plotIt:
|
||||
fig = MT.Utils.dataUtils.plotMT1DModelData(problem,[mopt])
|
||||
fig = NSEM.Utils.dataUtils.plotMT1DModelData(problem,[mopt])
|
||||
fig.suptitle('Target - smooth true')
|
||||
fig.axes[0].set_ylim([-10000,500])
|
||||
plt.show()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
from scipy.constants import epsilon_0, mu_0
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from ipywidgets import *
|
||||
from SimPEG.EM.Utils import k, omega
|
||||
|
||||
"""
|
||||
MT1D: n layered earth problem
|
||||
*****************************
|
||||
|
||||
Author: Thibaut Astic
|
||||
Contact: thast@eos.ubc.ca
|
||||
Date: January 2016
|
||||
|
||||
This code compute the analytic response of a n-layered Earth to a plane wave (Magneto-Tellurics).
|
||||
|
||||
We start by looking at Maxwell's equations in the electric
|
||||
field \\\(\\\mathbf{E}\\) and the magnetic flux
|
||||
\\\(\\\mathbf{H}\\) to write the wave equations
|
||||
\\(\\ \nabla ^2 \mathbf{E_x} + k^2 \mathbf{E_x} = 0 \\) &
|
||||
\\(\\ \nabla ^2 \mathbf{H_y} + k^2 \mathbf{H_y} = 0 \\)
|
||||
|
||||
Then solving the equations in each layer "j" between z_{j-1} and z_j in the form of
|
||||
\\(\\ E_{x,j} (z) = U_j e^{i k (z-z_{j-1})} + D_j e^{-i k (z-z_{j-1})} \\)
|
||||
\\(\\ H_{y,j} (z) = \frac{1}{Z_j} (D_j e^{-i k (z-z_{j-1})} - U_j e^{i k (z-z_{j-1})}) \\)
|
||||
|
||||
With U and D the Up and Down components of the E-field.
|
||||
|
||||
The iteration from one layer to another is ensure by:
|
||||
|
||||
\\(\\ \left(\begin{matrix} E_{x,j} \\ H_{y,j} \end{matrix} \right) =
|
||||
P_j T_j P^{-1}_J \left(\begin{matrix} E_{x,j+1} \\ H_{y,j+1} \end{matrix} \right) \\)
|
||||
|
||||
And the Boundary Condition is set for the E-field in the last layer, with no Up component (=0)
|
||||
and only a down component (=1 then normalized by the highest amplitude to ensure numeric stability)
|
||||
|
||||
The layer 0 is assumed to be the air layer.
|
||||
|
||||
"""
|
||||
|
||||
#Define a frquency range for a survey
|
||||
frange = lambda minfreq, maxfreq, step: np.logspace(minfreq,maxfreq,num = step, base = 10.)
|
||||
|
||||
#Functions to create random physical Perties for a n-layered earth
|
||||
thick = lambda minthick, maxthick, nlayer: np.append(np.array([1.2*10.**5]),
|
||||
np.ndarray.round(minthick + (maxthick-minthick)* np.random.rand(nlayer-1,1)
|
||||
,decimals =1))
|
||||
|
||||
sig = lambda minsig, maxsig, nlayer: np.append(np.array([0.]),
|
||||
np.ndarray.round(10.**minsig + (10.**maxsig-10.**minsig)* np.random.rand(nlayer,1)
|
||||
,decimals=3))
|
||||
|
||||
mu = lambda minmu, maxmu, nlayer: np.append(np.array([1.]),
|
||||
np.ndarray.round(minmu + (maxmu-minmu)* np.random.rand(nlayer,1)
|
||||
,decimals=1))
|
||||
|
||||
eps = lambda mineps, maxeps, nlayer: np.append(np.array([1.]),
|
||||
np.ndarray.round(mineps + (maxeps-mineps)* np.random.rand(nlayer,1)
|
||||
,decimals=1))
|
||||
|
||||
#Evaluate Impedance Z of a layer
|
||||
ImpZ = lambda f, mu, k: omega(f)*mu*mu_0/k
|
||||
|
||||
#Complex Cole-Cole Conductivity - EM utils
|
||||
PCC= lambda siginf,m,t,c,f: siginf*(1.-(m/(1.+(1j*omega(f)*t)**c)))
|
||||
|
||||
#Converted thickness array into top of layer array
|
||||
top = lambda thick: np.cumsum(thick)
|
||||
|
||||
#Propagation Matrix and theirs inverses
|
||||
|
||||
#matrix T for transition of Up and Down components accross a layer
|
||||
T = lambda h,k: np.matrix([[np.exp(1j*k*h),0.],[0.,np.exp(-1j*k*h)]],dtype='complex_')
|
||||
|
||||
Tinv = lambda h,k: np.matrix([[np.exp(-1j*k*h),0.],[0.,np.exp(1j*k*h)]],dtype='complex_')
|
||||
|
||||
#transition of Up and Down components accross a layer
|
||||
UD_Z = lambda UD,z,zj,k : T((z-zj),k)*UD
|
||||
|
||||
|
||||
#matrix P relating Up and Down components with E and H fields
|
||||
P = lambda z: np.matrix([[1.,1,],[-1./z,1./z]],dtype='complex_')
|
||||
|
||||
Pinv = lambda z: np.matrix([[1.,-z],[1.,z]],dtype='complex_')/2.
|
||||
|
||||
|
||||
#Time Variation of E and H
|
||||
E_ZT = lambda U,D,f,t : np.exp(1j*omega(f)*t)*(U+D)
|
||||
H_ZT = lambda U,D,Z,f,t : (1./Z)*np.exp(1j*omega(f)*t)*(D-U)
|
||||
|
||||
#Plot the configuration of the problem
|
||||
def PlotConfiguration(thick,sig,eps,mu,ax,widthg,z):
|
||||
|
||||
topn = top(thick)
|
||||
widthn = np.arange(-widthg,widthg+widthg/10.,widthg/10.)
|
||||
|
||||
ax.set_ylim([z.min(),z.max()])
|
||||
ax.set_xlim([-widthg,widthg])
|
||||
|
||||
ax.set_ylabel("Depth (m)", fontsize=16.)
|
||||
ax.yaxis.tick_right()
|
||||
ax.yaxis.set_label_position("right")
|
||||
|
||||
#define filling for the different layers
|
||||
hatches=['/' , '+', 'x', '|' , '\\', '-' , 'o' , 'O' , '.' , '*' ]
|
||||
|
||||
#Write the physical properties of air
|
||||
ax.annotate(("Air, $\sigma$ =%1.0f mS/m")%(sig[0]*10**(3)),
|
||||
xy=(-widthg/2., -np.abs(z.max())/2.), xycoords='data',
|
||||
xytext=(-widthg/2., -np.abs(z.max())/2.), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
ax.annotate(("$\epsilon_r$= %1i")%(eps[0]),
|
||||
xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data',
|
||||
xytext=(-widthg/2., -np.abs(z.max())/3.), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
ax.annotate(("$\mu_r$= %1i")%(mu[0]),
|
||||
xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data',
|
||||
xytext=(0, -np.abs(z.max())/3.), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
#Write the physical properties of the differents layers up to the (n-1)-th and fill it with pattern
|
||||
for i in range(1,len(topn)-1,1):
|
||||
if topn[i] == topn[i+1]:
|
||||
pass
|
||||
else:
|
||||
ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[i]*10**(3)),
|
||||
xy=(0., (2.*topn[i]+topn[i+1])/3), xycoords='data',
|
||||
xytext=(0., (2.*topn[i]+topn[i+1])/3), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
ax.annotate(("$\epsilon_r$= %1i")%(eps[i]),
|
||||
xy=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), xycoords='data',
|
||||
xytext=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
ax.annotate(("$\mu_r$= %1.2f")%(mu[i]),
|
||||
xy=(-widthg/2., (2.*topn[i]+topn[i+1])/3), xycoords='data',
|
||||
xytext=(-widthg/2., (2.*topn[i]+topn[i+1])/3), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
ax.plot(widthn,topn[i]*np.ones_like(widthn),color='black')
|
||||
ax.fill_between(widthn,topn[i],topn[i+1],alpha=0.3,color="none",edgecolor='black', hatch=hatches[(i-1)%10])
|
||||
|
||||
#Write the physical properties of the n-th layer and fill it with pattern
|
||||
ax.plot(widthn,topn[-1]*np.ones_like(widthn),color='black')
|
||||
ax.fill_between(widthn,topn[-1],z.max(),alpha=0.3,color="none",edgecolor='black', hatch=hatches[(len(topn)-2)%10])
|
||||
|
||||
ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[-1]*10**(3)),
|
||||
xy=(0., (2.*topn[-1]+z.max())/3), xycoords='data',
|
||||
xytext=(0., (2.*topn[-1]+z.max())/3), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
ax.annotate(("$\epsilon_r$= %1i")%(eps[-1]),
|
||||
xy=(-widthg/1.1, (2.*topn[-1]+z.max())/3), xycoords='data',
|
||||
xytext=(-widthg/1.1, (2.*topn[-1]+z.max())/3), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
ax.annotate(("$\mu_r$= %1.2f")%(mu[-1]),
|
||||
xy=(-widthg/2., (2.*topn[-1]+z.max())/3), xycoords='data',
|
||||
xytext=(-widthg/2., (2.*topn[-1]+z.max())/3), textcoords='data',
|
||||
fontsize=14.)
|
||||
|
||||
#plot Trees!
|
||||
ax.annotate("",
|
||||
xy=(widthg/2., -1.*z.max()/5.), xycoords='data',
|
||||
xytext=(widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
ax.annotate("",
|
||||
xy=(widthg/2., -3./4.*z.max()/5.), xycoords='data',
|
||||
xytext=(widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
ax.annotate("",
|
||||
xy=(widthg/2., -1./2.*z.max()/5.), xycoords='data',
|
||||
xytext=(widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
ax.annotate("",
|
||||
xy=(1.2*widthg/2., -1.*z.max()/5.), xycoords='data',
|
||||
xytext=(1.2*widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
ax.annotate("",
|
||||
xy=(1.2*widthg/2., -3./4.*z.max()/5.), xycoords='data',
|
||||
xytext=(1.2*widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
ax.annotate("",
|
||||
xy=(1.2*widthg/2., -1./2.*z.max()/5.), xycoords='data',
|
||||
xytext=(1.2*widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
ax.annotate("",
|
||||
xy=(1.5*widthg/2., -1.*z.max()/5.), xycoords='data',
|
||||
xytext=(1.5*widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
ax.annotate("",
|
||||
xy=(1.5*widthg/2., -3./4.*z.max()/5.), xycoords='data',
|
||||
xytext=(1.5*widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
ax.annotate("",
|
||||
xy=(1.5*widthg/2., -1./2.*z.max()/5.), xycoords='data',
|
||||
xytext=(1.5*widthg/2., 0.), textcoords='data',
|
||||
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
|
||||
)
|
||||
|
||||
|
||||
ax.invert_yaxis()
|
||||
|
||||
return ax
|
||||
|
||||
#Propagate Up and Down component for a certain frequency & evaluate E and H field
|
||||
|
||||
def Propagate(f,H,sig,chg,taux,c,mu,eps,n):
|
||||
|
||||
sigcm = np.zeros_like(sig,dtype='complex_')
|
||||
|
||||
for j in range(1,len(sig)):
|
||||
sigcm[j]=PCC(sig[j],chg[j],taux[j],c[j],f)
|
||||
|
||||
K = k(f, sigcm, mu, eps)
|
||||
Z = ImpZ(f,mu,K)
|
||||
|
||||
EH = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_')
|
||||
UD = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_')
|
||||
|
||||
UD[1,-1] = 1.
|
||||
|
||||
for i in range(-2,-(n+2),-1):
|
||||
|
||||
UD[:,i] = Tinv(H[i+1],K[i])*Pinv(Z[i])*P(Z[i+1])*UD[:,i+1]
|
||||
UD = UD/((np.abs(UD[0,:]+UD[1,:])).max())
|
||||
|
||||
for j in range(0,n+1):
|
||||
EH[:,j] = np.matrix([[1.,1,],[-1./Z[j],1./Z[j]]])*UD[:,j]
|
||||
|
||||
return UD, EH, Z ,K
|
||||
|
||||
|
||||
#Evaluate the apparent resistivity and phase for a frequency range
|
||||
def appres(F,H,sig,chg,taux,c,mu,eps,n):
|
||||
|
||||
Res = np.zeros_like(F)
|
||||
Phase = np.zeros_like(F)
|
||||
App_ImpZ= np.zeros_like(F,dtype='complex_')
|
||||
|
||||
for i in range(0,len(F)):
|
||||
|
||||
UD,EH,Z ,K = Propagate(F[i],H,sig,chg,taux,c,mu,eps,n)
|
||||
|
||||
App_ImpZ[i] = EH[0,1]/EH[1,1]
|
||||
|
||||
Res[i] = np.abs(App_ImpZ[i])**2./(mu_0*omega(F[i]))
|
||||
Phase[i] = np.angle(App_ImpZ[i], deg = True)
|
||||
|
||||
return Res,Phase
|
||||
|
||||
#Evaluate Up, Down components, E and H field, for a frequency range,
|
||||
#a discretized depth range and a time range (use to calculate envelope)
|
||||
def calculateEHzt(F,H,sig,chg,taux,c,mu,eps,n,zsample,tsample):
|
||||
|
||||
topc = top(H)
|
||||
|
||||
layer = np.zeros(len(zsample),dtype=np.int)-1
|
||||
|
||||
Exzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
|
||||
Hyzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
|
||||
Uz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
|
||||
Dz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
|
||||
UDaux = np.matrix(np.zeros((2,len(zsample)),dtype = 'complex_'),dtype = 'complex_')
|
||||
|
||||
for i in range(0,n+1,1):
|
||||
layer = layer+(zsample>=topc[i])*1
|
||||
|
||||
for j in range(0,len(F)):
|
||||
|
||||
UD,EH,Z ,K = Propagate(F[j],H,sig,chg,taux,c,mu,eps,n)
|
||||
|
||||
for p in range(0,len(zsample)):
|
||||
|
||||
UDaux[:,p] = UD_Z(UD[:,layer[p]],zsample[p],topc[layer[p]],K[layer[p]])
|
||||
|
||||
for q in range(0,len(tsample)):
|
||||
|
||||
Exzt[p,q] = Exzt[p,q] + E_ZT(UDaux[0,p],UDaux[1,p],F[j],tsample[q])/len(F)
|
||||
Hyzt[p,q] = Hyzt[p,q] + H_ZT(UDaux[0,p],UDaux[1,p],Z[layer[p]],F[j],tsample[q])/len(F)
|
||||
Uz[p,q] = Uz[p,q] + UDaux[0,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F)
|
||||
Dz[p,q] = Dz[p,q] + UDaux[1,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F)
|
||||
|
||||
return Exzt,Hyzt,Uz,Dz,UDaux,layer
|
||||
|
||||
|
||||
#Function to Plot Apparent Resistivity and Phase
|
||||
def PlotAppRes(F,H,sig,chg,taux,c,mu,eps,n,fenvelope,PlotEnvelope):
|
||||
|
||||
Res, Phase = appres(F,H,sig,chg,taux,c,mu,eps,n)
|
||||
|
||||
fig,ax = plt.subplots(1,2,figsize=(16,10))
|
||||
|
||||
ax[0].scatter(Res,F,color='black')
|
||||
ax[0].set_xscale('Log')
|
||||
ax[0].set_yscale('Log')
|
||||
ax[0].set_xlim([10.**(np.log10(Res.min())-1.),10.**(np.log10(Res.max())+1.)])
|
||||
ax[0].set_ylim([F.min(),F.max()])
|
||||
ax[0].set_xlabel('Apparent Resistivity (Ohm*m)',fontsize=16.,color="black")
|
||||
ax[0].set_ylabel('Frequency (Hz)',fontsize=16.)
|
||||
ax[0].grid(which='major')
|
||||
|
||||
ax0 = ax[0].twiny()
|
||||
|
||||
ax0.set_xlim([0.,90.])
|
||||
ax0.set_ylim([F.min(),F.max()])
|
||||
ax0.scatter(Phase,F,color='purple')
|
||||
ax0.set_xlabel('Phase (Degrees)',fontsize=16.,color="purple")
|
||||
|
||||
zc=np.arange(-(H[1:].max()+10)*n,(H[1:].max()+10)*n,10.)
|
||||
|
||||
ax[0].tick_params(labelsize=16)
|
||||
ax[1].tick_params(labelsize=16)
|
||||
ax0.tick_params(labelsize=16)
|
||||
|
||||
if PlotEnvelope:
|
||||
|
||||
widthn=np.logspace(np.log10(Res.min())-1., np.log10(Res.max())+1., num=100, endpoint=True, base=10.0)
|
||||
fenvelope1n=np.ones(100)*fenvelope
|
||||
ax[0].plot(widthn,fenvelope1n,linestyle='dashed',color='black')
|
||||
|
||||
tc=np.arange(0.,1./fenvelope,0.01/(fenvelope))
|
||||
Exzt,Hyzt,Uz,Dz,UDaux,layer = calculateEHzt(np.array([fenvelope]),H,sig,chg,taux,c,mu,eps,n,zc,tc)
|
||||
|
||||
ax1=ax[1].twiny()
|
||||
|
||||
ax[1].tick_params(labelsize=16)
|
||||
ax1.tick_params(labelsize=16)
|
||||
|
||||
ax[1].set_xlabel('Amplitude Electric Field E (V/m)',color='blue',fontsize=16)
|
||||
|
||||
ax1.set_xlabel('Amplitude Magnetic Field H (A/m)',color='red',fontsize=16)
|
||||
|
||||
ax[1].fill_betweenx(zc,np.squeeze(np.asarray(np.real(Exzt.min(axis=1)))),
|
||||
np.squeeze(np.asarray(np.real(Exzt.max(axis=1)))),
|
||||
color='blue', alpha=0.1)
|
||||
|
||||
ax1.fill_betweenx(zc,np.squeeze(np.asarray(np.real(Hyzt.min(axis=1)))),
|
||||
np.squeeze(np.asarray(np.real(Hyzt.max(axis=1)))),
|
||||
color='red', alpha=0.1)
|
||||
|
||||
ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],(1.5*np.abs(Exzt).max()),zc)
|
||||
ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()])
|
||||
ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()])
|
||||
else:
|
||||
print 'No envelop (if True, might be slow)'
|
||||
ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],1.,zc)
|
||||
ax[1].get_xaxis().set_ticks([])
|
||||
|
||||
plt.show()
|
||||
|
||||
#Interactive MT for Notebook
|
||||
def PlotAppRes3LayersInteract(h1,h2,sigl1,sigl2,sigl3,mul1,mul2,mul3,epsl1,epsl2,epsl3,PlotEnvelope,F_Envelope):
|
||||
|
||||
frangn=frange(-5,5,100.)
|
||||
sig3= np.array([0.,0.001,0.1, 0.001])
|
||||
thick3 = np.array([120000.,50.,50.])
|
||||
eps3=np.array([1.,1.,1.,1])
|
||||
mu3=np.array([1.,1.,1.,1])
|
||||
chg3=np.array([0.,0.1,0.,0.2])
|
||||
chg3_0=np.array([0.,0.1,0.,0.])
|
||||
taux3=np.array([0.,0.1,0.,0.1])
|
||||
c3=np.array([1.,1.,1.,1.])
|
||||
|
||||
sig3[1]=sigl1
|
||||
sig3[1]=10.**sig3[1]
|
||||
sig3[2]=sigl2
|
||||
sig3[2]=10.**sig3[2]
|
||||
sig3[3]=sigl3
|
||||
sig3[3]=10.**sig3[3]
|
||||
mu3[1]=mul1
|
||||
mu3[2]=mul2
|
||||
mu3[3]=mul3
|
||||
eps3[1]=epsl1
|
||||
eps3[2]=epsl2
|
||||
eps3[3]=epsl3
|
||||
thick3[1]=h1
|
||||
thick3[2]=h2
|
||||
|
||||
PlotAppRes(frangn,thick3,sig3,chg3_0,taux3,c3,mu3,eps3,3,F_Envelope,PlotEnvelope)
|
||||
|
||||
|
||||
def run(n=3,plotIt=True):
|
||||
# something to make a plot
|
||||
|
||||
F = frange(-5.,5.,20)
|
||||
H = thick(50.,100.,n)
|
||||
sign = sig(-5.,0.,n)
|
||||
mun = mu(1.,2.,n)
|
||||
epsn = eps(1.,9.,n)
|
||||
chg = np.zeros_like(sign)
|
||||
taux = np.zeros_like(sign)
|
||||
c = np.zeros_like(sign)
|
||||
|
||||
Res, Phase = appres(F,H,sign,chg,taux,c,mun,epsn,n)
|
||||
|
||||
if plotIt:
|
||||
|
||||
PlotAppRes(F, H, sign, chg, taux, c, mun, epsn, n, fenvelope=1000., PlotEnvelope=True)
|
||||
|
||||
return Res, Phase
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
# Import
|
||||
import SimPEG as simpeg
|
||||
from SimPEG import MT
|
||||
from SimPEG import NSEM
|
||||
import numpy as np
|
||||
try:
|
||||
from pymatsolver import MumpsSolver as Solver
|
||||
@@ -37,16 +37,16 @@ def run(plotIt=True, nFreq=1):
|
||||
for loc in rx_loc:
|
||||
# NOTE: loc has to be a (1,3) np.ndarray otherwise errors accure
|
||||
for rxType in ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi','tzxr','tzxi','tzyr','tzyi']:
|
||||
rxList.append(MT.Rx(simpeg.mkvc(loc,2).T,rxType))
|
||||
rxList.append(NSEM.Rx(simpeg.mkvc(loc,2).T,rxType))
|
||||
# Source list
|
||||
srcList =[]
|
||||
for freq in np.logspace(3,-3,nFreq):
|
||||
srcList.append(MT.SrcMT.polxy_1Dprimary(rxList,freq))
|
||||
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,freq))
|
||||
# Survey MT
|
||||
survey = MT.Survey(srcList)
|
||||
survey = NSEM.Survey(srcList)
|
||||
|
||||
## Setup the problem object
|
||||
problem = MT.Problem3D.eForm_ps(M, sigmaPrimary=sigBG)
|
||||
problem = NSEM.Problem3D_ePrimSec(M, sigmaPrimary=sigBG)
|
||||
problem.pair(survey)
|
||||
problem.Solver = Solver
|
||||
|
||||
@@ -55,7 +55,7 @@ def run(plotIt=True, nFreq=1):
|
||||
dataVec = survey.eval(fields)
|
||||
|
||||
# Make the data
|
||||
mtData = MT.Data(survey,dataVec)
|
||||
mtData = NSEM.Data(survey,dataVec)
|
||||
# Add plots
|
||||
if plotIt:
|
||||
pass
|
||||
|
||||
+12
-31
@@ -1,22 +1,25 @@
|
||||
from SimPEG import Mesh, Utils, np, SolverLU
|
||||
|
||||
## 2D DC forward modeling example with Tensor and Curvilinear Meshes
|
||||
|
||||
def run(plotIt=True):
|
||||
|
||||
"""
|
||||
Mesh: Basic Forward 2D DC Resistivity
|
||||
=====================================
|
||||
|
||||
2D DC forward modeling example with Tensor and Curvilinear Meshes
|
||||
"""
|
||||
|
||||
# Step1: Generate Tensor and Curvilinear Mesh
|
||||
sz = [40,40]
|
||||
# Tensor Mesh
|
||||
tM = Mesh.TensorMesh(sz)
|
||||
# Curvilinear Mesh
|
||||
rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz,'rotate'))
|
||||
|
||||
# Step2: Direct Current (DC) operator
|
||||
def DCfun(mesh, pts):
|
||||
D = mesh.faceDiv
|
||||
G = D.T
|
||||
sigma = 1e-2*np.ones(mesh.nC)
|
||||
Msigi = mesh.getFaceInnerProduct(1./sigma)
|
||||
MsigI = Utils.sdInv(Msigi)
|
||||
A = D*MsigI*G
|
||||
MsigI = mesh.getFaceInnerProduct(sigma, invProp=True, invMat=True)
|
||||
A = -D*MsigI*D.T
|
||||
A[-1,-1] /= mesh.vol[-1] # Remove null space
|
||||
rhs = np.zeros(mesh.nC)
|
||||
txind = Utils.meshutils.closestPoints(mesh, pts)
|
||||
@@ -37,39 +40,17 @@ def run(plotIt=True):
|
||||
if not plotIt: return
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib
|
||||
from matplotlib.mlab import griddata
|
||||
|
||||
#Step4: Making Figure
|
||||
fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2))
|
||||
label = ["(a)", "(b)"]
|
||||
opts = {}
|
||||
vmin, vmax = phitM.min(), phitM.max()
|
||||
dat = tM.plotImage(phitM, ax=axes[0], clim=(vmin, vmax), grid=True)
|
||||
|
||||
#TODO: At the moment Curvilinear Mesh do not have plotimage
|
||||
|
||||
Xi = tM.gridCC[:,0].reshape(sz[0], sz[1], order='F')
|
||||
Yi = tM.gridCC[:,1].reshape(sz[0], sz[1], order='F')
|
||||
PHIrM = griddata(rM.gridCC[:,0], rM.gridCC[:,1], phirM, Xi, Yi, interp='linear')
|
||||
axes[1].contourf(Xi, Yi, PHIrM, 100, vmin=vmin, vmax=vmax)
|
||||
|
||||
dat = rM.plotImage(phirM, ax=axes[1], clim=(vmin, vmax), grid=True)
|
||||
cb = plt.colorbar(dat[0], ax=axes[0]); cb.set_label("Voltage (V)")
|
||||
cb = plt.colorbar(dat[0], ax=axes[1]); cb.set_label("Voltage (V)")
|
||||
|
||||
tM.plotGrid(ax=axes[0], **opts)
|
||||
axes[0].set_title('TensorMesh')
|
||||
rM.plotGrid(ax=axes[1], **opts)
|
||||
axes[1].set_title('CurvilinearMesh')
|
||||
for i in range(2):
|
||||
axes[i].set_xlim(0.025, 0.975)
|
||||
axes[i].set_ylim(0.025, 0.975)
|
||||
axes[i].text(0., 1.0, label[i], fontsize=20)
|
||||
if i==0:
|
||||
axes[i].set_ylabel("y")
|
||||
else:
|
||||
axes[i].set_ylabel(" ")
|
||||
axes[i].set_xlabel("x")
|
||||
plt.show()
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
from SimPEG import *
|
||||
from SimPEG.Utils import surface2ind_topo
|
||||
|
||||
|
||||
def run(plotIt=False, nx = 5, ny = 5):
|
||||
"""
|
||||
Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below
|
||||
a topographic surface.
|
||||
|
||||
"""
|
||||
|
||||
mesh = Mesh.TensorMesh([nx,ny], x0='CC') # 2D mesh
|
||||
xtopo = np.linspace(mesh.gridN[:,0].min(), mesh.gridN[:,0].max())
|
||||
topo = 0.4*np.sin(xtopo*5) # define a topographic surface
|
||||
|
||||
Topo = np.hstack([Utils.mkvc(xtopo,2),Utils.mkvc(topo,2)]) #make it an array
|
||||
|
||||
indcc = surface2ind_topo(mesh, Topo,'CC')
|
||||
|
||||
if plotIt:
|
||||
from matplotlib.pylab import plt
|
||||
from scipy.interpolate import interp1d
|
||||
fig, ax = plt.subplots(1,1,figsize=(6,6))
|
||||
mesh.plotGrid(ax=ax, nodes=True, centers=True)
|
||||
ax.plot(xtopo,topo,'k',linewidth=1)
|
||||
# ax.plot(mesh.vectorNx, interp1d(xtopo,topo)(mesh.vectorNx),'--k',linewidth=3)
|
||||
ax.plot(mesh.vectorCCx, interp1d(xtopo,topo)(mesh.vectorCCx),'--k',linewidth=3)
|
||||
|
||||
|
||||
aveN2CC = Utils.sdiag(mesh.aveN2CC.T.sum(1))*mesh.aveN2CC.T
|
||||
a = aveN2CC * indcc
|
||||
a[a > 0] = 1.
|
||||
a[a < 0.25] = np.nan
|
||||
a = a.reshape(mesh.vnN, order='F')
|
||||
masked_array = np.ma.array(a, mask=np.isnan(a))
|
||||
ax.pcolor(mesh.vectorNx,mesh.vectorNy,masked_array.T, cmap = plt.cm.gray,alpha=0.2)
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run(plotIt=True)
|
||||
+17
-13
@@ -1,25 +1,29 @@
|
||||
# Run this file to add imports.
|
||||
|
||||
##### AUTOIMPORTS #####
|
||||
import DC_Analytic_Dipole
|
||||
import DC_Forward_PseudoSection
|
||||
import EM_FDEM_1D_Inversion
|
||||
import EM_FDEM_Analytic_MagDipoleWholespace
|
||||
import EM_TDEM_1D_Inversion
|
||||
import FLOW_Richards_1D_Celia1990
|
||||
import Forward_BasicDirectCurrent
|
||||
import Inversion_Linear
|
||||
import Mesh_Basic_PlotImage
|
||||
import Mesh_Basic_Types
|
||||
import Mesh_Operators_CahnHilliard
|
||||
import Mesh_QuadTree_Creation
|
||||
import EM_TDEM_1D_Inversion
|
||||
import Mesh_QuadTree_FaceDiv
|
||||
import Mesh_QuadTree_HangingNodes
|
||||
import Mesh_Tensor_Creation
|
||||
import MT_1D_ForwardAndInversion
|
||||
import FLOW_Richards_1D_Celia1990
|
||||
import DC_Forward_PseudoSection
|
||||
import Mesh_Operators_CahnHilliard
|
||||
import Mesh_Basic_Types
|
||||
import Inversion_IRLS
|
||||
import Inversion_Linear
|
||||
import EM_Schenkel_Morrison_Casing
|
||||
import MT_3D_Foward
|
||||
import Mesh_Basic_ForwardDC
|
||||
import MT_1D_ForwardAndInversion
|
||||
import Utils_surface2ind_topo
|
||||
import MT_1D_analytic_nlayer_Earth
|
||||
import EM_FDEM_Analytic_MagDipoleWholespace
|
||||
import Mesh_Basic_PlotImage
|
||||
import DC_Analytic_Dipole
|
||||
import Mesh_QuadTree_HangingNodes
|
||||
|
||||
__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"]
|
||||
__examples__ = ["EM_FDEM_1D_Inversion", "Mesh_QuadTree_Creation", "EM_TDEM_1D_Inversion", "Mesh_QuadTree_FaceDiv", "Mesh_Tensor_Creation", "FLOW_Richards_1D_Celia1990", "DC_Forward_PseudoSection", "Mesh_Operators_CahnHilliard", "Mesh_Basic_Types", "Inversion_IRLS", "Inversion_Linear", "EM_Schenkel_Morrison_Casing", "MT_3D_Foward", "Mesh_Basic_ForwardDC", "MT_1D_ForwardAndInversion", "Utils_surface2ind_topo", "MT_1D_analytic_nlayer_Earth", "EM_FDEM_Analytic_MagDipoleWholespace", "Mesh_Basic_PlotImage", "DC_Analytic_Dipole", "Mesh_QuadTree_HangingNodes"]
|
||||
|
||||
##### AUTOIMPORTS #####
|
||||
|
||||
|
||||
@@ -45,19 +45,19 @@ class RichardsSurvey(Survey.BaseSurvey):
|
||||
|
||||
@Utils.count
|
||||
@Utils.requires('prob')
|
||||
def dpred(self, m, u=None):
|
||||
def dpred(self, m, f=None):
|
||||
"""
|
||||
Create the projected data from a model.
|
||||
The field, u, (if provided) will be used for the predicted data
|
||||
The field, f, (if provided) will be used for the predicted data
|
||||
instead of recalculating the fields (which may be expensive!).
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = P(u(m), m)
|
||||
d_\\text{pred} = P(f(m), m)
|
||||
|
||||
Where P is a projection of the fields onto the data space.
|
||||
"""
|
||||
if u is None: u = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(u, m))
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(f, m))
|
||||
|
||||
@Utils.requires('prob')
|
||||
def eval(self, U, m):
|
||||
@@ -233,16 +233,16 @@ class RichardsProblem(Problem.BaseTimeProblem):
|
||||
return r, J
|
||||
|
||||
@Utils.timeIt
|
||||
def Jfull(self, m, u=None):
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
def Jfull(self, m, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
nn = len(u)-1
|
||||
nn = len(f)-1
|
||||
Asubs, Adiags, Bs = range(nn), range(nn), range(nn)
|
||||
for ii in range(nn):
|
||||
dt = self.timeSteps[ii]
|
||||
bc = self.getBoundaryConditions(ii, u[ii])
|
||||
Asubs[ii], Adiags[ii], Bs[ii] = self.diagsJacobian(m, u[ii], u[ii+1], dt, bc)
|
||||
bc = self.getBoundaryConditions(ii, f[ii])
|
||||
Asubs[ii], Adiags[ii], Bs[ii] = self.diagsJacobian(m, f[ii], f[ii+1], dt, bc)
|
||||
Ad = sp.block_diag(Adiags)
|
||||
zRight = Utils.spzeros((len(Asubs)-1)*Asubs[0].shape[0],Adiags[0].shape[1])
|
||||
zTop = Utils.spzeros(Adiags[0].shape[0], len(Adiags)*Adiags[0].shape[1])
|
||||
@@ -251,7 +251,7 @@ class RichardsProblem(Problem.BaseTimeProblem):
|
||||
B = np.array(sp.vstack(Bs).todense())
|
||||
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
P = self.survey.evalDeriv(u, m)
|
||||
P = self.survey.evalDeriv(f, m)
|
||||
AinvB = Ainv * B
|
||||
z = np.zeros((self.mesh.nC, B.shape[1]))
|
||||
zAinvB = np.vstack((z, AinvB))
|
||||
@@ -259,41 +259,41 @@ class RichardsProblem(Problem.BaseTimeProblem):
|
||||
return J
|
||||
|
||||
@Utils.timeIt
|
||||
def Jvec(self, m, v, u=None):
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
def Jvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
JvC = range(len(u)-1) # Cell to hold each row of the long vector.
|
||||
JvC = range(len(f)-1) # Cell to hold each row of the long vector.
|
||||
|
||||
# This is done via forward substitution.
|
||||
bc = self.getBoundaryConditions(0, u[0])
|
||||
temp, Adiag, B = self.diagsJacobian(m, u[0], u[1], self.timeSteps[0], bc)
|
||||
bc = self.getBoundaryConditions(0, f[0])
|
||||
temp, Adiag, B = self.diagsJacobian(m, f[0], f[1], self.timeSteps[0], bc)
|
||||
Adiaginv = self.Solver(Adiag, **self.solverOpts)
|
||||
JvC[0] = Adiaginv * (B*v)
|
||||
|
||||
for ii in range(1,len(u)-1):
|
||||
bc = self.getBoundaryConditions(ii, u[ii])
|
||||
Asub, Adiag, B = self.diagsJacobian(m, u[ii], u[ii+1], self.timeSteps[ii], bc)
|
||||
for ii in range(1,len(f)-1):
|
||||
bc = self.getBoundaryConditions(ii, f[ii])
|
||||
Asub, Adiag, B = self.diagsJacobian(m, f[ii], f[ii+1], self.timeSteps[ii], bc)
|
||||
Adiaginv = self.Solver(Adiag, **self.solverOpts)
|
||||
JvC[ii] = Adiaginv * (B*v - Asub*JvC[ii-1])
|
||||
|
||||
P = self.survey.evalDeriv(u, m)
|
||||
P = self.survey.evalDeriv(f, m)
|
||||
return P * np.concatenate([np.zeros(self.mesh.nC)] + JvC)
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec(self, m, v, u=None):
|
||||
if u is None:
|
||||
u = self.field(m)
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.field(m)
|
||||
|
||||
P = self.survey.evalDeriv(u, m)
|
||||
P = self.survey.evalDeriv(f, m)
|
||||
PTv = P.T*v
|
||||
|
||||
# This is done via backward substitution.
|
||||
minus = 0
|
||||
BJtv = 0
|
||||
for ii in range(len(u)-1,0,-1):
|
||||
bc = self.getBoundaryConditions(ii-1, u[ii-1])
|
||||
Asub, Adiag, B = self.diagsJacobian(m, u[ii-1], u[ii], self.timeSteps[ii-1], bc)
|
||||
for ii in range(len(f)-1,0,-1):
|
||||
bc = self.getBoundaryConditions(ii-1, f[ii-1])
|
||||
Asub, Adiag, B = self.diagsJacobian(m, f[ii-1], f[ii], self.timeSteps[ii-1], bc)
|
||||
#select the correct part of v
|
||||
vpart = range((ii)*Adiag.shape[0], (ii+1)*Adiag.shape[0])
|
||||
AdiaginvT = self.Solver(Adiag.T, **self.solverOpts)
|
||||
|
||||
+13
-13
@@ -82,23 +82,23 @@ class BaseInvProblem(object):
|
||||
self._warmstart = value
|
||||
|
||||
def getFields(self, m, store=False, deleteWarmstart=True):
|
||||
u = None
|
||||
f = None
|
||||
|
||||
for mtest, u_ofmtest in self.warmstart:
|
||||
if m is mtest:
|
||||
u = u_ofmtest
|
||||
f = u_ofmtest
|
||||
if self.debug: print 'InvProb is Warm Starting!'
|
||||
break
|
||||
|
||||
if u is None:
|
||||
u = self.prob.fields(m)
|
||||
if f is None:
|
||||
f = self.prob.fields(m)
|
||||
|
||||
if deleteWarmstart:
|
||||
self.warmstart = []
|
||||
if store:
|
||||
self.warmstart += [(m,u)]
|
||||
self.warmstart += [(m,f)]
|
||||
|
||||
return u
|
||||
return f
|
||||
|
||||
@Utils.timeIt
|
||||
def evalFunction(self, m, return_g=True, return_H=True):
|
||||
@@ -109,21 +109,21 @@ class BaseInvProblem(object):
|
||||
gc.collect()
|
||||
|
||||
# Store fields if doing a line-search
|
||||
u = self.getFields(m, store=(return_g==False and return_H==False))
|
||||
f = self.getFields(m, store=(return_g==False and return_H==False))
|
||||
|
||||
phi_d = self.dmisfit.eval(m, u=u)
|
||||
phi_d = self.dmisfit.eval(m, f=f)
|
||||
phi_m = self.reg.eval(m)
|
||||
|
||||
self.dpred = self.survey.dpred(m, u=u) # This is a cheap matrix vector calculation.
|
||||
self.dpred = self.survey.dpred(m, f=f) # This is a cheap matrix vector calculation.
|
||||
|
||||
self.phi_d, self.phi_d_last = phi_d, self.phi_d
|
||||
self.phi_m, self.phi_m_last = phi_m, self.phi_m
|
||||
|
||||
f = phi_d + self.beta * phi_m
|
||||
phi = phi_d + self.beta * phi_m
|
||||
|
||||
out = (f,)
|
||||
out = (phi,)
|
||||
if return_g:
|
||||
phi_dDeriv = self.dmisfit.evalDeriv(m, u=u)
|
||||
phi_dDeriv = self.dmisfit.evalDeriv(m, f=f)
|
||||
phi_mDeriv = self.reg.evalDeriv(m)
|
||||
|
||||
g = phi_dDeriv + self.beta * phi_mDeriv
|
||||
@@ -131,7 +131,7 @@ class BaseInvProblem(object):
|
||||
|
||||
if return_H:
|
||||
def H_fun(v):
|
||||
phi_d2Deriv = self.dmisfit.eval2Deriv(m, v, u=u)
|
||||
phi_d2Deriv = self.dmisfit.eval2Deriv(m, v, f=f)
|
||||
phi_m2Deriv = self.reg.eval2Deriv(m, v=v)
|
||||
|
||||
return phi_d2Deriv + self.beta * phi_m2Deriv
|
||||
|
||||
+3
-1
@@ -33,7 +33,9 @@ class BaseInversion(object):
|
||||
self._directiveList = value
|
||||
self._directiveList.inversion = self
|
||||
|
||||
def __init__(self, invProb, directiveList=[], **kwargs):
|
||||
def __init__(self, invProb, directiveList=None, **kwargs):
|
||||
if directiveList is None:
|
||||
directiveList = []
|
||||
self.directiveList = directiveList
|
||||
Utils.setKwargs(self, **kwargs)
|
||||
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
from SimPEG import SolverLU as SimpegSolver, PropMaps, Utils, mkvc, sp, np
|
||||
from SimPEG.EM.FDEM.FDEM import BaseFDEMProblem
|
||||
from SurveyMT import Survey, Data
|
||||
from FieldsMT import BaseMTFields
|
||||
|
||||
|
||||
class BaseMTProblem(BaseFDEMProblem):
|
||||
"""
|
||||
Base class for all Natural source problems.
|
||||
"""
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
Utils.setKwargs(self, **kwargs)
|
||||
# Set the default pairs of the problem
|
||||
surveyPair = Survey
|
||||
dataPair = Data
|
||||
fieldsPair = BaseMTFields
|
||||
|
||||
# Set the solver
|
||||
Solver = SimpegSolver
|
||||
solverOpts = {}
|
||||
|
||||
verbose = False
|
||||
# Notes:
|
||||
# Use the forward and devs from BaseFDEMProblem
|
||||
# Might need to add more stuff here.
|
||||
|
||||
## NEED to clean up the Jvec and Jtvec to use Zero and Identities for None components.
|
||||
def Jvec(self, m, v, u=None):
|
||||
"""
|
||||
Function to calculate the data sensitivities dD/dm times a vector.
|
||||
|
||||
:param numpy.ndarray m (nC, 1) - conductive model
|
||||
:param numpy.ndarray v (nC, 1) - random vector
|
||||
:param MTfields object (optional) - MT fields object, if not given it is calculated
|
||||
:rtype: MTdata object
|
||||
:return: Data sensitivities wrt m
|
||||
"""
|
||||
|
||||
# Calculate the fields
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
# Set current model
|
||||
self.curModel = m
|
||||
# Initiate the Jv object
|
||||
Jv = self.dataPair(self.survey)
|
||||
|
||||
# Loop all the frequenies
|
||||
for freq in self.survey.freqs:
|
||||
dA_du = self.getA(freq) #
|
||||
|
||||
dA_duI = self.Solver(dA_du, **self.solverOpts)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
# We need fDeriv_m = df/du*du/dm + df/dm
|
||||
# Construct du/dm, it requires a solve
|
||||
# NOTE: need to account for the 2 polarizations in the derivatives.
|
||||
u_src = u[src,:]
|
||||
# dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by dA_duI. The 2 columns are each of the polarizations.
|
||||
dA_dm = self.getADeriv_m(freq, u_src, v) # Size: nE,2 (u_px,u_py) in the columns.
|
||||
dRHS_dm = self.getRHSDeriv_m(freq, v) # Size: nE,2 (u_px,u_py) in the columns.
|
||||
if dRHS_dm is None:
|
||||
du_dm = dA_duI * ( -dA_dm )
|
||||
else:
|
||||
du_dm = dA_duI * ( -dA_dm + dRHS_dm )
|
||||
# Calculate the projection derivatives
|
||||
for rx in src.rxList:
|
||||
# Get the projection derivative
|
||||
# v should be of size 2*nE (for 2 polarizations)
|
||||
PDeriv_u = lambda t: rx.evalDeriv(src, self.mesh, u, t) # wrt u, we don't have have PDeriv wrt m
|
||||
Jv[src, rx] = PDeriv_u(mkvc(du_dm))
|
||||
dA_duI.clean()
|
||||
# Return the vectorized sensitivities
|
||||
return mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
"""
|
||||
Function to calculate the transpose of the data sensitivities (dD/dm)^T times a vector.
|
||||
|
||||
:param numpy.ndarray m (nC, 1) - conductive model
|
||||
:param numpy.ndarray v (nD, 1) - vector
|
||||
:param MTfields object u (optional) - MT fields object, if not given it is calculated
|
||||
:rtype: MTdata object
|
||||
:return: Data sensitivities wrt m
|
||||
"""
|
||||
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv = np.zeros(m.size)
|
||||
|
||||
for freq in self.survey.freqs:
|
||||
AT = self.getA(freq).T
|
||||
|
||||
ATinv = self.Solver(AT, **self.solverOpts)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
ftype = self._fieldType + 'Solution'
|
||||
u_src = u[src, :]
|
||||
|
||||
for rx in src.rxList:
|
||||
# Get the adjoint evalDeriv
|
||||
# PTv needs to be nE,
|
||||
PTv = rx.evalDeriv(src, self.mesh, u, mkvc(v[src, rx],2), adjoint=True) # wrt u, need possibility wrt m
|
||||
# Get the
|
||||
dA_duIT = ATinv * PTv
|
||||
dA_dmT = self.getADeriv_m(freq, u_src, mkvc(dA_duIT), adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv_m(freq, mkvc(dA_duIT), adjoint=True)
|
||||
# Make du_dmT
|
||||
if dRHS_dmT is None:
|
||||
du_dmT = -dA_dmT
|
||||
else:
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
# Select the correct component
|
||||
# du_dmT needs to be of size nC,
|
||||
real_or_imag = rx.projComp
|
||||
if real_or_imag == 'real':
|
||||
Jtv += du_dmT.real
|
||||
elif real_or_imag == 'imag':
|
||||
Jtv += -du_dmT.real
|
||||
else:
|
||||
raise Exception('Must be real or imag')
|
||||
# Clean the factorization, clear memory.
|
||||
ATinv.clean()
|
||||
return Jtv
|
||||
@@ -1,291 +0,0 @@
|
||||
from SimPEG.EM.Utils import omega
|
||||
from SimPEG import mkvc
|
||||
from scipy.constants import mu_0
|
||||
from SimPEG.MT.BaseMT import BaseMTProblem
|
||||
from SimPEG.MT.SurveyMT import Survey, Data
|
||||
from SimPEG.MT.FieldsMT import Fields1D_e
|
||||
from SimPEG.MT.Utils.MT1Danalytic import getEHfields
|
||||
import numpy as np
|
||||
import multiprocessing, sys, time
|
||||
|
||||
|
||||
class eForm_psField(BaseMTProblem):
|
||||
"""
|
||||
A MT problem soving a e formulation and primary/secondary fields decomposion.
|
||||
|
||||
By eliminating the magnetic flux density using
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} \\right)
|
||||
|
||||
|
||||
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
|
||||
|
||||
.. math ::
|
||||
\\left(\mathbf{C}^T \mathbf{M^e_{\mu^{-1}}} \mathbf{C} + i \omega \mathbf{M^f_\sigma}] \mathbf{e}_{s} =& i \omega \mathbf{M^f_{\delta \sigma}} \mathbf{e}_{p}
|
||||
which we solve for \\\(\\\mathbf{e_s}\\\). The total field \\\mathbf{e}\\ = \\\mathbf{e_p}\\ + \\\mathbf{e_s}\\.
|
||||
|
||||
The primary field is estimated from a background model (commonly half space ).
|
||||
|
||||
|
||||
"""
|
||||
# From FDEMproblem: Used to project the fields. Currently not used for MTproblem.
|
||||
_fieldType = 'e_1d'
|
||||
_eqLocs = 'EF'
|
||||
_sigmaPrimary = None
|
||||
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseMTProblem.__init__(self, mesh, **kwargs)
|
||||
self.fieldsPair = Fields1D_e
|
||||
# self._sigmaPrimary = sigmaPrimary
|
||||
@property
|
||||
def MeMui(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MeMui', None) is None:
|
||||
self._MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
|
||||
return self._MeMui
|
||||
|
||||
@property
|
||||
def MfSigma(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MfSigma', None) is None:
|
||||
self._MfSigma = self.mesh.getFaceInnerProduct(self.curModel.sigma)
|
||||
return self._MfSigma
|
||||
|
||||
@property
|
||||
def sigmaPrimary(self):
|
||||
"""
|
||||
A background model, use for the calculation of the primary fields.
|
||||
|
||||
"""
|
||||
return self._sigmaPrimary
|
||||
|
||||
@sigmaPrimary.setter
|
||||
def sigmaPrimary(self, val):
|
||||
# Note: TODO add logic for val, make sure it is the correct size.
|
||||
self._sigmaPrimary = val
|
||||
|
||||
def getA(self, freq):
|
||||
"""
|
||||
Function to get the A matrix.
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: A
|
||||
"""
|
||||
|
||||
# Note: need to use the code above since in the 1D problem I want
|
||||
# e to live on Faces(nodes) and h on edges(cells). Might need to rethink this
|
||||
# Possible that _fieldType and _eqLocs can fix this
|
||||
MeMui = self.MeMui
|
||||
MfSigma = self.MfSigma
|
||||
C = self.mesh.nodalGrad
|
||||
# Make A
|
||||
A = C.T*MeMui*C + 1j*omega(freq)*MfSigma
|
||||
# Either return full or only the inner part of A
|
||||
return A
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
"""
|
||||
The derivative of A wrt sigma
|
||||
"""
|
||||
|
||||
dsig_dm = self.curModel.sigmaDeriv
|
||||
MeMui = self.MeMui
|
||||
#
|
||||
u_src = u['e_1dSolution']
|
||||
dMfSigma_dm = self.mesh.getFaceInnerProductDeriv(self.curModel.sigma)(u_src) * self.curModel.sigmaDeriv
|
||||
if adjoint:
|
||||
return 1j * omega(freq) * ( dMfSigma_dm.T * v )
|
||||
# Note: output has to be nN/nF, not nC/nE.
|
||||
# v should be nC
|
||||
return 1j * omega(freq) * ( dMfSigma_dm * v )
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Function to return the right hand side for the system.
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray (nF, 1), numpy.ndarray (nF, 1)
|
||||
:return: RHS for 1 polarizations, primary fields
|
||||
"""
|
||||
|
||||
# Get sources for the frequncy(polarizations)
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
S_e = Src.S_e(self)
|
||||
return -1j * omega(freq) * S_e
|
||||
|
||||
def getRHSDeriv_m(self, freq, v, adjoint=False):
|
||||
"""
|
||||
The derivative of the RHS wrt sigma
|
||||
"""
|
||||
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
S_eDeriv = Src.S_eDeriv_m(self, v, adjoint)
|
||||
return -1j * omega(freq) * S_eDeriv
|
||||
|
||||
def fields(self, m):
|
||||
'''
|
||||
Function to calculate all the fields for the model m.
|
||||
|
||||
:param np.ndarray (nC,) m: Conductivity model
|
||||
'''
|
||||
# Set the current model
|
||||
self.curModel = m
|
||||
|
||||
F = Fields1D_e(self.mesh, self.survey)
|
||||
for freq in self.survey.freqs:
|
||||
if self.verbose:
|
||||
startTime = time.time()
|
||||
print 'Starting work for {:.3e}'.format(freq)
|
||||
sys.stdout.flush()
|
||||
A = self.getA(freq)
|
||||
rhs = self.getRHS(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
e_s = Ainv * rhs
|
||||
|
||||
# Store the fields
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
# NOTE: only store the e_solution(secondary), all other components calculated in the fields object
|
||||
F[Src, 'e_1dSolution'] = e_s[:,-1] # Only storing the yx polarization as 1d
|
||||
|
||||
# Note curl e = -iwb so b = -curl e /iw
|
||||
# b = -( self.mesh.nodalGrad * e )/( 1j*omega(freq) )
|
||||
# F[Src, 'b_1d'] = b[:,1]
|
||||
if self.verbose:
|
||||
print 'Ran for {:f} seconds'.format(time.time()-startTime)
|
||||
sys.stdout.flush()
|
||||
return F
|
||||
|
||||
# Note this is not fully functional.
|
||||
# Missing:
|
||||
# Fields class corresponding to the fields
|
||||
# Update Jvec and Jtvec to include all the derivatives components
|
||||
# Other things ...
|
||||
class eForm_TotalField(BaseMTProblem):
|
||||
"""
|
||||
A MT problem solving a e formulation and a Total bondary domain decompostion.
|
||||
|
||||
Solves the equation:
|
||||
|
||||
Math:
|
||||
|
||||
|
||||
"""
|
||||
|
||||
# From FDEMproblem: Used to project the fields. Currently not used for MTproblem.
|
||||
_fieldType = 'e'
|
||||
_eqLocs = 'EF'
|
||||
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseMTProblem.__init__(self, mesh, **kwargs)
|
||||
@property
|
||||
def MeMui(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MeMui', None) is None:
|
||||
self._MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
|
||||
return self._MeMui
|
||||
|
||||
@property
|
||||
def MfSigma(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MfSigma', None) is None:
|
||||
self._MfSigma = self.mesh.getFaceInnerProduct(self.curModel.sigma)
|
||||
return self._MfSigma
|
||||
|
||||
def getA(self, freq, full=False):
|
||||
"""
|
||||
Function to get the A matrix.
|
||||
|
||||
:param float freq: Frequency
|
||||
:param logic full: Return full A or the inner part
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: A
|
||||
"""
|
||||
|
||||
MeMui = self.MeMui
|
||||
MfSigma = self.MfSigma
|
||||
# Note: need to use the code above since in the 1D problem I want
|
||||
# e to live on Faces(nodes) and h on edges(cells). Might need to rethink this
|
||||
# Possible that _fieldType and _eqLocs can fix this
|
||||
# MeMui = self.MfMui
|
||||
# MfSigma = self.MfSigma
|
||||
C = self.mesh.nodalGrad
|
||||
# Make A
|
||||
A = C.T*MeMui*C + 1j*omega(freq)*MfSigma
|
||||
# Either return full or only the inner part of A
|
||||
if full:
|
||||
return A
|
||||
else:
|
||||
return A[1:-1,1:-1]
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
raise NotImplementedError('getADeriv is not implemented')
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Function to return the right hand side for the system.
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray (nE, 2), numpy.ndarray (nE, 2)
|
||||
:return: RHS for both polarizations, primary fields
|
||||
"""
|
||||
# Get sources for the frequency
|
||||
# NOTE: Need to use the source information, doesn't really apply in 1D
|
||||
src = self.survey.getSrcByFreq(freq)
|
||||
# Get the full A
|
||||
A = self.getA(freq,full=True)
|
||||
# Define the outer part of the solution matrix
|
||||
Aio = A[1:-1,[0,-1]]
|
||||
Ed, Eu, Hd, Hu = getEHfields(self.mesh,self.curModel.sigma,freq,self.mesh.vectorNx)
|
||||
Etot = (Ed + Eu)
|
||||
sourceAmp = 1.0
|
||||
Etot = ((Etot/Etot[-1])*sourceAmp) # Scale the fields to be equal to sourceAmp at the top
|
||||
## Note: The analytic solution is derived with e^iwt
|
||||
eBC = np.r_[Etot[0],Etot[-1]]
|
||||
# The right hand side
|
||||
|
||||
return -Aio*eBC, eBC
|
||||
|
||||
def getRHSderiv_m(self, freq, backSigma, u, v, adjoint=False):
|
||||
raise NotImplementedError('getRHSDeriv not implemented yet')
|
||||
return None
|
||||
|
||||
def fields(self, m):
|
||||
'''
|
||||
Function to calculate all the fields for the model m.
|
||||
|
||||
:param np.ndarray (nC,) m: Conductivity model
|
||||
:param np.ndarray (nC,) m_back: Background conductivity model
|
||||
'''
|
||||
self.curModel = m
|
||||
# RHS, CalcFields = self.getRHS(freq,m_back), self.calcFields
|
||||
|
||||
F = Fields1D_e(self.mesh, self.survey)
|
||||
for freq in self.survey.freqs:
|
||||
if self.verbose:
|
||||
startTime = time.time()
|
||||
print 'Starting work for {:.3e}'.format(freq)
|
||||
sys.stdout.flush()
|
||||
A = self.getA(freq)
|
||||
rhs, e_o = self.getRHS(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
e_i = Ainv * rhs
|
||||
e = mkvc(np.r_[e_o[0], e_i, e_o[1]],2)
|
||||
# Store the fields
|
||||
Src = self.survey.getSrcByFreq(freq)
|
||||
# NOTE: only store e fields
|
||||
F[Src, 'e_1dSolution'] = e[:,0]
|
||||
if self.verbose:
|
||||
print 'Ran for {:f} seconds'.format(time.time()-startTime)
|
||||
sys.stdout.flush()
|
||||
return F
|
||||
@@ -1 +0,0 @@
|
||||
from Probs import eForm_TotalField, eForm_psField
|
||||
@@ -1 +0,0 @@
|
||||
pass
|
||||
@@ -1,138 +0,0 @@
|
||||
from SimPEG import Survey, Problem, Utils, Models, np, sp, mkvc, SolverLU as SimpegSolver
|
||||
from SimPEG.EM.Utils import omega
|
||||
from scipy.constants import mu_0
|
||||
from SimPEG.MT.BaseMT import BaseMTProblem
|
||||
from SimPEG.MT.SurveyMT import Survey, Data
|
||||
from SimPEG.MT.FieldsMT import Fields3D_e
|
||||
import multiprocessing, sys, time
|
||||
|
||||
|
||||
|
||||
class eForm_ps(BaseMTProblem):
|
||||
"""
|
||||
A MT problem solving a e formulation and a primary/secondary fields decompostion.
|
||||
|
||||
By eliminating the magnetic flux density using
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} \\right)
|
||||
|
||||
|
||||
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
|
||||
|
||||
.. math ::
|
||||
\\left(\mathbf{C}^T \mathbf{M^f_{\mu^{-1}}} \mathbf{C} + i \omega \mathbf{M^e_\sigma}] \mathbf{e}_{s} =& i \omega \mathbf{M^e_{\delta \sigma}} \mathbf{e}_{p}
|
||||
which we solve for \\\(\\\mathbf{e_s}\\\). The total field \\\mathbf{e}\\ = \\\mathbf{e_p}\\ + \\\mathbf{e_s}\\.
|
||||
|
||||
The primary field is estimated from a background model (commonly as a 1D model).
|
||||
|
||||
"""
|
||||
|
||||
# From FDEMproblem: Used to project the fields. Currently not used for MTproblem.
|
||||
_fieldType = 'e'
|
||||
_eqLocs = 'FE'
|
||||
fieldsPair = Fields3D_e
|
||||
_sigmaPrimary = None
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseMTProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
@property
|
||||
def sigmaPrimary(self):
|
||||
"""
|
||||
A background model, use for the calculation of the primary fields.
|
||||
|
||||
"""
|
||||
return self._sigmaPrimary
|
||||
@sigmaPrimary.setter
|
||||
def sigmaPrimary(self, val):
|
||||
# Note: TODO add logic for val, make sure it is the correct size.
|
||||
self._sigmaPrimary = val
|
||||
|
||||
def getA(self, freq):
|
||||
"""
|
||||
Function to get the A system.
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: A
|
||||
"""
|
||||
Mmui = self.MfMui
|
||||
Msig = self.MeSigma
|
||||
C = self.mesh.edgeCurl
|
||||
|
||||
return C.T*Mmui*C + 1j*omega(freq)*Msig
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
"""
|
||||
Calculate the derivative of A wrt m.
|
||||
|
||||
"""
|
||||
|
||||
# This considers both polarizations and returns a nE,2 matrix for each polarization
|
||||
if adjoint:
|
||||
dMe_dsigV = sp.hstack(( self.MeSigmaDeriv( u['e_pxSolution'] ).T, self.MeSigmaDeriv(u['e_pySolution'] ).T ))*v
|
||||
else:
|
||||
# Need a nE,2 matrix to be returned
|
||||
dMe_dsigV = np.hstack(( mkvc(self.MeSigmaDeriv( u['e_pxSolution'] )*v,2), mkvc( self.MeSigmaDeriv(u['e_pySolution'] )*v,2) ))
|
||||
return 1j * omega(freq) * dMe_dsigV
|
||||
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Function to return the right hand side for the system.
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray (nE, 2), numpy.ndarray (nE, 2)
|
||||
:return: RHS for both polarizations, primary fields
|
||||
"""
|
||||
|
||||
# Get sources for the frequncy(polarizations)
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
S_e = Src.S_e(self)
|
||||
return -1j * omega(freq) * S_e
|
||||
|
||||
def getRHSDeriv_m(self, freq, v, adjoint=False):
|
||||
"""
|
||||
The derivative of the RHS with respect to sigma
|
||||
"""
|
||||
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
S_eDeriv = Src.S_eDeriv_m(self, v, adjoint)
|
||||
return -1j * omega(freq) * S_eDeriv
|
||||
|
||||
def fields(self, m):
|
||||
'''
|
||||
Function to calculate all the fields for the model m.
|
||||
|
||||
:param np.ndarray (nC,) m: Conductivity model
|
||||
'''
|
||||
# Set the current model
|
||||
self.curModel = m
|
||||
|
||||
F = Fields3D_e(self.mesh, self.survey)
|
||||
for freq in self.survey.freqs:
|
||||
if self.verbose:
|
||||
startTime = time.time()
|
||||
print 'Starting work for {:.3e}'.format(freq)
|
||||
sys.stdout.flush()
|
||||
A = self.getA(freq)
|
||||
rhs = self.getRHS(freq)
|
||||
# Solve the system
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
e_s = Ainv * rhs
|
||||
|
||||
# Store the fields
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
# Store the fieldss
|
||||
F[Src, 'e_pxSolution'] = e_s[:,0]
|
||||
F[Src, 'e_pySolution'] = e_s[:,1]
|
||||
# Note curl e = -iwb so b = -curl/iw
|
||||
|
||||
if self.verbose:
|
||||
print 'Ran for {:f} seconds'.format(time.time()-startTime)
|
||||
sys.stdout.flush()
|
||||
Ainv.clean()
|
||||
return F
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
from Probs import eForm_ps
|
||||
@@ -1,4 +0,0 @@
|
||||
from MT1Dsolutions import * # Add the names of the functions
|
||||
from MT1Danalytic import *
|
||||
from dataUtils import *
|
||||
from ediFilesUtils import *
|
||||
@@ -1,46 +0,0 @@
|
||||
import SimPEG as simpeg, numpy as np
|
||||
|
||||
def homo1DModelSource(mesh,freq,m_back):
|
||||
'''
|
||||
Function that calculates and return background fields for a 3D mesh and model.
|
||||
The calculuations use 1D field solution for a vertical slice throught model (south-western most column),
|
||||
which is assigned at the fields everywhere for the respective polarizations.2
|
||||
|
||||
:param Simpeg mesh object mesh: Holds information on the discretization
|
||||
:param float freq: The frequency to solve at
|
||||
:param np.array m_back: Background model of conductivity to base the calculations on.
|
||||
:rtype: numpy.ndarray (mesh.nE,2)
|
||||
:return: eBG_bp, E fields for the background model at both polarizations.
|
||||
|
||||
'''
|
||||
|
||||
# import
|
||||
from SimPEG.MT.Utils import get1DEfields
|
||||
# Get a 1d solution for a halfspace background
|
||||
mesh1d = simpeg.Mesh.TensorMesh([mesh.hz],np.array([mesh.x0[2]]))
|
||||
# Note: Everything is using e^iwt
|
||||
e0_1d = get1DEfields(mesh1d,mesh.r(m_back,'CC','CC','M')[0,0,:],freq)
|
||||
# Setup x (east) polarization (_x)
|
||||
ex_px = np.zeros(mesh.vnEx,dtype=complex)
|
||||
ey_px = np.zeros((mesh.nEy,1),dtype=complex)
|
||||
ez_px = np.zeros((mesh.nEz,1),dtype=complex)
|
||||
# Assign the source to ex_x
|
||||
for i in np.arange(mesh.vnEx[0]):
|
||||
for j in np.arange(mesh.vnEx[1]):
|
||||
ex_px[i,j,:] = -e0_1d
|
||||
eBG_px = np.vstack((simpeg.Utils.mkvc(ex_px,2),ey_px,ez_px))
|
||||
# Setup y (north) polarization (_py)
|
||||
ex_py = np.zeros((mesh.nEx,1), dtype='complex128')
|
||||
ey_py = np.zeros(mesh.vnEy, dtype='complex128')
|
||||
ez_py = np.zeros((mesh.nEz,1), dtype='complex128')
|
||||
# Assign the source to ey_py
|
||||
|
||||
for i in np.arange(mesh.vnEy[0]):
|
||||
for j in np.arange(mesh.vnEy[1]):
|
||||
ey_py[i,j,:] = e0_1d
|
||||
# ey_py[1:-1,1:-1,1:-1] = 0
|
||||
eBG_py = np.vstack((ex_py,simpeg.Utils.mkvc(ey_py,2),ez_py))
|
||||
|
||||
# Return the electric fields
|
||||
eBG_bp = np.hstack((eBG_px,eBG_py))
|
||||
return eBG_bp
|
||||
@@ -1,5 +0,0 @@
|
||||
import Utils
|
||||
from SurveyMT import Rx, Survey, Data
|
||||
from FieldsMT import Fields1D_e, Fields3D_e
|
||||
import Problem1D, Problem2D, Problem3D
|
||||
import SrcMT
|
||||
+26
-88
@@ -533,83 +533,6 @@ class ActiveCells(InjectActiveCells):
|
||||
FutureWarning)
|
||||
InjectActiveCells.__init__(self, mesh, indActive, valInactive, nC)
|
||||
|
||||
class InjectActiveCellsTopo(IdentityMap):
|
||||
"""
|
||||
Active model parameters. Extend for cells on topography to air cell (only works for tensor mesh)
|
||||
|
||||
"""
|
||||
|
||||
indActive = None #: Active Cells
|
||||
valInactive = None #: Values of inactive Cells
|
||||
nC = None #: Number of cells in the full model
|
||||
|
||||
def __init__(self, mesh, indActive, nC=None):
|
||||
self.mesh = mesh
|
||||
|
||||
self.nC = nC or mesh.nC
|
||||
|
||||
if indActive.dtype is not bool:
|
||||
z = np.zeros(self.nC,dtype=bool)
|
||||
z[indActive] = True
|
||||
indActive = z
|
||||
self.indActive = indActive
|
||||
|
||||
self.indInactive = np.logical_not(indActive)
|
||||
inds = np.nonzero(self.indActive)[0]
|
||||
self.P = sp.csr_matrix((np.ones(inds.size),(inds, range(inds.size))), shape=(self.nC, self.nP))
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
return (self.nC, self.nP)
|
||||
|
||||
@property
|
||||
def nP(self):
|
||||
"""Number of parameters in the model."""
|
||||
return self.indActive.sum()
|
||||
|
||||
def _transform(self, m):
|
||||
val_temp = np.zeros(self.mesh.nC)
|
||||
val_temp[self.indActive] = m
|
||||
valInactive = np.zeros(self.mesh.nC)
|
||||
#1D
|
||||
if self.mesh.dim == 1:
|
||||
z_temp = self.mesh.gridCC
|
||||
val_temp[~self.indActive] = val_temp[np.argmax(z_temp[self.indActive])]
|
||||
#2D
|
||||
elif self.mesh.dim == 2:
|
||||
act_temp = self.indActive.reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
|
||||
val_temp = val_temp.reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
|
||||
y_temp = self.mesh.gridCC[:,1].reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
|
||||
for i in range(self.mesh.nCx):
|
||||
act_tempx = act_temp[i,:] == 1
|
||||
val_temp[i,~act_tempx] = val_temp[i,np.argmax(y_temp[i,act_tempx])]
|
||||
valInactive[~self.indActive] = Utils.mkvc(val_temp)[~self.indActive]
|
||||
#3D
|
||||
elif self.mesh.dim == 3:
|
||||
act_temp = self.indActive.reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
|
||||
val_temp = val_temp.reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
|
||||
z_temp = self.mesh.gridCC[:,2].reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
|
||||
for i in range(self.mesh.nCx*self.mesh.nCy):
|
||||
act_tempxy = act_temp[i,:] == 1
|
||||
val_temp[i,~act_tempxy] = val_temp[i,np.argmax(z_temp[i,act_tempxy])]
|
||||
valInactive[~self.indActive] = Utils.mkvc(val_temp)[~self.indActive]
|
||||
|
||||
self.valInactive = valInactive
|
||||
|
||||
return self.P*m + self.valInactive
|
||||
|
||||
def inverse(self, D):
|
||||
return self.P.T*D
|
||||
|
||||
def deriv(self, m):
|
||||
return self.P
|
||||
|
||||
class ActiveCellsTopo(InjectActiveCellsTopo):
|
||||
def __init__(self, mesh, indActive, valInactive, nC=None):
|
||||
warnings.warn(
|
||||
"`ActiveCellsTopo` is deprecated and will be removed in future versions. Use `InjectActiveCellsTopo` instead",
|
||||
FutureWarning)
|
||||
InjectActiveCellsTopo.__init__(self, mesh, indActive, valInactive, nC)
|
||||
|
||||
class Weighting(IdentityMap):
|
||||
"""
|
||||
@@ -759,15 +682,29 @@ class PolyMap(IdentityMap):
|
||||
|
||||
m = [\sigma_1, \sigma_2, c]
|
||||
|
||||
Can take in an actInd vector to account for topography.
|
||||
|
||||
"""
|
||||
def __init__(self, mesh, order, logSigma=True, normal='X'):
|
||||
def __init__(self, mesh, order, logSigma=True, normal='X', actInd = None):
|
||||
IdentityMap.__init__(self, mesh)
|
||||
self.logSigma = logSigma
|
||||
self.order = order
|
||||
self.normal = normal
|
||||
self.actInd = actInd
|
||||
|
||||
if getattr(self, 'actInd', None) is None:
|
||||
self.actInd = range(self.mesh.nC)
|
||||
self.nC = self.mesh.nC
|
||||
|
||||
else:
|
||||
self.nC = len(self.actInd)
|
||||
|
||||
slope = 1e4
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
return (self.nC, self.nP)
|
||||
|
||||
@property
|
||||
def nP(self):
|
||||
if np.isscalar(self.order):
|
||||
@@ -785,8 +722,8 @@ class PolyMap(IdentityMap):
|
||||
sig1, sig2 = np.exp(sig1), np.exp(sig2)
|
||||
#2D
|
||||
if self.mesh.dim == 2:
|
||||
X = self.mesh.gridCC[:,0]
|
||||
Y = self.mesh.gridCC[:,1]
|
||||
X = self.mesh.gridCC[self.actInd,0]
|
||||
Y = self.mesh.gridCC[self.actInd,1]
|
||||
if self.normal =='X':
|
||||
f = polynomial.polyval(Y, c) - X
|
||||
elif self.normal =='Y':
|
||||
@@ -795,9 +732,9 @@ class PolyMap(IdentityMap):
|
||||
raise(Exception("Input for normal = X or Y or Z"))
|
||||
#3D
|
||||
elif self.mesh.dim == 3:
|
||||
X = self.mesh.gridCC[:,0]
|
||||
Y = self.mesh.gridCC[:,1]
|
||||
Z = self.mesh.gridCC[:,2]
|
||||
X = self.mesh.gridCC[self.actInd,0]
|
||||
Y = self.mesh.gridCC[self.actInd,1]
|
||||
Z = self.mesh.gridCC[self.actInd,2]
|
||||
if self.normal =='X':
|
||||
f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X
|
||||
elif self.normal =='Y':
|
||||
@@ -806,6 +743,7 @@ class PolyMap(IdentityMap):
|
||||
f = polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,self.order[1]+1))) - Z
|
||||
else:
|
||||
raise(Exception("Input for normal = X or Y or Z"))
|
||||
|
||||
else:
|
||||
raise(Exception("Only supports 2D"))
|
||||
|
||||
@@ -819,8 +757,8 @@ class PolyMap(IdentityMap):
|
||||
sig1, sig2 = np.exp(sig1), np.exp(sig2)
|
||||
#2D
|
||||
if self.mesh.dim == 2:
|
||||
X = self.mesh.gridCC[:,0]
|
||||
Y = self.mesh.gridCC[:,1]
|
||||
X = self.mesh.gridCC[self.actInd,0]
|
||||
Y = self.mesh.gridCC[self.actInd,1]
|
||||
|
||||
if self.normal =='X':
|
||||
f = polynomial.polyval(Y, c) - X
|
||||
@@ -832,9 +770,9 @@ class PolyMap(IdentityMap):
|
||||
raise(Exception("Input for normal = X or Y or Z"))
|
||||
#3D
|
||||
elif self.mesh.dim == 3:
|
||||
X = self.mesh.gridCC[:,0]
|
||||
Y = self.mesh.gridCC[:,1]
|
||||
Z = self.mesh.gridCC[:,2]
|
||||
X = self.mesh.gridCC[self.actInd,0]
|
||||
Y = self.mesh.gridCC[self.actInd,1]
|
||||
Z = self.mesh.gridCC[self.actInd,2]
|
||||
|
||||
if self.normal =='X':
|
||||
f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X
|
||||
|
||||
@@ -2,6 +2,7 @@ from SimPEG import Utils, np
|
||||
from BaseMesh import BaseRectangularMesh
|
||||
from DiffOperators import DiffOperators
|
||||
from InnerProducts import InnerProducts
|
||||
from View import CurvView
|
||||
|
||||
# Some helper functions.
|
||||
length2D = lambda x: (x[:, 0]**2 + x[:, 1]**2)**0.5
|
||||
@@ -10,7 +11,7 @@ normalize2D = lambda x: x/np.kron(np.ones((1, 2)), Utils.mkvc(length2D(x), 2))
|
||||
normalize3D = lambda x: x/np.kron(np.ones((1, 3)), Utils.mkvc(length3D(x), 2))
|
||||
|
||||
|
||||
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
|
||||
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts, CurvView):
|
||||
"""
|
||||
CurvilinearMesh is a mesh class that deals with curvilinear meshes.
|
||||
|
||||
@@ -330,102 +331,6 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
|
||||
|
||||
|
||||
|
||||
#############################################
|
||||
# Plotting Functions #
|
||||
#############################################
|
||||
|
||||
def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False):
|
||||
"""Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions.
|
||||
|
||||
|
||||
.. plot::
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh, Utils
|
||||
X, Y = Utils.exampleLrmGrid([3,3],'rotate')
|
||||
M = Mesh.CurvilinearMesh([X, Y])
|
||||
M.plotGrid(showIt=True)
|
||||
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
mkvc = Utils.mkvc
|
||||
|
||||
axOpts = {'projection':'3d'} if self.dim == 3 else {}
|
||||
if ax is None: ax = plt.subplot(111, **axOpts)
|
||||
|
||||
NN = self.r(self.gridN, 'N', 'N', 'M')
|
||||
if self.dim == 2:
|
||||
|
||||
if lines:
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
|
||||
|
||||
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
|
||||
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
|
||||
|
||||
X = np.r_[X1, X2]
|
||||
Y = np.r_[Y1, Y2]
|
||||
|
||||
ax.plot(X, Y, 'b-')
|
||||
if centers:
|
||||
ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro')
|
||||
|
||||
# Nx = self.r(self.normals, 'F', 'Fx', 'V')
|
||||
# Ny = self.r(self.normals, 'F', 'Fy', 'V')
|
||||
# Tx = self.r(self.tangents, 'E', 'Ex', 'V')
|
||||
# Ty = self.r(self.tangents, 'E', 'Ey', 'V')
|
||||
|
||||
# ax.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
|
||||
|
||||
# nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
|
||||
# ax.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
|
||||
# ax.plot(nX, nY, 'r-')
|
||||
|
||||
# nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
|
||||
# #ax.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
|
||||
# ax.plot(nX, nY, 'g-')
|
||||
|
||||
# tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
|
||||
# tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
|
||||
# ax.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
|
||||
# ax.plot(tX, tY, 'r-')
|
||||
|
||||
# nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
|
||||
# #ax.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
|
||||
# ax.plot(nX, nY, 'g-')
|
||||
|
||||
elif self.dim == 3:
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :, :]), mkvc(NN[0][1:, :, :]), mkvc(NN[0][:-1, :, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :, :]), mkvc(NN[1][1:, :, :]), mkvc(NN[1][:-1, :, :])*np.nan].flatten()
|
||||
Z1 = np.c_[mkvc(NN[2][:-1, :, :]), mkvc(NN[2][1:, :, :]), mkvc(NN[2][:-1, :, :])*np.nan].flatten()
|
||||
|
||||
X2 = np.c_[mkvc(NN[0][:, :-1, :]), mkvc(NN[0][:, 1:, :]), mkvc(NN[0][:, :-1, :])*np.nan].flatten()
|
||||
Y2 = np.c_[mkvc(NN[1][:, :-1, :]), mkvc(NN[1][:, 1:, :]), mkvc(NN[1][:, :-1, :])*np.nan].flatten()
|
||||
Z2 = np.c_[mkvc(NN[2][:, :-1, :]), mkvc(NN[2][:, 1:, :]), mkvc(NN[2][:, :-1, :])*np.nan].flatten()
|
||||
|
||||
X3 = np.c_[mkvc(NN[0][:, :, :-1]), mkvc(NN[0][:, :, 1:]), mkvc(NN[0][:, :, :-1])*np.nan].flatten()
|
||||
Y3 = np.c_[mkvc(NN[1][:, :, :-1]), mkvc(NN[1][:, :, 1:]), mkvc(NN[1][:, :, :-1])*np.nan].flatten()
|
||||
Z3 = np.c_[mkvc(NN[2][:, :, :-1]), mkvc(NN[2][:, :, 1:]), mkvc(NN[2][:, :, :-1])*np.nan].flatten()
|
||||
|
||||
X = np.r_[X1, X2, X3]
|
||||
Y = np.r_[Y1, Y2, Y3]
|
||||
Z = np.r_[Z1, Z2, Z3]
|
||||
|
||||
ax.plot(X, Y, 'b', zs=Z)
|
||||
ax.set_zlabel('x3')
|
||||
|
||||
ax.grid(True)
|
||||
ax.set_xlabel('x1')
|
||||
ax.set_ylabel('x2')
|
||||
|
||||
if showIt: plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
nc = 5
|
||||
h1 = np.cumsum(np.r_[0, np.ones(nc)/(nc)])
|
||||
|
||||
+12
-9
@@ -330,7 +330,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
raise NotImplementedError('wrapping in the averaging is not yet implemented')
|
||||
return self._aveF2CCV
|
||||
|
||||
def getInterpolationMatCartMesh(self, Mrect, locType='CC'):
|
||||
def getInterpolationMatCartMesh(self, Mrect, locType='CC', locTypeTo=None):
|
||||
"""
|
||||
Takes a cartesian mesh and returns a projection to translate onto the cartesian grid.
|
||||
"""
|
||||
@@ -338,19 +338,22 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
assert self.isSymmetric, "Currently we have not taken into account other projections for more complicated CylMeshes"
|
||||
|
||||
|
||||
if locTypeTo is None:
|
||||
locTypeTo = locType
|
||||
|
||||
if locType == 'F':
|
||||
# do this three times for each component
|
||||
X = self.getInterpolationMatCartMesh(Mrect, locType='Fx')
|
||||
Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy')
|
||||
Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz')
|
||||
X = self.getInterpolationMatCartMesh(Mrect, locType='Fx', locTypeTo=locTypeTo+'x')
|
||||
Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy', locTypeTo=locTypeTo+'y')
|
||||
Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz', locTypeTo=locTypeTo+'z')
|
||||
return sp.vstack((X,Y,Z))
|
||||
if locType == 'E':
|
||||
X = self.getInterpolationMatCartMesh(Mrect, locType='Ex')
|
||||
Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey')
|
||||
Z = spzeros(Mrect.nEz, self.nE)
|
||||
X = self.getInterpolationMatCartMesh(Mrect, locType='Ex', locTypeTo=locTypeTo+'x')
|
||||
Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey', locTypeTo=locTypeTo+'y')
|
||||
Z = spzeros(getattr(Mrect, 'n' + locTypeTo + 'z'), self.nE)
|
||||
return sp.vstack((X,Y,Z))
|
||||
|
||||
grid = getattr(Mrect, 'grid' + locType)
|
||||
grid = getattr(Mrect, 'grid' + locTypeTo)
|
||||
# This is unit circle stuff, 0 to 2*pi, starting at x-axis, rotating counter clockwise in an x-y slice
|
||||
theta = - np.arctan2(grid[:,0] - self.cartesianOrigin[0], grid[:,1] - self.cartesianOrigin[1]) + np.pi/2
|
||||
theta[theta < 0] += np.pi*2.0
|
||||
@@ -366,7 +369,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
'Ex': Mrect.tangents[:Mrect.nEx,:],
|
||||
'Ey': Mrect.tangents[Mrect.nEx:(Mrect.nEx+Mrect.nEy),:],
|
||||
'Ez': Mrect.tangents[-Mrect.nEz:,:],
|
||||
}[locType]
|
||||
}[locTypeTo]
|
||||
if 'F' in locType:
|
||||
normals = np.c_[np.cos(theta), np.sin(theta), np.zeros(theta.size)]
|
||||
proj = ( normals * dotMe ).sum(axis=1)
|
||||
|
||||
+109
-30
@@ -307,24 +307,28 @@ class DiffOperators(object):
|
||||
return BC
|
||||
_cellGradBC_list = 'neumann'
|
||||
|
||||
def _cellGradStencil(self):
|
||||
BC = self.setCellGradBC(self._cellGradBC_list)
|
||||
n = self.vnC
|
||||
if(self.dim == 1):
|
||||
G = ddxCellGrad(n[0], BC[0])
|
||||
elif(self.dim == 2):
|
||||
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0]))
|
||||
G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0]))
|
||||
G = sp.vstack((G1, G2), format="csr")
|
||||
elif(self.dim == 3):
|
||||
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0]))
|
||||
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0]))
|
||||
G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0]))
|
||||
G = sp.vstack((G1, G2, G3), format="csr")
|
||||
return G
|
||||
|
||||
def cellGrad():
|
||||
doc = "The cell centered Gradient, takes you to cell faces."
|
||||
|
||||
def fget(self):
|
||||
if(self._cellGrad is None):
|
||||
BC = self.setCellGradBC(self._cellGradBC_list)
|
||||
n = self.vnC
|
||||
if(self.dim == 1):
|
||||
G = ddxCellGrad(n[0], BC[0])
|
||||
elif(self.dim == 2):
|
||||
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0]))
|
||||
G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0]))
|
||||
G = sp.vstack((G1, G2), format="csr")
|
||||
elif(self.dim == 3):
|
||||
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0]))
|
||||
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0]))
|
||||
G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0]))
|
||||
G = sp.vstack((G1, G2, G3), format="csr")
|
||||
G = self._cellGradStencil()
|
||||
# Compute areas of cell faces & volumes
|
||||
S = self.area
|
||||
V = self.aveCC2F*self.vol # Average volume between adjacent cells
|
||||
@@ -361,19 +365,24 @@ class DiffOperators(object):
|
||||
_cellGradBC = None
|
||||
cellGradBC = property(**cellGradBC())
|
||||
|
||||
def _cellGradxStencil(self):
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
if(self.dim == 1):
|
||||
G1 = ddxCellGrad(n[0], BC)
|
||||
elif(self.dim == 2):
|
||||
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC))
|
||||
elif(self.dim == 3):
|
||||
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC))
|
||||
return G1
|
||||
|
||||
|
||||
def cellGradx():
|
||||
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
|
||||
|
||||
def fget(self):
|
||||
if getattr(self, '_cellGradx', None) is None:
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
if(self.dim == 1):
|
||||
G1 = ddxCellGrad(n[0], BC)
|
||||
elif(self.dim == 2):
|
||||
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC))
|
||||
elif(self.dim == 3):
|
||||
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC))
|
||||
G1 = self._cellGradxStencil()
|
||||
# Compute areas of cell faces & volumes
|
||||
V = self.aveCC2F*self.vol
|
||||
L = self.r(self.area/V, 'F','Fx', 'V')
|
||||
@@ -382,17 +391,22 @@ class DiffOperators(object):
|
||||
return locals()
|
||||
cellGradx = property(**cellGradx())
|
||||
|
||||
def _cellGradyStencil(self):
|
||||
if self.dim < 2: return None
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
if(self.dim == 2):
|
||||
G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0]))
|
||||
elif(self.dim == 3):
|
||||
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0]))
|
||||
return G2
|
||||
|
||||
def cellGrady():
|
||||
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
|
||||
def fget(self):
|
||||
if self.dim < 2: return None
|
||||
if getattr(self, '_cellGrady', None) is None:
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
if(self.dim == 2):
|
||||
G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0]))
|
||||
elif(self.dim == 3):
|
||||
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0]))
|
||||
G2 = self._cellGradyStencil()
|
||||
# Compute areas of cell faces & volumes
|
||||
V = self.aveCC2F*self.vol
|
||||
L = self.r(self.area/V, 'F','Fy', 'V')
|
||||
@@ -401,14 +415,19 @@ class DiffOperators(object):
|
||||
return locals()
|
||||
cellGrady = property(**cellGrady())
|
||||
|
||||
def _cellGradzStencil(self):
|
||||
if self.dim < 3: return None
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0]))
|
||||
return G3
|
||||
|
||||
def cellGradz():
|
||||
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
|
||||
def fget(self):
|
||||
if self.dim < 3: return None
|
||||
if getattr(self, '_cellGradz', None) is None:
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0]))
|
||||
G3 = self._cellGradzStencil()
|
||||
# Compute areas of cell faces & volumes
|
||||
V = self.aveCC2F*self.vol
|
||||
L = self.r(self.area/V, 'F','Fz', 'V')
|
||||
@@ -565,7 +584,67 @@ class DiffOperators(object):
|
||||
|
||||
return Pbc, Pin, Pout
|
||||
|
||||
def getBCProjWF_simple(self, discretization='CC'):
|
||||
"""
|
||||
|
||||
The weak form boundary condition projection matrices
|
||||
when mixed boundary condition is used
|
||||
|
||||
|
||||
"""
|
||||
|
||||
if discretization is not 'CC':
|
||||
raise NotImplementedError('Boundary conditions only implemented for CC discretization.')
|
||||
|
||||
def projBC(n):
|
||||
ij = ([0,n], [0,1])
|
||||
vals = [0,0]
|
||||
vals[0] = 1
|
||||
vals[1] = 1
|
||||
return sp.csr_matrix((vals, ij), shape=(n+1,2))
|
||||
|
||||
def projDirichlet(n, bc):
|
||||
bc = checkBC(bc)
|
||||
ij = ([0,n], [0,1])
|
||||
vals = [0,0]
|
||||
if(bc[0] == 'dirichlet'):
|
||||
vals[0] = -1
|
||||
if(bc[1] == 'dirichlet'):
|
||||
vals[1] = 1
|
||||
return sp.csr_matrix((vals, ij), shape=(n+1,2))
|
||||
|
||||
BC = [['dirichlet','dirichlet'],['dirichlet','dirichlet'],['dirichlet','dirichlet']]
|
||||
n = self.vnC
|
||||
indF = self.faceBoundaryInd
|
||||
if(self.dim == 1):
|
||||
Pbc = projDirichlet(n[0], BC[0])
|
||||
B = projBC(n[0])
|
||||
indF = indF[0] | indF[1]
|
||||
Pbc = Pbc*sdiag(self.area[indF])
|
||||
|
||||
elif(self.dim == 2):
|
||||
Pbc1 = sp.kron(speye(n[1]), projDirichlet(n[0], BC[0]))
|
||||
Pbc2 = sp.kron(projDirichlet(n[1], BC[1]), speye(n[0]))
|
||||
Pbc = sp.block_diag((Pbc1, Pbc2), format="csr")
|
||||
B1 = sp.kron(speye(n[1]), projBC(n[0]))
|
||||
B2 = sp.kron(projBC(n[1]), speye(n[0]))
|
||||
B = sp.block_diag((B1, B2), format="csr")
|
||||
indF = np.r_[(indF[0] | indF[1]), (indF[2] | indF[3])]
|
||||
Pbc = Pbc*sdiag(self.area[indF])
|
||||
|
||||
elif(self.dim == 3):
|
||||
Pbc1 = kron3(speye(n[2]), speye(n[1]), projDirichlet(n[0], BC[0]))
|
||||
Pbc2 = kron3(speye(n[2]), projDirichlet(n[1], BC[1]), speye(n[0]))
|
||||
Pbc3 = kron3(projDirichlet(n[2], BC[2]), speye(n[1]), speye(n[0]))
|
||||
Pbc = sp.block_diag((Pbc1, Pbc2, Pbc3), format="csr")
|
||||
B1 = kron3(speye(n[2]), speye(n[1]), projBC(n[0]))
|
||||
B2 = kron3(speye(n[2]), projBC(n[1]), speye(n[0]))
|
||||
B3 = kron3(projBC(n[2]), speye(n[1]), speye(n[0]))
|
||||
B = sp.block_diag((B1, B2, B3), format="csr")
|
||||
indF = np.r_[(indF[0] | indF[1]), (indF[2] | indF[3]), (indF[4] | indF[5])]
|
||||
Pbc = Pbc*sdiag(self.area[indF])
|
||||
|
||||
return Pbc, B.T
|
||||
# --------------- Averaging ---------------------
|
||||
|
||||
@property
|
||||
|
||||
+45
-3
@@ -21,10 +21,9 @@ class TensorMeshIO(object):
|
||||
if '*' in seg:
|
||||
st = seg
|
||||
sp = seg.split('*')
|
||||
re = np.array(sp[0],dtype=int)*(' ' + sp[1])
|
||||
re = int(sp[0])*(' ' + sp[1])
|
||||
line = line.replace(st,re.strip())
|
||||
return np.array(line.split(),dtype=float)
|
||||
|
||||
# Read the file as line strings, remove lines with comment = !
|
||||
msh = np.genfromtxt(fileName,delimiter='\n',dtype=np.str,comments='!')
|
||||
|
||||
@@ -141,7 +140,6 @@ class TensorMeshIO(object):
|
||||
vtkObj.GetCellData().AddArray(vtkDoubleArr)
|
||||
# Set the active scalar
|
||||
vtkObj.GetCellData().SetActiveScalars(models.keys()[0])
|
||||
# vtkObj.Update()
|
||||
|
||||
# Check the extension of the fileName
|
||||
ext = os.path.splitext(fileName)[1]
|
||||
@@ -158,6 +156,50 @@ class TensorMeshIO(object):
|
||||
vtrWriteFilter.SetFileName(fileName)
|
||||
vtrWriteFilter.Update()
|
||||
|
||||
def _toVTRObj(mesh,models=None):
|
||||
"""
|
||||
Makes and saves a VTK rectilinear file (vtr) for a simpeg Tensor mesh and model.
|
||||
|
||||
Input:
|
||||
:param str, path to the output vtk file
|
||||
:param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK
|
||||
:param models, dictionary of numpy.array - Name('s) and array('s). Match number of cells
|
||||
|
||||
"""
|
||||
# Import
|
||||
from vtk import vtkRectilinearGrid as rectGrid, VTK_VERSION
|
||||
from vtk.util.numpy_support import numpy_to_vtk
|
||||
|
||||
# Deal with dimensionalities
|
||||
if mesh.dim >= 1:
|
||||
vX = mesh.vectorNx
|
||||
xD = mesh.nNx
|
||||
yD,zD = 1,1
|
||||
vY, vZ = np.array([0,0])
|
||||
if mesh.dim >= 2:
|
||||
vY = mesh.vectorNy
|
||||
yD = mesh.nNy
|
||||
if mesh.dim == 3:
|
||||
vZ = mesh.vectorNz
|
||||
zD = mesh.nNz
|
||||
# Use rectilinear VTK grid.
|
||||
# Assign the spatial information.
|
||||
vtkObj = rectGrid()
|
||||
vtkObj.SetDimensions(xD,yD,zD)
|
||||
vtkObj.SetXCoordinates(numpy_to_vtk(vX,deep=1))
|
||||
vtkObj.SetYCoordinates(numpy_to_vtk(vY,deep=1))
|
||||
vtkObj.SetZCoordinates(numpy_to_vtk(vZ,deep=1))
|
||||
|
||||
# Assign the model('s) to the object
|
||||
if models is not None:
|
||||
for item in models.iteritems():
|
||||
# Convert numpy array
|
||||
vtkDoubleArr = numpy_to_vtk(item[1],deep=1)
|
||||
vtkDoubleArr.SetName(item[0])
|
||||
vtkObj.GetCellData().AddArray(vtkDoubleArr)
|
||||
# Set the active scalar
|
||||
vtkObj.GetCellData().SetActiveScalars(models.keys()[0])
|
||||
return vtkObj
|
||||
|
||||
def readModelUBC(mesh, fileName):
|
||||
"""
|
||||
|
||||
@@ -2131,10 +2131,16 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO):
|
||||
def plotSlice(self, v, vType='CC',
|
||||
normal='Z', ind=None, grid=True, view='real',
|
||||
ax=None, clim=None, showIt=False,
|
||||
pcolorOpts={},
|
||||
streamOpts={'color':'k'},
|
||||
gridOpts={'color':'k', 'alpha':0.5}):
|
||||
pcolorOpts=None,
|
||||
streamOpts=None,
|
||||
gridOpts=None):
|
||||
|
||||
if pcolorOpts is None:
|
||||
pcolorOpts = {}
|
||||
if streamOpts is None:
|
||||
streamOpts = {'color':'k'}
|
||||
if gridOpts is None:
|
||||
gridOpts = {'color':'k', 'alpha':0.5}
|
||||
assert vType in ['CC','F','E']
|
||||
assert self.dim == 3
|
||||
|
||||
|
||||
+106
-50
@@ -42,9 +42,9 @@ class TensorView(object):
|
||||
|
||||
def plotImage(self, v, vType='CC', grid=False, view='real',
|
||||
ax=None, clim=None, showIt=False,
|
||||
pcolorOpts={},
|
||||
streamOpts={'color':'k'},
|
||||
gridOpts={'color':'k'},
|
||||
pcolorOpts=None,
|
||||
streamOpts=None,
|
||||
gridOpts=None,
|
||||
numbering=True, annotationColor='w'
|
||||
):
|
||||
"""
|
||||
@@ -84,6 +84,12 @@ class TensorView(object):
|
||||
M.plotImage(v, annotationColor='k', showIt=True)
|
||||
|
||||
"""
|
||||
if pcolorOpts is None:
|
||||
pcolorOpts = {}
|
||||
if streamOpts is None:
|
||||
streamOpts = {'color':'k'}
|
||||
if gridOpts is None:
|
||||
gridOpts = {'color':'k'}
|
||||
|
||||
if ax is None:
|
||||
fig = plt.figure()
|
||||
@@ -174,9 +180,9 @@ class TensorView(object):
|
||||
def plotSlice(self, v, vType='CC',
|
||||
normal='Z', ind=None, grid=False, view='real',
|
||||
ax=None, clim=None, showIt=False,
|
||||
pcolorOpts={},
|
||||
streamOpts={'color':'k'},
|
||||
gridOpts={'color':'k', 'alpha':0.5}
|
||||
pcolorOpts=None,
|
||||
streamOpts=None,
|
||||
gridOpts=None
|
||||
):
|
||||
|
||||
"""
|
||||
@@ -197,6 +203,12 @@ class TensorView(object):
|
||||
M.plotSlice(M.cellGrad*b, 'F', view='vec', grid=True, showIt=True, pcolorOpts={'alpha':0.8})
|
||||
|
||||
"""
|
||||
if pcolorOpts is None:
|
||||
pcolorOpts = {}
|
||||
if streamOpts is None:
|
||||
streamOpts = {'color':'k'}
|
||||
if gridOpts is None:
|
||||
gridOpts = {'color':'k', 'alpha':0.5}
|
||||
if type(vType) in [list, tuple]:
|
||||
assert ax is None, "cannot specify an axis to plot on with this function."
|
||||
fig, axs = plt.subplots(1,len(vType))
|
||||
@@ -206,7 +218,7 @@ class TensorView(object):
|
||||
return out
|
||||
viewOpts = ['real','imag','abs','vec']
|
||||
normalOpts = ['X', 'Y', 'Z']
|
||||
vTypeOpts = ['CC', 'CCv','F','E','Fx','Fy','Fz','E','Ex','Ey','Ez']
|
||||
vTypeOpts = ['CC', 'CCv','N','F','E','Fx','Fy','Fz','E','Ex','Ey','Ez']
|
||||
|
||||
# Some user error checking
|
||||
assert vType in vTypeOpts, "vType must be in ['%s']" % "','".join(vTypeOpts)
|
||||
@@ -289,11 +301,17 @@ class TensorView(object):
|
||||
|
||||
def _plotImage2D(self, v, vType='CC', grid=False, view='real',
|
||||
ax=None, clim=None, showIt=False,
|
||||
pcolorOpts={},
|
||||
streamOpts={'color':'k'},
|
||||
gridOpts={'color':'k'}
|
||||
pcolorOpts=None,
|
||||
streamOpts=None,
|
||||
gridOpts=None
|
||||
):
|
||||
|
||||
if pcolorOpts is None:
|
||||
pcolorOpts = {}
|
||||
if streamOpts is None:
|
||||
streamOpts = {'color':'k'}
|
||||
if gridOpts is None:
|
||||
gridOpts = {'color':'k'}
|
||||
vTypeOptsCC = ['N','CC','Fx','Fy','Ex','Ey']
|
||||
vTypeOptsV = ['CCv','F','E']
|
||||
vTypeOpts = vTypeOptsCC + vTypeOptsV
|
||||
@@ -534,7 +552,8 @@ class CurvView(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def plotGrid(self, length=0.05, showIt=False):
|
||||
|
||||
def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False):
|
||||
"""Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions.
|
||||
|
||||
|
||||
@@ -542,60 +561,63 @@ class CurvView(object):
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh, Utils
|
||||
X, Y = Utils.exampleCurvGird([3,3],'rotate')
|
||||
X, Y = Utils.exampleLrmGrid([3,3],'rotate')
|
||||
M = Mesh.CurvilinearMesh([X, Y])
|
||||
M.plotGrid(showIt=True)
|
||||
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
|
||||
axOpts = {'projection':'3d'} if self.dim == 3 else {}
|
||||
if ax is None: ax = plt.subplot(111, **axOpts)
|
||||
|
||||
NN = self.r(self.gridN, 'N', 'N', 'M')
|
||||
if self.dim == 2:
|
||||
fig = plt.figure(2)
|
||||
fig.clf()
|
||||
ax = plt.subplot(111)
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
|
||||
|
||||
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
|
||||
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
|
||||
if lines:
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
|
||||
|
||||
X = np.r_[X1, X2]
|
||||
Y = np.r_[Y1, Y2]
|
||||
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
|
||||
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
|
||||
|
||||
plt.plot(X, Y)
|
||||
X = np.r_[X1, X2]
|
||||
Y = np.r_[Y1, Y2]
|
||||
|
||||
plt.hold(True)
|
||||
Nx = self.r(self.normals, 'F', 'Fx', 'V')
|
||||
Ny = self.r(self.normals, 'F', 'Fy', 'V')
|
||||
Tx = self.r(self.tangents, 'E', 'Ex', 'V')
|
||||
Ty = self.r(self.tangents, 'E', 'Ey', 'V')
|
||||
ax.plot(X, Y, 'b-')
|
||||
if centers:
|
||||
ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro')
|
||||
|
||||
plt.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
|
||||
# Nx = self.r(self.normals, 'F', 'Fx', 'V')
|
||||
# Ny = self.r(self.normals, 'F', 'Fy', 'V')
|
||||
# Tx = self.r(self.tangents, 'E', 'Ex', 'V')
|
||||
# Ty = self.r(self.tangents, 'E', 'Ey', 'V')
|
||||
|
||||
nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
|
||||
nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
|
||||
plt.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
|
||||
plt.plot(nX, nY, 'r-')
|
||||
# ax.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
|
||||
|
||||
nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
|
||||
nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
|
||||
#plt.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
|
||||
plt.plot(nX, nY, 'g-')
|
||||
# nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
|
||||
# ax.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
|
||||
# ax.plot(nX, nY, 'r-')
|
||||
|
||||
tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
|
||||
tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
|
||||
plt.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
|
||||
plt.plot(tX, tY, 'r-')
|
||||
# nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
|
||||
# #ax.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
|
||||
# ax.plot(nX, nY, 'g-')
|
||||
|
||||
nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
|
||||
nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
|
||||
#plt.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
|
||||
plt.plot(nX, nY, 'g-')
|
||||
plt.axis('equal')
|
||||
# tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
|
||||
# tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
|
||||
# ax.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
|
||||
# ax.plot(tX, tY, 'r-')
|
||||
|
||||
# nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
|
||||
# #ax.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
|
||||
# ax.plot(nX, nY, 'g-')
|
||||
|
||||
elif self.dim == 3:
|
||||
fig = plt.figure(3)
|
||||
fig.clf()
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :, :]), mkvc(NN[0][1:, :, :]), mkvc(NN[0][:-1, :, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :, :]), mkvc(NN[1][1:, :, :]), mkvc(NN[1][:-1, :, :])*np.nan].flatten()
|
||||
Z1 = np.c_[mkvc(NN[2][:-1, :, :]), mkvc(NN[2][1:, :, :]), mkvc(NN[2][:-1, :, :])*np.nan].flatten()
|
||||
@@ -612,16 +634,50 @@ class CurvView(object):
|
||||
Y = np.r_[Y1, Y2, Y3]
|
||||
Z = np.r_[Z1, Z2, Z3]
|
||||
|
||||
plt.plot(X, Y, 'b', zs=Z)
|
||||
ax.plot(X, Y, 'b', zs=Z)
|
||||
ax.set_zlabel('x3')
|
||||
|
||||
ax.grid(True)
|
||||
ax.hold(False)
|
||||
ax.set_xlabel('x1')
|
||||
ax.set_ylabel('x2')
|
||||
|
||||
if showIt: plt.show()
|
||||
|
||||
def plotImage(self, I, ax=None, showIt=False, grid=False, clim=None):
|
||||
if self.dim == 3: raise NotImplementedError('This is not yet done!')
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
import matplotlib.colors as colors
|
||||
import matplotlib.cm as cmx
|
||||
|
||||
if ax is None: ax = plt.subplot(111)
|
||||
jet = cm = plt.get_cmap('jet')
|
||||
cNorm = colors.Normalize(
|
||||
vmin=I.min() if clim is None else clim[0],
|
||||
vmax=I.max() if clim is None else clim[1])
|
||||
|
||||
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
|
||||
# ax.set_xlim((self.x0[0], self.h[0].sum()))
|
||||
# ax.set_ylim((self.x0[1], self.h[1].sum()))
|
||||
|
||||
Nx = self.r(self.gridN[:,0],'N','N','M')
|
||||
Ny = self.r(self.gridN[:,1],'N','N','M')
|
||||
cell = self.r(I,'CC','CC','M')
|
||||
|
||||
for ii in range(self.nCx):
|
||||
for jj in range(self.nCy):
|
||||
I = [ii,ii+1,ii+1,ii]
|
||||
J = [jj,jj,jj+1,jj+1]
|
||||
ax.add_patch(plt.Polygon(np.c_[Nx[I,J],Ny[I,J]], facecolor=scalarMap.to_rgba(cell[ii,jj]), edgecolor='k' if grid else 'none'))
|
||||
|
||||
scalarMap._A = [] # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots
|
||||
ax.set_xlabel('x')
|
||||
ax.set_ylabel('y')
|
||||
if showIt: plt.show()
|
||||
return [scalarMap]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from SimPEG import *
|
||||
|
||||
@@ -4,18 +4,21 @@ import sys
|
||||
from numpy.lib import recfunctions as recFunc
|
||||
from SimPEG.EM.Utils import omega
|
||||
|
||||
|
||||
##############
|
||||
### Fields ###
|
||||
##############
|
||||
class BaseMTFields(Problem.Fields):
|
||||
"""Field Storage for a MT survey."""
|
||||
class BaseNSEMFields(Problem.Fields):
|
||||
"""Field Storage for a NSEM survey."""
|
||||
knownFields = {}
|
||||
dtype = complex
|
||||
|
||||
|
||||
class Fields1D_e(BaseMTFields):
|
||||
###########
|
||||
# 1D Fields
|
||||
###########
|
||||
class Fields1D_ePrimSec(BaseNSEMFields):
|
||||
"""
|
||||
Fields storage for the 1D MT solution.
|
||||
Fields storage for the 1D NSEM solution.
|
||||
"""
|
||||
knownFields = {'e_1dSolution':'F'}
|
||||
aliasFields = {
|
||||
@@ -28,7 +31,119 @@ class Fields1D_e(BaseMTFields):
|
||||
}
|
||||
|
||||
def __init__(self,mesh,survey,**kwargs):
|
||||
BaseMTFields.__init__(self,mesh,survey,**kwargs)
|
||||
BaseNSEMFields.__init__(self,mesh,survey,**kwargs)
|
||||
|
||||
def _ePrimary(self, eSolution, srcList):
|
||||
ePrimary = np.zeros_like(eSolution)
|
||||
for i, src in enumerate(srcList):
|
||||
ep = src.ePrimary(self.survey.prob)
|
||||
if ep is not None:
|
||||
ePrimary[:,i] = ep[:,-1]
|
||||
return ePrimary
|
||||
|
||||
def _eSecondary(self, eSolution, srcList):
|
||||
return eSolution
|
||||
|
||||
def _e(self, eSolution, srcList):
|
||||
return self._ePrimary(eSolution,srcList) + self._eSecondary(eSolution,srcList)
|
||||
|
||||
def _eDeriv_u(self, src, du_dm_v, adjoint = False):
|
||||
|
||||
|
||||
return Utils.Identity()*du_dm_v
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint = False):
|
||||
# assuming primary does not depend on the model
|
||||
return Utils.Zero()
|
||||
|
||||
def _bPrimary(self, eSolution, srcList):
|
||||
bPrimary = np.zeros([self.survey.mesh.nE,eSolution.shape[1]], dtype = complex)
|
||||
for i, src in enumerate(srcList):
|
||||
bp = src.bPrimary(self.survey.prob)
|
||||
if bp is not None:
|
||||
bPrimary[:,i] += bp[:,-1]
|
||||
return bPrimary
|
||||
|
||||
def _bSecondary(self, eSolution, srcList):
|
||||
C = self.mesh.nodalGrad
|
||||
b = (C * eSolution)
|
||||
for i, src in enumerate(srcList):
|
||||
b[:,i] *= - 1./(1j*omega(src.freq))
|
||||
# There is no magnetic source in the MT problem
|
||||
# S_m, _ = src.eval(self.survey.prob)
|
||||
# if S_m is not None:
|
||||
# b[:,i] += 1./(1j*omega(src.freq)) * S_m
|
||||
return b
|
||||
|
||||
def _b(self, eSolution, srcList):
|
||||
return self._bPrimary(eSolution, srcList) + self._bSecondary(eSolution, srcList)
|
||||
|
||||
def _bSecondaryDeriv_u(self, src, v, adjoint = False):
|
||||
C = self.mesh.nodalGrad
|
||||
if adjoint:
|
||||
return - 1./(1j*omega(src.freq)) * (C.T * v)
|
||||
return - 1./(1j*omega(src.freq)) * (C * v)
|
||||
|
||||
def _bSecondaryDeriv_m(self, src, v, adjoint = False):
|
||||
# Doesn't depend on m
|
||||
# _, S_eDeriv = src.evalDeriv(self.survey.prob, adjoint)
|
||||
# S_eDeriv = S_eDeriv(v)
|
||||
# if S_eDeriv is not None:
|
||||
# return 1./(1j * omega(src.freq)) * S_eDeriv
|
||||
return None
|
||||
|
||||
def _bDeriv_u(self, src, v, adjoint=False):
|
||||
# Primary does not depend on u
|
||||
return self._bSecondaryDeriv_u(src, v, adjoint)
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint=False):
|
||||
# Assuming the primary does not depend on the model
|
||||
return self._bSecondaryDeriv_m(src, v, adjoint)
|
||||
|
||||
def _fDeriv_u(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the fields object wrt u.
|
||||
|
||||
:param NSEMsrc src: NSEM source
|
||||
:param numpy.ndarray v: random vector of f_sol.size
|
||||
This function stacks the fields derivatives appropriately
|
||||
|
||||
return a vector of size (nreEle+nrbEle)
|
||||
"""
|
||||
|
||||
de_du = v #Utils.spdiag(np.ones((self.nF,)))
|
||||
db_du = self._bDeriv_u(src, v, adjoint)
|
||||
# Return the stack
|
||||
# This doesn't work...
|
||||
return np.vstack((de_du,db_du))
|
||||
|
||||
def _fDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the fields object wrt m.
|
||||
|
||||
This function stacks the fields derivatives appropriately
|
||||
"""
|
||||
return None
|
||||
|
||||
|
||||
class Fields1D_eTotal(BaseNSEMFields):
|
||||
"""
|
||||
Fields storage for the 1D NSEM solution solved with for a total domain formulation.
|
||||
|
||||
Used in conjuction with Problem1D_eTotal.
|
||||
"""
|
||||
knownFields = {'e_1dSolution':'F'}
|
||||
aliasFields = {
|
||||
'e_1d' : ['e_1dSolution','F','_e'],
|
||||
'e_1dPrimary' : ['e_1dSolution','F','_ePrimary'],
|
||||
'e_1dSecondary' : ['e_1dSolution','F','_eSecondary'],
|
||||
'b_1d' : ['e_1dSolution','E','_b'],
|
||||
'b_1dPrimary' : ['e_1dSolution','E','_bPrimary'],
|
||||
'b_1dSecondary' : ['e_1dSolution','E','_bSecondary']
|
||||
}
|
||||
|
||||
def __init__(self,mesh,survey,**kwargs):
|
||||
BaseNSEMFields.__init__(self,mesh,survey,**kwargs)
|
||||
|
||||
def _ePrimary(self, eSolution, srcList):
|
||||
ePrimary = np.zeros_like(eSolution)
|
||||
@@ -99,7 +214,7 @@ class Fields1D_e(BaseMTFields):
|
||||
"""
|
||||
Derivative of the fields object wrt u.
|
||||
|
||||
:param MTsrc src: MT source
|
||||
:param NSEMsrc src: NSEM source
|
||||
:param numpy.ndarray v: random vector of f_sol.size
|
||||
This function stacks the fields derivatives appropriately
|
||||
|
||||
@@ -120,9 +235,18 @@ class Fields1D_e(BaseMTFields):
|
||||
"""
|
||||
return None
|
||||
|
||||
class Fields3D_e(BaseMTFields):
|
||||
|
||||
###########
|
||||
# 2D Fields
|
||||
###########
|
||||
|
||||
|
||||
###########
|
||||
# 3D Fields
|
||||
###########
|
||||
class Fields3D_ePrimSec(BaseNSEMFields):
|
||||
"""
|
||||
Fields storage for the 3D MT solution. Labels polarizations by px and py.
|
||||
Fields storage for the 3D NSEM solution. Labels polarizations by px and py.
|
||||
|
||||
:param SimPEG object mesh: The solution mesh
|
||||
:param SimPEG object survey: A survey object
|
||||
@@ -147,7 +271,7 @@ class Fields3D_e(BaseMTFields):
|
||||
}
|
||||
|
||||
def __init__(self,mesh,survey,**kwargs):
|
||||
BaseMTFields.__init__(self,mesh,survey,**kwargs)
|
||||
BaseNSEMFields.__init__(self,mesh,survey,**kwargs)
|
||||
|
||||
def _e_pxPrimary(self, e_pxSolution, srcList):
|
||||
e_pxPrimary = np.zeros_like(e_pxSolution)
|
||||
@@ -228,7 +352,7 @@ class Fields3D_e(BaseMTFields):
|
||||
b = (C * e_pxSolution)
|
||||
for i, src in enumerate(srcList):
|
||||
b[:,i] *= - 1./(1j*omega(src.freq))
|
||||
# There is no magnetic source in the MT problem
|
||||
# There is no magnetic source in the NSEM problem
|
||||
# S_m, _ = src.eval(self.survey.prob)
|
||||
# if S_m is not None:
|
||||
# b[:,i] += 1./(1j*omega(src.freq)) * S_m
|
||||
@@ -239,7 +363,7 @@ class Fields3D_e(BaseMTFields):
|
||||
b = (C * e_pySolution)
|
||||
for i, src in enumerate(srcList):
|
||||
b[:,i] *= - 1./(1j*omega(src.freq))
|
||||
# There is no magnetic source in the MT problem
|
||||
# There is no magnetic source in the NSEM problem
|
||||
# S_m, _ = src.eval(self.survey.prob)
|
||||
# if S_m is not None:
|
||||
# b[:,i] += 1./(1j*omega(src.freq)) * S_m
|
||||
@@ -302,7 +426,7 @@ class Fields3D_e(BaseMTFields):
|
||||
"""
|
||||
Derivative of the fields object wrt u.
|
||||
|
||||
:param MTsrc src: MT source
|
||||
:param NSEMsrc src: NSEM source
|
||||
:param numpy.ndarray v: random vector of f_sol.size
|
||||
This function stacks the fields derivatives appropriately
|
||||
|
||||
@@ -319,7 +443,7 @@ class Fields3D_e(BaseMTFields):
|
||||
"""
|
||||
Derivative of the fields object wrt u.
|
||||
|
||||
:param MTsrc src: MT source
|
||||
:param NSEMsrc src: NSEM source
|
||||
:param numpy.ndarray v: random vector of f_sol.size
|
||||
This function stacks the fields derivatives appropriately
|
||||
|
||||
@@ -0,0 +1,560 @@
|
||||
from SimPEG.EM.Utils.EMUtils import omega, mu_0
|
||||
from SimPEG import SolverLU as SimpegSolver, PropMaps, Utils, mkvc, sp, np
|
||||
from SimPEG.EM.FDEM.ProblemFDEM import BaseFDEMProblem
|
||||
from SurveyNSEM import Survey, Data
|
||||
from FieldsNSEM import BaseNSEMFields, Fields1D_ePrimSec, Fields3D_ePrimSec
|
||||
from SimPEG.NSEM.Utils.MT1Danalytic import getEHfields
|
||||
import time, sys
|
||||
|
||||
class BaseNSEMProblem(BaseFDEMProblem):
|
||||
"""
|
||||
Base class for all Natural source problems.
|
||||
"""
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
Utils.setKwargs(self, **kwargs)
|
||||
# Set the default pairs of the problem
|
||||
surveyPair = Survey
|
||||
dataPair = Data
|
||||
fieldsPair = BaseNSEMFields
|
||||
|
||||
# Set the solver
|
||||
Solver = SimpegSolver
|
||||
solverOpts = {}
|
||||
|
||||
verbose = False
|
||||
# Notes:
|
||||
# Use the forward and devs from BaseFDEMProblem
|
||||
# Might need to add more stuff here.
|
||||
|
||||
## NEED to clean up the Jvec and Jtvec to use Zero and Identities for None components.
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""
|
||||
Function to calculate the data sensitivities dD/dm times a vector.
|
||||
|
||||
:param numpy.ndarray m (nC, 1) - conductive model
|
||||
:param numpy.ndarray v (nC, 1) - random vector
|
||||
:param NSEMfields object (optional) - NSEM fields object, if not given it is calculated
|
||||
:rtype: NSEMdata object
|
||||
:return: Data sensitivities wrt m
|
||||
"""
|
||||
|
||||
# Calculate the fields
|
||||
if f is None:
|
||||
f= self.fields(m)
|
||||
# Set current model
|
||||
self.curModel = m
|
||||
# Initiate the Jv object
|
||||
Jv = self.dataPair(self.survey)
|
||||
|
||||
# Loop all the frequenies
|
||||
for freq in self.survey.freqs:
|
||||
dA_du = self.getA(freq) #
|
||||
|
||||
dA_duI = self.Solver(dA_du, **self.solverOpts)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
# We need fDeriv_m = df/du*du/dm + df/dm
|
||||
# Construct du/dm, it requires a solve
|
||||
# NOTE: need to account for the 2 polarizations in the derivatives.
|
||||
u_src = f[src,:] # u should be a vector by definition. Need to fix this...
|
||||
# dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by dA_duI. The 2 columns are each of the polarizations.
|
||||
dA_dm = self.getADeriv_m(freq, u_src, v) # Size: nE,2 (u_px,u_py) in the columns.
|
||||
dRHS_dm = self.getRHSDeriv_m(freq, v) # Size: nE,2 (u_px,u_py) in the columns.
|
||||
if dRHS_dm is None:
|
||||
du_dm = dA_duI * ( -dA_dm )
|
||||
else:
|
||||
du_dm = dA_duI * ( -dA_dm + dRHS_dm )
|
||||
# Calculate the projection derivatives
|
||||
for rx in src.rxList:
|
||||
# Get the projection derivative
|
||||
# v should be of size 2*nE (for 2 polarizations)
|
||||
PDeriv_u = lambda t: rx.evalDeriv(src, self.mesh, f, t) # wrt u, we don't have have PDeriv wrt m
|
||||
Jv[src, rx] = PDeriv_u(mkvc(du_dm))
|
||||
dA_duI.clean()
|
||||
# Return the vectorized sensitivities
|
||||
return mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""
|
||||
Function to calculate the transpose of the data sensitivities (dD/dm)^T times a vector.
|
||||
|
||||
:param numpy.ndarray m (nC, 1) - conductive model
|
||||
:param numpy.ndarray v (nD, 1) - vector
|
||||
:param NSEMfields object f (optional) - NSEM fields object, if not given it is calculated
|
||||
:rtype: NSEMdata object
|
||||
:return: Data sensitivities wrt m
|
||||
"""
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv = np.zeros(m.size)
|
||||
|
||||
for freq in self.survey.freqs:
|
||||
AT = self.getA(freq).T
|
||||
|
||||
ATinv = self.Solver(AT, **self.solverOpts)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
ftype = self._solutionType
|
||||
f_src = f[src, :] # Need to fix this...
|
||||
|
||||
for rx in src.rxList:
|
||||
# Get the adjoint evalDeriv
|
||||
# PTv needs to be nE,
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, mkvc(v[src, rx],2), adjoint=True) # wrt u, need possibility wrt m
|
||||
# Get the
|
||||
dA_duIT = ATinv * PTv
|
||||
dA_dmT = self.getADeriv_m(freq, f_src, mkvc(dA_duIT), adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv_m(freq, mkvc(dA_duIT), adjoint=True)
|
||||
# Make du_dmT
|
||||
if dRHS_dmT is None:
|
||||
du_dmT = -dA_dmT
|
||||
else:
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
# Select the correct component
|
||||
# du_dmT needs to be of size nC,
|
||||
real_or_imag = rx.projComp
|
||||
if real_or_imag == 'real':
|
||||
Jtv += du_dmT.real
|
||||
elif real_or_imag == 'imag':
|
||||
Jtv += -du_dmT.real
|
||||
else:
|
||||
raise Exception('Must be real or imag')
|
||||
# Clean the factorization, clear memory.
|
||||
ATinv.clean()
|
||||
return Jtv
|
||||
|
||||
###################################
|
||||
## 1D problems
|
||||
###################################
|
||||
|
||||
class Problem1D_ePrimSec(BaseNSEMProblem):
|
||||
"""
|
||||
A NSEM problem soving a e formulation and primary/secondary fields decomposion.
|
||||
|
||||
By eliminating the magnetic flux density using
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} \\right)
|
||||
|
||||
|
||||
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
|
||||
|
||||
.. math ::
|
||||
\\left(\mathbf{C}^T \mathbf{M^e_{\mu^{-1}}} \mathbf{C} + i \omega \mathbf{M^f_\sigma}] \mathbf{e}_{s} =& i \omega \mathbf{M^f_{\delta \sigma}} \mathbf{e}_{p}
|
||||
which we solve for \\\(\\\mathbf{e_s}\\\). The total field \\\mathbf{e}\\ = \\\mathbf{e_p}\\ + \\\mathbf{e_s}\\.
|
||||
|
||||
The primary field is estimated from a background model (commonly half space ).
|
||||
|
||||
|
||||
"""
|
||||
|
||||
# From FDEMproblem: Used to project the fields. Currently not used for NSEMproblem.
|
||||
_solutionType = 'e_1dSolution'
|
||||
_formulation = 'EF'
|
||||
fieldsPair = Fields1D_ePrimSec
|
||||
|
||||
# Initiate properties
|
||||
_sigmaPrimary = None
|
||||
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseNSEMProblem.__init__(self, mesh, **kwargs)
|
||||
# self._sigmaPrimary = sigmaPrimary
|
||||
@property
|
||||
def MeMui(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MeMui', None) is None:
|
||||
self._MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
|
||||
return self._MeMui
|
||||
|
||||
@property
|
||||
def MfSigma(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MfSigma', None) is None:
|
||||
self._MfSigma = self.mesh.getFaceInnerProduct(self.curModel.sigma)
|
||||
return self._MfSigma
|
||||
|
||||
@property
|
||||
def sigmaPrimary(self):
|
||||
"""
|
||||
A background model, use for the calculation of the primary fields.
|
||||
|
||||
"""
|
||||
return self._sigmaPrimary
|
||||
|
||||
@sigmaPrimary.setter
|
||||
def sigmaPrimary(self, val):
|
||||
# Note: TODO add logic for val, make sure it is the correct size.
|
||||
self._sigmaPrimary = val
|
||||
|
||||
def getA(self, freq):
|
||||
"""
|
||||
Function to get the A matrix.
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: A
|
||||
"""
|
||||
|
||||
# Note: need to use the code above since in the 1D problem I want
|
||||
# e to live on Faces(nodes) and h on edges(cells). Might need to rethink this
|
||||
# Possible that _fieldType and _eqLocs can fix this
|
||||
MeMui = self.MeMui
|
||||
MfSigma = self.MfSigma
|
||||
C = self.mesh.nodalGrad
|
||||
# Make A
|
||||
A = C.T*MeMui*C + 1j*omega(freq)*MfSigma
|
||||
# Either return full or only the inner part of A
|
||||
return A
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
"""
|
||||
The derivative of A wrt sigma
|
||||
"""
|
||||
|
||||
dsig_dm = self.curModel.sigmaDeriv
|
||||
MeMui = self.MeMui
|
||||
#
|
||||
u_src = u['e_1dSolution']
|
||||
dMfSigma_dm = self.mesh.getFaceInnerProductDeriv(self.curModel.sigma)(u_src) * self.curModel.sigmaDeriv
|
||||
if adjoint:
|
||||
return 1j * omega(freq) * ( dMfSigma_dm.T * v )
|
||||
# Note: output has to be nN/nF, not nC/nE.
|
||||
# v should be nC
|
||||
return 1j * omega(freq) * ( dMfSigma_dm * v )
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Function to return the right hand side for the system.
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray (nF, 1), numpy.ndarray (nF, 1)
|
||||
:return: RHS for 1 polarizations, primary fields
|
||||
"""
|
||||
|
||||
# Get sources for the frequncy(polarizations)
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
S_e = Src.S_e(self)
|
||||
return -1j * omega(freq) * S_e
|
||||
|
||||
def getRHSDeriv_m(self, freq, v, adjoint=False):
|
||||
"""
|
||||
The derivative of the RHS wrt sigma
|
||||
"""
|
||||
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
S_eDeriv = Src.S_eDeriv_m(self, v, adjoint)
|
||||
return -1j * omega(freq) * S_eDeriv
|
||||
|
||||
def fields(self, m):
|
||||
'''
|
||||
Function to calculate all the fields for the model m.
|
||||
|
||||
:param np.ndarray (nC,) m: Conductivity model
|
||||
'''
|
||||
# Set the current model
|
||||
self.curModel = m
|
||||
# Make the fields object
|
||||
F = self.fieldsPair(self.mesh, self.survey)
|
||||
# Loop over the frequencies
|
||||
for freq in self.survey.freqs:
|
||||
if self.verbose:
|
||||
startTime = time.time()
|
||||
print 'Starting work for {:.3e}'.format(freq)
|
||||
sys.stdout.flush()
|
||||
A = self.getA(freq)
|
||||
rhs = self.getRHS(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
e_s = Ainv * rhs
|
||||
|
||||
# Store the fields
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
# NOTE: only store the e_solution(secondary), all other components calculated in the fields object
|
||||
F[Src, 'e_1dSolution'] = e_s[:,-1] # Only storing the yx polarization as 1d
|
||||
|
||||
# Note curl e = -iwb so b = -curl e /iw
|
||||
# b = -( self.mesh.nodalGrad * e )/( 1j*omega(freq) )
|
||||
# F[Src, 'b_1d'] = b[:,1]
|
||||
if self.verbose:
|
||||
print 'Ran for {:f} seconds'.format(time.time()-startTime)
|
||||
sys.stdout.flush()
|
||||
return F
|
||||
|
||||
# Note this is not fully functional.
|
||||
# Missing:
|
||||
# Fields class corresponding to the fields
|
||||
# Update Jvec and Jtvec to include all the derivatives components
|
||||
# Other things ...
|
||||
class Problem1D_eTotal(BaseNSEMProblem):
|
||||
"""
|
||||
A NSEM problem solving a e formulation and a Total bondary domain decompostion.
|
||||
|
||||
Solves the equation:
|
||||
|
||||
Math:
|
||||
Have to do this...
|
||||
Not implement correctly.......
|
||||
"""
|
||||
|
||||
# From FDEMproblem: Used to project the fields. Currently not used for NSEMproblem.
|
||||
_solutionType = 'e_1dSolution'
|
||||
_formulation = 'EF'
|
||||
# fieldsPair = Fields1D_eTotal
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseNSEMProblem.__init__(self, mesh, **kwargs)
|
||||
@property
|
||||
def MeMui(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MeMui', None) is None:
|
||||
self._MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
|
||||
return self._MeMui
|
||||
|
||||
@property
|
||||
def MfSigma(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MfSigma', None) is None:
|
||||
self._MfSigma = self.mesh.getFaceInnerProduct(self.curModel.sigma)
|
||||
return self._MfSigma
|
||||
|
||||
def getA(self, freq, full=False):
|
||||
"""
|
||||
Function to get the A matrix.
|
||||
|
||||
:param float freq: Frequency
|
||||
:param logic full: Return full A or the inner part
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: A
|
||||
"""
|
||||
|
||||
MeMui = self.MeMui
|
||||
MfSigma = self.MfSigma
|
||||
# Note: need to use the code above since in the 1D problem I want
|
||||
# e to live on Faces(nodes) and h on edges(cells). Might need to rethink this
|
||||
# Possible that _fieldType and _eqLocs can fix this
|
||||
# MeMui = self.MfMui
|
||||
# MfSigma = self.MfSigma
|
||||
C = self.mesh.nodalGrad
|
||||
# Make A
|
||||
A = C.T*MeMui*C + 1j*omega(freq)*MfSigma
|
||||
# Either return full or only the inner part of A
|
||||
if full:
|
||||
return A
|
||||
else:
|
||||
return A[1:-1,1:-1]
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
raise NotImplementedError('getADeriv is not implemented')
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Function to return the right hand side for the system.
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray (nE, 2), numpy.ndarray (nE, 2)
|
||||
:return: RHS for both polarizations, primary fields
|
||||
"""
|
||||
# Get sources for the frequency
|
||||
# NOTE: Need to use the source information, doesn't really apply in 1D
|
||||
src = self.survey.getSrcByFreq(freq)
|
||||
# Get the full A
|
||||
A = self.getA(freq,full=True)
|
||||
# Define the outer part of the solution matrix
|
||||
Aio = A[1:-1,[0,-1]]
|
||||
Ed, Eu, Hd, Hu = getEHfields(self.mesh,self.curModel.sigma,freq,self.mesh.vectorNx)
|
||||
Etot = (Ed + Eu)
|
||||
sourceAmp = 1.0
|
||||
Etot = ((Etot/Etot[-1])*sourceAmp) # Scale the fields to be equal to sourceAmp at the top
|
||||
## Note: The analytic solution is derived with e^iwt
|
||||
eBC = np.r_[Etot[0],Etot[-1]]
|
||||
# The right hand side
|
||||
|
||||
return -Aio*eBC, eBC
|
||||
|
||||
def getRHSderiv_m(self, freq, backSigma, u, v, adjoint=False):
|
||||
raise NotImplementedError('getRHSDeriv not implemented yet')
|
||||
return None
|
||||
|
||||
def fields(self, m):
|
||||
'''
|
||||
Function to calculate all the fields for the model m.
|
||||
|
||||
:param np.ndarray (nC,) m: Conductivity model
|
||||
:param np.ndarray (nC,) m_back: Background conductivity model
|
||||
'''
|
||||
|
||||
|
||||
self.curModel = m
|
||||
# RHS, CalcFields = self.getRHS(freq,m_back), self.calcFields
|
||||
|
||||
F = Fields1D_eTotal(self.mesh, self.survey)
|
||||
for freq in self.survey.freqs:
|
||||
if self.verbose:
|
||||
startTime = time.time()
|
||||
print 'Starting work for {:.3e}'.format(freq)
|
||||
sys.stdout.flush()
|
||||
A = self.getA(freq)
|
||||
rhs, e_o = self.getRHS(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
e_i = Ainv * rhs
|
||||
e = mkvc(np.r_[e_o[0], e_i, e_o[1]],2)
|
||||
# Store the fields
|
||||
Src = self.survey.getSrcByFreq(freq)
|
||||
# NOTE: only store e fields
|
||||
F[Src, 'e_1dSolution'] = e[:,0]
|
||||
if self.verbose:
|
||||
print 'Ran for {:f} seconds'.format(time.time()-startTime)
|
||||
sys.stdout.flush()
|
||||
return F
|
||||
|
||||
|
||||
###################################
|
||||
## 3D problems
|
||||
###################################
|
||||
class Problem3D_ePrimSec(BaseNSEMProblem):
|
||||
"""
|
||||
A NSEM problem solving a e formulation and a primary/secondary fields decompostion.
|
||||
|
||||
By eliminating the magnetic flux density using
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} \\right)
|
||||
|
||||
|
||||
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
|
||||
|
||||
.. math ::
|
||||
\\left(\mathbf{C}^T \mathbf{M^f_{\mu^{-1}}} \mathbf{C} + i \omega \mathbf{M^e_\sigma}] \mathbf{e}_{s} =& i \omega \mathbf{M^e_{\delta \sigma}} \mathbf{e}_{p}
|
||||
which we solve for \\\(\\\mathbf{e_s}\\\). The total field \\\mathbf{e}\\ = \\\mathbf{e_p}\\ + \\\mathbf{e_s}\\.
|
||||
|
||||
The primary field is estimated from a background model (commonly as a 1D model).
|
||||
|
||||
"""
|
||||
|
||||
# From FDEMproblem: Used to project the fields. Currently not used for NSEMproblem.
|
||||
_solutionType = [ 'e_pxSolution', 'e_pySolution'] # Forces order on the object
|
||||
_formulation = 'EB'
|
||||
fieldsPair = Fields3D_ePrimSec
|
||||
|
||||
# Initiate properties
|
||||
_sigmaPrimary = None
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseNSEMProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
@property
|
||||
def sigmaPrimary(self):
|
||||
"""
|
||||
A background model, use for the calculation of the primary fields.
|
||||
|
||||
"""
|
||||
return self._sigmaPrimary
|
||||
@sigmaPrimary.setter
|
||||
def sigmaPrimary(self, val):
|
||||
# Note: TODO add logic for val, make sure it is the correct size.
|
||||
self._sigmaPrimary = val
|
||||
|
||||
def getA(self, freq):
|
||||
"""
|
||||
Function to get the A system.
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: A
|
||||
"""
|
||||
Mmui = self.MfMui
|
||||
Msig = self.MeSigma
|
||||
C = self.mesh.edgeCurl
|
||||
|
||||
return C.T*Mmui*C + 1j*omega(freq)*Msig
|
||||
|
||||
def getADeriv_m(self, freq, u, v, adjoint=False):
|
||||
"""
|
||||
Calculate the derivative of A wrt m.
|
||||
|
||||
"""
|
||||
# Fix u to be a matrix nE,2
|
||||
# This considers both polarizations and returns a nE,2 matrix for each polarization
|
||||
if adjoint:
|
||||
dMe_dsigV = sp.hstack(( self.MeSigmaDeriv( u['e_pxSolution'] ).T, self.MeSigmaDeriv(u['e_pySolution'] ).T ))*v
|
||||
else:
|
||||
# Need a nE,2 matrix to be returned
|
||||
dMe_dsigV = np.hstack(( mkvc(self.MeSigmaDeriv( u['e_pxSolution'] )*v,2), mkvc( self.MeSigmaDeriv(u['e_pySolution'] )*v,2) ))
|
||||
return 1j * omega(freq) * dMe_dsigV
|
||||
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Function to return the right hand side for the system.
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray (nE, 2), numpy.ndarray (nE, 2)
|
||||
:return: RHS for both polarizations, primary fields
|
||||
"""
|
||||
|
||||
# Get sources for the frequncy(polarizations)
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
S_e = Src.S_e(self)
|
||||
return -1j * omega(freq) * S_e
|
||||
|
||||
def getRHSDeriv_m(self, freq, v, adjoint=False):
|
||||
"""
|
||||
The derivative of the RHS with respect to sigma
|
||||
"""
|
||||
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
S_eDeriv = Src.S_eDeriv_m(self, v, adjoint)
|
||||
return -1j * omega(freq) * S_eDeriv
|
||||
|
||||
def fields(self, m):
|
||||
'''
|
||||
Function to calculate all the fields for the model m.
|
||||
|
||||
:param np.ndarray (nC,) m: Conductivity model
|
||||
'''
|
||||
# Set the current model
|
||||
self.curModel = m
|
||||
|
||||
F = self.fieldsPair(self.mesh, self.survey)
|
||||
for freq in self.survey.freqs:
|
||||
if self.verbose:
|
||||
startTime = time.time()
|
||||
print 'Starting work for {:.3e}'.format(freq)
|
||||
sys.stdout.flush()
|
||||
A = self.getA(freq)
|
||||
rhs = self.getRHS(freq)
|
||||
# Solve the system
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
e_s = Ainv * rhs
|
||||
|
||||
# Store the fields
|
||||
Src = self.survey.getSrcByFreq(freq)[0]
|
||||
# Store the fields
|
||||
# Use self._solutionType
|
||||
F[Src, 'e_pxSolution'] = e_s[:,0]
|
||||
F[Src, 'e_pySolution'] = e_s[:,1]
|
||||
# Note curl e = -iwb so b = -curl/iw
|
||||
|
||||
if self.verbose:
|
||||
print 'Ran for {:f} seconds'.format(time.time()-startTime)
|
||||
sys.stdout.flush()
|
||||
Ainv.clean()
|
||||
return F
|
||||
@@ -11,9 +11,9 @@ import sys
|
||||
### Sources ###
|
||||
#################
|
||||
|
||||
class BaseMTSrc(FDEMBaseSrc):
|
||||
class BaseNSEMSrc(FDEMBaseSrc):
|
||||
'''
|
||||
Sources for the MT problem.
|
||||
Sources for the NSEM problem.
|
||||
Use the SimPEG BaseSrc, since the source fields share properties with the transmitters.
|
||||
|
||||
:param float freq: The frequency of the source
|
||||
@@ -29,28 +29,28 @@ class BaseMTSrc(FDEMBaseSrc):
|
||||
FDEMBaseSrc.__init__(self, rxList)
|
||||
|
||||
# 1D sources
|
||||
class polxy_1DhomotD(BaseMTSrc):
|
||||
class polxy_1DhomotD(BaseNSEMSrc):
|
||||
"""
|
||||
MT source for both polarizations (x and y) for the total Domain.
|
||||
NSEM source for both polarizations (x and y) for the total Domain.
|
||||
|
||||
It calculates fields calculated based on conditions on the boundary of the domain.
|
||||
"""
|
||||
def __init__(self, rxList, freq):
|
||||
BaseMTSrc.__init__(self, rxList, freq)
|
||||
BaseNSEMSrc.__init__(self, rxList, freq)
|
||||
|
||||
|
||||
# TODO: need to add the primary fields calc and source terms into the problem.
|
||||
|
||||
# Need to implement such that it works for all dims.
|
||||
class polxy_1Dprimary(BaseMTSrc):
|
||||
class polxy_1Dprimary(BaseNSEMSrc):
|
||||
"""
|
||||
MT source for both polarizations (x and y) given a 1D primary models.
|
||||
NSEM source for both polarizations (x and y) given a 1D primary models.
|
||||
It assigns fields calculated from the 1D model as fields in the full space of the problem.
|
||||
"""
|
||||
def __init__(self, rxList, freq):
|
||||
# assert mkvc(self.mesh.hz.shape,1) == mkvc(sigma1d.shape,1),'The number of values in the 1D background model does not match the number of vertical cells (hz).'
|
||||
self.sigma1d = None
|
||||
BaseMTSrc.__init__(self, rxList, freq)
|
||||
BaseNSEMSrc.__init__(self, rxList, freq)
|
||||
# Hidden property of the ePrimary
|
||||
self._ePrimary = None
|
||||
|
||||
@@ -86,7 +86,7 @@ class polxy_1Dprimary(BaseMTSrc):
|
||||
Get the electrical field source
|
||||
"""
|
||||
e_p = self.ePrimary(problem)
|
||||
Map_sigma_p = Maps.Vertical1DMap(problem.mesh)
|
||||
Map_sigma_p = Maps.SurjectVertical1D(problem.mesh)
|
||||
sigma_p = Map_sigma_p._transform(self.sigma1d)
|
||||
# Make mass matrix
|
||||
# Note: M(sig) - M(sig_p) = M(sig - sig_p)
|
||||
@@ -128,15 +128,15 @@ class polxy_1Dprimary(BaseMTSrc):
|
||||
# v should be nC size
|
||||
return MsigmaDeriv * v
|
||||
|
||||
class polxy_3Dprimary(BaseMTSrc):
|
||||
class polxy_3Dprimary(BaseNSEMSrc):
|
||||
"""
|
||||
MT source for both polarizations (x and y) given a 3D primary model. It assigns fields calculated from the 1D model
|
||||
NSEM source for both polarizations (x and y) given a 3D primary model. It assigns fields calculated from the 1D model
|
||||
as fields in the full space of the problem.
|
||||
"""
|
||||
def __init__(self, rxList, freq):
|
||||
# assert mkvc(self.mesh.hz.shape,1) == mkvc(sigma1d.shape,1),'The number of values in the 1D background model does not match the number of vertical cells (hz).'
|
||||
self.sigmaPrimary = None
|
||||
BaseMTSrc.__init__(self, rxList, freq)
|
||||
BaseNSEMSrc.__init__(self, rxList, freq)
|
||||
# Hidden property of the ePrimary
|
||||
self._ePrimary = None
|
||||
|
||||
@@ -163,7 +163,7 @@ class polxy_3Dprimary(BaseMTSrc):
|
||||
Get the electrical field source
|
||||
"""
|
||||
e_p = self.ePrimary(problem)
|
||||
Map_sigma_p = Maps.Vertical1DMap(problem.mesh)
|
||||
Map_sigma_p = Maps.SurjectVertical1D(problem.mesh)
|
||||
sigma_p = Map_sigma_p._transform(self.sigma1d)
|
||||
# Make mass matrix
|
||||
# Note: M(sig) - M(sig_p) = M(sig - sig_p)
|
||||
@@ -4,7 +4,7 @@ from SimPEG.EM.Utils import omega
|
||||
from scipy.constants import mu_0
|
||||
from numpy.lib import recfunctions as recFunc
|
||||
from Utils import rec2ndarr
|
||||
import SrcMT
|
||||
import SrcNSEM
|
||||
import sys
|
||||
|
||||
#################
|
||||
@@ -63,9 +63,9 @@ class Rx(SimPEGsurvey.BaseRx):
|
||||
'''
|
||||
Project the fields to natural source data.
|
||||
|
||||
:param SrcMT src: The source of the fields to project
|
||||
:param SrcNSEM src: The source of the fields to project
|
||||
:param SimPEG.Mesh mesh:
|
||||
:param FieldsMT f: Natural source fields object to project
|
||||
:param FieldsNSEM f: Natural source fields object to project
|
||||
'''
|
||||
|
||||
## NOTE: Assumes that e is on t
|
||||
@@ -143,9 +143,9 @@ class Rx(SimPEGsurvey.BaseRx):
|
||||
"""
|
||||
The derivative of the projection wrt u
|
||||
|
||||
:param MTsrc src: MT source
|
||||
:param NSEMsrc src: NSEM source
|
||||
:param TensorMesh mesh: Mesh defining the topology of the problem
|
||||
:param MTfields f: MT fields object of the source
|
||||
:param NSEMfields f: NSEM fields object of the source
|
||||
:param numpy.ndarray v: Random vector of size
|
||||
"""
|
||||
|
||||
@@ -390,12 +390,12 @@ class Rx(SimPEGsurvey.BaseRx):
|
||||
#################
|
||||
class Survey(SimPEGsurvey.BaseSurvey):
|
||||
"""
|
||||
Survey class for MT. Contains all the sources associated with the survey.
|
||||
Survey class for NSEM. Contains all the sources associated with the survey.
|
||||
|
||||
:param list srcList: List of sources associated with the survey
|
||||
|
||||
"""
|
||||
srcPair = SrcMT.BaseMTSrc
|
||||
srcPair = SrcNSEM.BaseNSEMSrc
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
# Sort these by frequency
|
||||
@@ -427,15 +427,15 @@ class Survey(SimPEGsurvey.BaseSurvey):
|
||||
assert freq in self._freqDict, "The requested frequency is not in this survey."
|
||||
return self._freqDict[freq]
|
||||
|
||||
def eval(self, u):
|
||||
def eval(self, f):
|
||||
data = Data(self)
|
||||
for src in self.srcList:
|
||||
sys.stdout.flush()
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.eval(src, self.mesh, u)
|
||||
data[src, rx] = rx.eval(src, self.mesh, f)
|
||||
return data
|
||||
|
||||
def evalDeriv(self, u):
|
||||
def evalDeriv(self, f):
|
||||
raise Exception('Use Transmitters to project fields deriv.')
|
||||
|
||||
#################
|
||||
@@ -443,7 +443,7 @@ class Survey(SimPEGsurvey.BaseSurvey):
|
||||
#################
|
||||
class Data(SimPEGsurvey.Data):
|
||||
'''
|
||||
Data class for MTdata. Stores the data vector indexed by the survey.
|
||||
Data class for NSEMdata. Stores the data vector indexed by the survey.
|
||||
|
||||
:param SimPEG survey object survey:
|
||||
:param v vector of the data in order matching of the survey
|
||||
@@ -461,7 +461,7 @@ class Data(SimPEGsurvey.Data):
|
||||
|
||||
def toRecArray(self,returnType='RealImag'):
|
||||
'''
|
||||
Function that returns a numpy.recarray for a SimpegMT impedance data object.
|
||||
Function that returns a numpy.recarray for a SimpegNSEM impedance data object.
|
||||
|
||||
:param str returnType: Switches between returning a rec array where the impedance is split to real and imaginary ('RealImag') or is a complex ('Complex')
|
||||
|
||||
@@ -483,7 +483,7 @@ class Data(SimPEGsurvey.Data):
|
||||
locs = np.hstack((np.array([[0.0]]),locs))
|
||||
tArrRec = np.concatenate((src.freq*np.ones((locs.shape[0],1)),locs,np.nan*np.ones((locs.shape[0],12))),axis=1).view(dtRI)
|
||||
# np.array([(src.freq,rx.locs[0,0],rx.locs[0,1],rx.locs[0,2],np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ) for rx in src.rxList],dtype=dtRI)
|
||||
# Get the type and the value for the DataMT object as a list
|
||||
# Get the type and the value for the DataNSEM object as a list
|
||||
typeList = [[rx.rxType.replace('z1d','zyx'),self[src,rx]] for rx in src.rxList]
|
||||
# Insert the values to the temp array
|
||||
for nr,(key,val) in enumerate(typeList):
|
||||
@@ -517,17 +517,17 @@ class Data(SimPEGsurvey.Data):
|
||||
@classmethod
|
||||
def fromRecArray(cls, recArray, srcType='primary'):
|
||||
"""
|
||||
Class method that reads in a numpy record array to MTdata object.
|
||||
Class method that reads in a numpy record array to NSEMdata object.
|
||||
|
||||
Only imports the impedance data.
|
||||
|
||||
"""
|
||||
if srcType=='primary':
|
||||
src = SrcMT.polxy_1Dprimary
|
||||
src = SrcNSEM.polxy_1Dprimary
|
||||
elif srcType=='total':
|
||||
src = SrcMT.polxy_1DhomotD
|
||||
src = SrcNSEM.polxy_1DhomotD
|
||||
else:
|
||||
raise NotImplementedError('{:s} is not a valid source type for MTdata')
|
||||
raise NotImplementedError('{:s} is not a valid source type for NSEMdata')
|
||||
|
||||
# Find all the frequencies in recArray
|
||||
uniFreq = np.unique(recArray['freq'])
|
||||
@@ -3,7 +3,7 @@
|
||||
import numpy as np, SimPEG as simpeg
|
||||
from scipy.constants import mu_0, epsilon_0 as eps_0
|
||||
|
||||
def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
|
||||
def getEHfields(m1d,sigma,freq,zd,scaleUD=True,scaleValue=1):
|
||||
'''Analytic solution for MT 1D layered earth. Returns E and H fields.
|
||||
|
||||
:param SimPEG.mesh, object m1d: Mesh object with the 1D spatial information.
|
||||
@@ -12,7 +12,7 @@ def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
|
||||
:param numpy array, vector zd: location to calculate EH fields at
|
||||
:param bollean, scaleUD: scales the output to be 1 at the top, increases numeracal stability.
|
||||
|
||||
Assumes a halfspace with the same conductive as the last cell below.
|
||||
Assumes a halfspace with the same conductive as the deepest cell.
|
||||
|
||||
'''
|
||||
# Note add an error check for the mesh and sigma are the same size.
|
||||
@@ -29,7 +29,7 @@ def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
|
||||
|
||||
# Initiate the propagation matrix, in the order down up.
|
||||
UDp = np.zeros((2,m1d.nC+1),dtype=complex)
|
||||
UDp[1,0] = 1. # Set the wave amplitude as 1 into the half-space at the bottom of the mesh
|
||||
UDp[1,0] = scaleValue # Set the wave amplitude as 1 into the half-space at the bottom of the mesh
|
||||
# Loop over all the layers, starting at the bottom layer
|
||||
for lnr, h in enumerate(m1d.hx): # lnr-number of layer, h-thickness of the layer
|
||||
# Calculate
|
||||
@@ -38,9 +38,9 @@ def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
|
||||
# Build the propagation matrix
|
||||
|
||||
# Convert fields to down/up going components in layer below current layer
|
||||
Pj1 = np.array([[1,1],[yp1,-yp1]])
|
||||
Pj1 = np.array([[1,1],[yp1,-yp1]],dtype=complex)
|
||||
# Convert fields to down/up going components in current layer
|
||||
Pjinv = 1./2*np.array([[1,zp],[1,-zp]])
|
||||
Pjinv = 1./2*np.array([[1,zp],[1,-zp]],dtype=complex)
|
||||
# Propagate down and up components through the current layer
|
||||
elamh = np.array([[np.exp(-1j*k[lnr+1]*h),0],[0,np.exp(1j*k[lnr+1]*h)]])
|
||||
|
||||
@@ -48,7 +48,14 @@ def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
|
||||
UDp[:,lnr+1] = elamh.dot(Pjinv.dot(Pj1)).dot(UDp[:,lnr])
|
||||
|
||||
if scaleUD:
|
||||
UDp[:,lnr+1::-1] = UDp[:,lnr+1::-1]/UDp[1,lnr+1]
|
||||
# Scale the values such that 1 at the top
|
||||
scaleVal = UDp[:,lnr+1::-1]/UDp[1,lnr+1]
|
||||
if np.any(np.isnan(scaleVal)):
|
||||
# If there is a nan (thickness very great), rebuild the move up cell
|
||||
scaleVal = np.zeros_like(UDp[:,lnr+1::-1],dtype=complex)
|
||||
scaleVal[1,0] = scaleValue
|
||||
|
||||
UDp[:,lnr+1::-1] = scaleVal
|
||||
|
||||
# Calculate the fields
|
||||
Ed = np.empty((zd.size,),dtype=complex)
|
||||
@@ -0,0 +1,5 @@
|
||||
from MT1Dsolutions import get1DEfields # Add the names of the functions
|
||||
from MT1Danalytic import getEHfields, getImpedance
|
||||
from dataUtils import *
|
||||
from ediFilesUtils import *
|
||||
from testUtils import *
|
||||
@@ -5,25 +5,25 @@ import numpy.lib.recfunctions as recFunc
|
||||
from scipy.constants import mu_0
|
||||
from scipy import interpolate as sciint
|
||||
|
||||
def getAppRes(MTdata):
|
||||
def getAppRes(NSEMdata):
|
||||
# Make impedance
|
||||
zList = []
|
||||
for src in MTdata.survey.srcList:
|
||||
for src in NSEMdata.survey.srcList:
|
||||
zc = [src.freq]
|
||||
for rx in src.rxList:
|
||||
if 'i' in rx.rxType:
|
||||
m=1j
|
||||
else:
|
||||
m = 1
|
||||
zc.append(m*MTdata[src,rx])
|
||||
zc.append(m*NSEMdata[src,rx])
|
||||
zList.append(zc)
|
||||
return [appResPhs(zList[i][0],np.sum(zList[i][1:3])) for i in np.arange(len(zList))]
|
||||
|
||||
def rotateData(MTdata,rotAngle):
|
||||
def rotateData(NSEMdata,rotAngle):
|
||||
'''
|
||||
Function that rotates clockwist by rotAngle (- negative for a counter-clockwise rotation)
|
||||
'''
|
||||
recData = MTdata.toRecArray('Complex')
|
||||
recData = NSEMdata.toRecArray('Complex')
|
||||
impData = rec2ndarr(recData[['zxx','zxy','zyx','zyy']],complex)
|
||||
# Make the rotation matrix
|
||||
# c,s,zxx,zxy,zyx,zyy = sympy.symbols('c,s,zxx,zxy,zyx,zyy')
|
||||
@@ -40,8 +40,8 @@ def rotateData(MTdata,rotAngle):
|
||||
for nr,comp in enumerate(['zxx','zxy','zyx','zyy']):
|
||||
outRec[comp] = rotData[:,nr]
|
||||
|
||||
from SimPEG import MT
|
||||
return MT.Data.fromRecArray(outRec)
|
||||
from SimPEG import NSEM
|
||||
return NSEM.Data.fromRecArray(outRec)
|
||||
|
||||
|
||||
def appResPhs(freq,z):
|
||||
@@ -57,10 +57,10 @@ def rec2ndarr(x,dt=float):
|
||||
return x.view((dt, len(x.dtype.names)))
|
||||
|
||||
def makeAnalyticSolution(mesh,model,elev,freqs):
|
||||
from SimPEG import MT
|
||||
from SimPEG import NSEM
|
||||
data1D = []
|
||||
for freq in freqs:
|
||||
anaEd, anaEu, anaHd, anaHu = MT.Utils.MT1Danalytic.getEHfields(mesh,model,freq,elev)
|
||||
anaEd, anaEu, anaHd, anaHu = NSEM.Utils.MT1Danalytic.getEHfields(mesh,model,freq,elev)
|
||||
anaE = anaEd+anaEu
|
||||
anaH = anaHd+anaHu
|
||||
|
||||
@@ -71,7 +71,7 @@ def makeAnalyticSolution(mesh,model,elev,freqs):
|
||||
return dataRec
|
||||
|
||||
def plotMT1DModelData(problem,models,symList=None):
|
||||
from SimPEG import MT
|
||||
from SimPEG import NSEM
|
||||
# Setup the figure
|
||||
fontSize = 15
|
||||
|
||||
@@ -79,7 +79,7 @@ def plotMT1DModelData(problem,models,symList=None):
|
||||
axM = fig.add_axes([0.075,.1,.25,.875])
|
||||
axM.set_xlabel('Resistivity [Ohm*m]',fontsize=fontSize)
|
||||
axM.set_xlim(1e-1,1e5)
|
||||
axM.set_ylim(-10000,5000)
|
||||
# axM.set_ylim(-10000,5000)
|
||||
axM.set_ylabel('Depth [km]',fontsize=fontSize)
|
||||
axR = fig.add_axes([0.42,.575,.5,.4])
|
||||
axR.set_xscale('log')
|
||||
@@ -132,38 +132,94 @@ def plotMT1DModelData(problem,models,symList=None):
|
||||
freq = simpeg.mkvc(data1D['freq'],2)
|
||||
res, phs = appResPhs(freq,allData)
|
||||
|
||||
stdCol = 'gray'
|
||||
axRtw = axR.twinx()
|
||||
axRtw.set_ylabel('Std of log10',color=stdCol)
|
||||
[(t.set_color(stdCol), t.set_rotation(-45)) for t in axRtw.get_yticklabels()]
|
||||
axPtw = axP.twinx()
|
||||
axPtw.set_ylabel('Std ',color=stdCol)
|
||||
[t.set_color(stdCol) for t in axPtw.get_yticklabels()]
|
||||
axRtw.plot(freq, np.std(np.log10(res),1),'--',color=stdCol)
|
||||
axPtw.plot(freq, np.std(phs,1),'--',color=stdCol)
|
||||
if False:
|
||||
stdCol = 'gray'
|
||||
axRtw = axR.twinx()
|
||||
axRtw.set_ylabel('Std of log10',color=stdCol)
|
||||
[(t.set_color(stdCol), t.set_rotation(-45)) for t in axRtw.get_yticklabels()]
|
||||
axPtw = axP.twinx()
|
||||
axPtw.set_ylabel('Std ',color=stdCol)
|
||||
[t.set_color(stdCol) for t in axPtw.get_yticklabels()]
|
||||
axRtw.plot(freq, np.std(np.log10(res),1),'--',color=stdCol)
|
||||
axPtw.plot(freq, np.std(phs,1),'--',color=stdCol)
|
||||
|
||||
# Fix labels and ticks
|
||||
|
||||
yMtick = [l/1000 for l in axM.get_yticks().tolist()]
|
||||
axM.set_yticklabels(yMtick)
|
||||
# yMtick = [l/1000 for l in axM.get_yticks().tolist()]
|
||||
# axM.set_yticklabels(yMtick)
|
||||
[ l.set_rotation(90) for l in axM.get_yticklabels()]
|
||||
[ l.set_rotation(90) for l in axR.get_yticklabels()]
|
||||
[(t.set_color(stdCol), t.set_rotation(-45)) for t in axRtw.get_yticklabels()]
|
||||
[t.set_color(stdCol) for t in axPtw.get_yticklabels()]
|
||||
# [(t.set_color(stdCol), t.set_rotation(-45)) for t in axRtw.get_yticklabels()]
|
||||
# [t.set_color(stdCol) for t in axPtw.get_yticklabels()]
|
||||
for ax in [axM,axR,axP]:
|
||||
ax.xaxis.set_tick_params(labelsize=fontSize)
|
||||
ax.yaxis.set_tick_params(labelsize=fontSize)
|
||||
return fig
|
||||
|
||||
def plotImpAppRes(dataArrays,plotLoc,textStr=[]):
|
||||
''' Plots amplitude impedance and phase'''
|
||||
# fig = plt.figure(1,(7, 7))
|
||||
import plotDataTypes as pDt
|
||||
# axes = ImageGrid(fig, (0.05,0.05,0.875,0.875),nrows_ncols = (2, 2),axes_pad = 0.25,add_all=True,share_all=True,label_mode = "L")
|
||||
# Make the figure and axes
|
||||
fig,axT=plt.subplots(2,2,sharex=True)
|
||||
axes = axT.ravel()
|
||||
fig.set_size_inches((13.5,7.0))
|
||||
fig.suptitle('{:s}\nStation at: {:.1f}x ; {:.1f}y'.format(textStr,plotLoc[0],plotLoc[1]))
|
||||
# Have to deal with axes
|
||||
# Set log
|
||||
for ax in axes.ravel():
|
||||
ax.set_xscale('log')
|
||||
|
||||
axes[0].invert_xaxis()
|
||||
axes[0].set_yscale('log')
|
||||
axes[2].set_yscale('log')
|
||||
# Set labels
|
||||
axes[2].set_xlabel('Frequency [Hz]')
|
||||
axes[3].set_xlabel('Frequency [Hz]')
|
||||
axes[0].set_ylabel('Apperent resistivity [Ohm m]')
|
||||
axes[1].set_ylabel('Apperent phase [degrees]')
|
||||
axes[1].set_ylim(-180,180)
|
||||
axes[2].set_ylabel('Impedance amplitude [V/A]')
|
||||
axes[3].set_ylim(-180,180)
|
||||
axes[3].set_ylabel('Impedance angle [degrees]')
|
||||
|
||||
|
||||
# Plot the data
|
||||
for nr,dataArray in enumerate(dataArrays):
|
||||
if nr==1:
|
||||
parSym = '*'
|
||||
else:
|
||||
parSym = 's'
|
||||
# app res
|
||||
pDt.plotIsoStaImpedance(axes[0],plotLoc,dataArray,'zxy',par='res',pSym=parSym)
|
||||
pDt.plotIsoStaImpedance(axes[0],plotLoc,dataArray,'zyx',par='res',pSym=parSym)
|
||||
# app phs
|
||||
pDt.plotIsoStaImpedance(axes[1],plotLoc,dataArray,'zxy',par='phs',pSym=parSym)
|
||||
pDt.plotIsoStaImpedance(axes[1],plotLoc,dataArray,'zyx',par='phs',pSym=parSym)
|
||||
# imp abs
|
||||
pDt.plotIsoStaImpedance(axes[2],plotLoc,dataArray,'zxx',par='abs',pSym=parSym)
|
||||
pDt.plotIsoStaImpedance(axes[2],plotLoc,dataArray,'zxy',par='abs',pSym=parSym)
|
||||
pDt.plotIsoStaImpedance(axes[2],plotLoc,dataArray,'zyx',par='abs',pSym=parSym)
|
||||
pDt.plotIsoStaImpedance(axes[2],plotLoc,dataArray,'zyy',par='abs',pSym=parSym)
|
||||
# imp abs
|
||||
pDt.plotIsoStaImpedance(axes[3],plotLoc,dataArray,'zxx',par='phs',pSym=parSym)
|
||||
pDt.plotIsoStaImpedance(axes[3],plotLoc,dataArray,'zxy',par='phs',pSym=parSym)
|
||||
pDt.plotIsoStaImpedance(axes[3],plotLoc,dataArray,'zyx',par='phs',pSym=parSym)
|
||||
pDt.plotIsoStaImpedance(axes[3],plotLoc,dataArray,'zyy',par='phs',pSym=parSym)
|
||||
|
||||
return fig,axes
|
||||
|
||||
|
||||
def printTime():
|
||||
import time
|
||||
print time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())
|
||||
|
||||
def convert3Dto1Dobject(MTdata,rxType3D='zyx'):
|
||||
from SimPEG import MT
|
||||
def convert3Dto1Dobject(NSEMdata,rxType3D='zyx'):
|
||||
from SimPEG import NSEM
|
||||
# Find the unique locations
|
||||
# Need to find the locations
|
||||
recDataTemp = MTdata.toRecArray()
|
||||
recDataTemp = NSEMdata.toRecArray()
|
||||
# Check if survey.std has been assigned.
|
||||
## NEED TO: write this...
|
||||
# Calculte and add the DET of the tensor to the recArray
|
||||
@@ -185,24 +241,24 @@ def convert3Dto1Dobject(MTdata,rxType3D='zyx'):
|
||||
# Make the receiver list
|
||||
rx1DList = []
|
||||
for rxType in ['z1dr','z1di']:
|
||||
rx1DList.append(MT.Rx(simpeg.mkvc(loc,2).T,rxType))
|
||||
rx1DList.append(NSEM.Rx(simpeg.mkvc(loc,2).T,rxType))
|
||||
# Source list
|
||||
locrecData = recData[np.sqrt(np.sum( (rec2ndarr(recData[['x','y','z']]).data - loc )**2,axis=1)) < 1e-5]
|
||||
dat1DList = []
|
||||
src1DList = []
|
||||
for freq in locrecData['freq']:
|
||||
src1DList.append(MT.SrcMT.src_polxy_1Dprimary(rx1DList,freq))
|
||||
src1DList.append(NSEM.SrcNSEM.src_polxy_1Dprimary(rx1DList,freq))
|
||||
for comp in ['r','i']:
|
||||
dat1DList.append( corr * locrecData[rxType3D+comp][locrecData['freq']== freq].data )
|
||||
|
||||
# Make the survey
|
||||
sur1D = MT.Survey(src1DList)
|
||||
sur1D = NSEM.Survey(src1DList)
|
||||
|
||||
# Make the data
|
||||
dataVec = np.hstack(dat1DList)
|
||||
dat1D = MT.Data(sur1D,dataVec)
|
||||
dat1D = NSEM.Data(sur1D,dataVec)
|
||||
sur1D.dobs = dataVec
|
||||
# Need to take MTdata.survey.std and split it as well.
|
||||
# Need to take NSEMdata.survey.std and split it as well.
|
||||
std=0.05
|
||||
sur1D.std = np.abs(sur1D.dobs*std) #+ 0.01*np.linalg.norm(sur1D.dobs)
|
||||
mtData1DList.append(dat1D)
|
||||
@@ -210,29 +266,29 @@ def convert3Dto1Dobject(MTdata,rxType3D='zyx'):
|
||||
# Return the the list of data.
|
||||
return mtData1DList
|
||||
|
||||
def resampleMTdataAtFreq(MTdata,freqs):
|
||||
def resampleNSEMdataAtFreq(NSEMdata,freqs):
|
||||
"""
|
||||
Function to resample MTdata at set of frequencies
|
||||
Function to resample NSEMdata at set of frequencies
|
||||
|
||||
"""
|
||||
from SimPEG import MT
|
||||
from SimPEG import NSEM
|
||||
# Make a rec array
|
||||
MTrec = MTdata.toRecArray().data
|
||||
NSEMrec = NSEMdata.toRecArray().data
|
||||
|
||||
# Find unique locations
|
||||
uniLoc = np.unique(MTrec[['x','y','z']])
|
||||
uniFreq = MTdata.survey.freqs
|
||||
uniLoc = np.unique(NSEMrec[['x','y','z']])
|
||||
uniFreq = NSEMdata.survey.freqs
|
||||
# Get the comps
|
||||
dNames = MTrec.dtype
|
||||
dNames = NSEMrec.dtype
|
||||
|
||||
# Loop over all the locations and interpolate
|
||||
for loc in uniLoc:
|
||||
# Find the index of the station
|
||||
ind = np.sqrt(np.sum((rec2ndarr(MTrec[['x','y','z']]) - rec2ndarr(loc))**2,axis=1)) < 1. # Find dist of 1 m accuracy
|
||||
ind = np.sqrt(np.sum((rec2ndarr(NSEMrec[['x','y','z']]) - rec2ndarr(loc))**2,axis=1)) < 1. # Find dist of 1 m accuracy
|
||||
# Make a temporary recArray and interpolate all the components
|
||||
tArrRec = np.concatenate((simpeg.mkvc(freqs,2),np.ones((len(freqs),1))*rec2ndarr(loc),np.nan*np.ones((len(freqs),12))),axis=1).view(dNames)
|
||||
for comp in ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi','tzxr','tzxi','tzyr','tzyi']:
|
||||
int1d = sciint.interp1d(MTrec[ind]['freq'],MTrec[ind][comp],bounds_error=False)
|
||||
int1d = sciint.interp1d(NSEMrec[ind]['freq'],NSEMrec[ind][comp],bounds_error=False)
|
||||
tArrRec[comp] = simpeg.mkvc(int1d(freqs),2)
|
||||
|
||||
# Join together
|
||||
@@ -241,5 +297,5 @@ def resampleMTdataAtFreq(MTdata,freqs):
|
||||
except NameError as e:
|
||||
outRecArr = tArrRec
|
||||
|
||||
# Make the MTdata and return
|
||||
return MT.Data.fromRecArray(outRecArr)
|
||||
# Make the NSEMdata and return
|
||||
return NSEM.Data.fromRecArray(outRecArr)
|
||||
@@ -2,22 +2,21 @@
|
||||
from SimPEG import mkvc
|
||||
from scipy.constants import mu_0
|
||||
from numpy.lib import recfunctions as recFunc
|
||||
from SimPEG.MT.Utils.dataUtils import rec2ndarr
|
||||
from SimPEG.NSEM.Utils.dataUtils import rec2ndarr
|
||||
|
||||
# Import modules
|
||||
import numpy as np
|
||||
import os, sys, re
|
||||
try:
|
||||
import osr
|
||||
except ImportError as e:
|
||||
print 'Could not import osr, missing the gdal package'
|
||||
pass
|
||||
|
||||
|
||||
class EDIimporter:
|
||||
"""
|
||||
A class to import EDIfiles.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# Define data converters
|
||||
_impUnitEDI2SI = 4*np.pi*1e-4 # Convert Z[mV/km/nT] (as in EDI)to Z[V/A] SI unit
|
||||
_impUnitSI2EDI = 1./_impUnitEDI2SI # ConvertZ[V/A] SI unit to Z[mV/km/nT] (as in EDI)
|
||||
|
||||
@@ -26,8 +25,8 @@ class EDIimporter:
|
||||
comps = None
|
||||
|
||||
# Hidden properties
|
||||
_outEPSG = None
|
||||
_2out = None
|
||||
_outEPSG = None # Project info
|
||||
_2out = None # The projection operator
|
||||
|
||||
|
||||
def __init__(self, EDIfilesList, compList=None, outEPSG=None):
|
||||
@@ -113,6 +112,12 @@ class EDIimporter:
|
||||
# nOutData=length(obj.data);
|
||||
# obj.data(nOutData+1:nOutData+length(TEMP.data),:) = TEMP.data;
|
||||
def _transfromPoints(self,longD,latD):
|
||||
# Import the coordinate projections
|
||||
try:
|
||||
import osr
|
||||
except ImportError as e:
|
||||
print 'Could not import osr, missing the gdal package\nCan not project coordinates'
|
||||
raise e
|
||||
# Coordinates convertor
|
||||
if self._2out is None:
|
||||
src = osr.SpatialReference()
|
||||
@@ -12,7 +12,7 @@ def homo1DModelSource(mesh,freq,sigma_1d):
|
||||
|
||||
'''
|
||||
# import
|
||||
from SimPEG.MT.Utils import get1DEfields
|
||||
from SimPEG.NSEM.Utils import get1DEfields
|
||||
# Get a 1d solution for a halfspace background
|
||||
if mesh.dim == 1:
|
||||
mesh1d = mesh
|
||||
@@ -77,7 +77,7 @@ def analytic1DModelSource(mesh,freq,sigma_1d):
|
||||
|
||||
'''
|
||||
# import
|
||||
from SimPEG.MT.Utils import getEHfields
|
||||
from SimPEG.NSEM.Utils import getEHfields
|
||||
# Get a 1d solution for a halfspace background
|
||||
if mesh.dim == 1:
|
||||
mesh1d = mesh
|
||||
@@ -0,0 +1,198 @@
|
||||
import unittest
|
||||
import sys
|
||||
from scipy.constants import mu_0
|
||||
import SimPEG as simpeg
|
||||
|
||||
from SimPEG.Utils import meshTensor
|
||||
import numpy as np
|
||||
|
||||
np.random.seed(1100)
|
||||
# Define the tolerances
|
||||
TOLr = 5e-2
|
||||
TOLp = 5e-2
|
||||
|
||||
|
||||
def getAppResPhs(NSEMdata):
|
||||
# Make impedance
|
||||
from SimPEG.NSEM.Utils import appResPhs
|
||||
zList = []
|
||||
for src in NSEMdata.survey.srcList:
|
||||
zc = [src.freq]
|
||||
for rx in src.rxList:
|
||||
if 'i' in rx.rxType:
|
||||
m=1j
|
||||
else:
|
||||
m = 1
|
||||
zc.append(m*NSEMdata[src,rx])
|
||||
zList.append(zc)
|
||||
return [appResPhs(zList[i][0],np.sum(zList[i][1:3])) for i in np.arange(len(zList))]
|
||||
|
||||
|
||||
def setup1DSurvey(sigmaHalf,tD=True,structure=False):
|
||||
from SimPEG import NSEM
|
||||
# Frequency
|
||||
nFreq = 33
|
||||
freqs = np.logspace(3,-3,nFreq)
|
||||
# Make the mesh
|
||||
ct = 5
|
||||
air = meshTensor([(ct,25,1.3)])
|
||||
# coreT0 = meshTensor([(ct,15,1.2)])
|
||||
# coreT1 = np.kron(meshTensor([(coreT0[-1],15,1.3)]),np.ones((7,)))
|
||||
core = np.concatenate( ( np.kron(meshTensor([(ct,15,-1.2)]),np.ones((10,))) , meshTensor([(ct,20)]) ) )
|
||||
bot = meshTensor([(core[0],20,-1.3)])
|
||||
x0 = -np.array([np.sum(np.concatenate((core,bot)))])
|
||||
m1d = simpeg.Mesh.TensorMesh([np.concatenate((bot,core,air))], x0=x0)
|
||||
# Make the model
|
||||
sigma = np.zeros(m1d.nC) + sigmaHalf
|
||||
sigma[m1d.gridCC > 0 ] = 1e-8
|
||||
sigmaBack = sigma.copy()
|
||||
# Add structure
|
||||
if structure:
|
||||
shallow = (m1d.gridCC < -200) * (m1d.gridCC > -600)
|
||||
deep = (m1d.gridCC < -3000) * (m1d.gridCC > -5000)
|
||||
sigma[shallow] = 1
|
||||
sigma[deep] = 0.1
|
||||
|
||||
rxList = []
|
||||
for rxType in ['z1dr','z1di']:
|
||||
rxList.append(NSEM.Rx(simpeg.mkvc(np.array([0.0]),2).T,rxType))
|
||||
# Source list
|
||||
srcList =[]
|
||||
if tD:
|
||||
for freq in freqs:
|
||||
srcList.append(NSEM.SrcNSEM.polxy_1DhomotD(rxList,freq))
|
||||
else:
|
||||
for freq in freqs:
|
||||
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,freq))
|
||||
|
||||
survey = NSEM.Survey(srcList)
|
||||
return survey, sigma, m1d
|
||||
|
||||
|
||||
def setupSimpegNSEM_ePrimSec(inputSetup,comp='Imp',singleFreq=False,expMap=True):
|
||||
from SimPEG import NSEM
|
||||
|
||||
M,freqs,sig,sigBG,rx_loc = inputSetup
|
||||
# Make a receiver list
|
||||
rxList = []
|
||||
if comp == 'All':
|
||||
for rxType in ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi','tzxr','tzxi','tzyr','tzyi']:
|
||||
rxList.append(NSEM.Rx(rx_loc,rxType))
|
||||
elif comp == 'Imp':
|
||||
for rxType in ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi']:
|
||||
rxList.append(NSEM.Rx(rx_loc,rxType))
|
||||
elif comp == 'Tip':
|
||||
for rxType in ['tzxr','tzxi','tzyr','tzyi']:
|
||||
rxList.append(NSEM.Rx(rx_loc,rxType))
|
||||
else:
|
||||
rxList.append(NSEM.Rx(rx_loc,comp))
|
||||
# Source list
|
||||
srcList =[]
|
||||
|
||||
if singleFreq:
|
||||
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,singleFreq))
|
||||
else:
|
||||
for freq in freqs:
|
||||
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,freq))
|
||||
# Survey NSEM
|
||||
survey = NSEM.Survey(srcList)
|
||||
|
||||
## Setup the problem object
|
||||
sigma1d = M.r(sigBG,'CC','CC','M')[0,0,:]
|
||||
if expMap:
|
||||
problem = NSEM.Problem3D_ePrimSec(M,sigmaPrimary= np.log(sigma1d) )
|
||||
problem.mapping = simpeg.Maps.ExpMap(problem.mesh)
|
||||
problem.curModel = np.log(sig)
|
||||
else:
|
||||
problem = NSEM.Problem3D_ePrimSec(M,sigmaPrimary= sigma1d)
|
||||
problem.curModel = sig
|
||||
problem.pair(survey)
|
||||
problem.verbose = False
|
||||
try:
|
||||
from pymatsolver import MumpsSolver
|
||||
problem.Solver = MumpsSolver
|
||||
except:
|
||||
pass
|
||||
|
||||
return (survey, problem)
|
||||
|
||||
def getInputs():
|
||||
"""
|
||||
Function that returns Mesh, freqs, rx_loc, elev.
|
||||
"""
|
||||
# Make a mesh
|
||||
# M = simpeg.Mesh.TensorMesh([[(100,5,-1.5),(100.,10),(100,5,1.5)],[(100,5,-1.5),(100.,10),(100,5,1.5)],[(100,5,1.6),(100.,10),(100,3,2)]], x0=['C','C',-3529.5360])
|
||||
# M = simpeg.Mesh.TensorMesh([[(1000,6,-1.5),(1000.,6),(1000,6,1.5)],[(1000,6,-1.5),(1000.,2),(1000,6,1.5)],[(1000,6,-1.3),(1000.,6),(1000,6,1.3)]], x0=['C','C','C'])# Setup the model
|
||||
M = simpeg.Mesh.TensorMesh([[(200,6,-1.5),(200.,4),(200,6,1.5)],[(200,6,-1.5),(200.,4),(200,6,1.5)],[(200,8,-1.5),(200.,8),(200,8,1.5)]], x0=['C','C','C'])# Setup the model
|
||||
# Set the frequencies
|
||||
freqs = np.logspace(1,-3,5)
|
||||
elev = 0
|
||||
|
||||
## Setup the the survey object
|
||||
# Receiver locations
|
||||
rx_x, rx_y = np.meshgrid(np.arange(-350,350,200),np.arange(-350,350,200))
|
||||
rx_loc = np.hstack((simpeg.Utils.mkvc(rx_x,2),simpeg.Utils.mkvc(rx_y,2),elev+np.zeros((np.prod(rx_x.shape),1))))
|
||||
|
||||
return M, freqs, rx_loc, elev
|
||||
|
||||
def random(conds):
|
||||
''' Returns a halfspace model based on the inputs'''
|
||||
M, freqs, rx_loc, elev = getInputs()
|
||||
|
||||
# Backround
|
||||
sigBG = np.ones(M.nC)*conds
|
||||
# Add randomness to the model (10% of the value).
|
||||
sig = np.exp( np.log(sigBG) + np.random.randn(M.nC)*(conds)*1e-1 )
|
||||
|
||||
return (M, freqs, sig, sigBG, rx_loc)
|
||||
|
||||
def halfSpace(conds):
|
||||
''' Returns a halfspace model based on the inputs'''
|
||||
M, freqs, rx_loc, elev = getInputs()
|
||||
|
||||
# Model
|
||||
ccM = M.gridCC
|
||||
# conds = [1e-2]
|
||||
groundInd = ccM[:,2] < elev
|
||||
sig = np.zeros(M.nC) + 1e-8
|
||||
sig[groundInd] = conds
|
||||
# Set the background, not the same as the model
|
||||
sigBG = np.zeros(M.nC) + 1e-8
|
||||
sigBG[groundInd] = conds
|
||||
|
||||
return (M, freqs, sig, sigBG, rx_loc)
|
||||
|
||||
def blockInhalfSpace(conds):
|
||||
''' Returns a halfspace model based on the inputs'''
|
||||
M, freqs, rx_loc, elev = getInputs()
|
||||
|
||||
# Model
|
||||
ccM = M.gridCC
|
||||
# conds = [1e-2]
|
||||
groundInd = ccM[:,2] < elev
|
||||
sig = simpeg.Utils.ModelBuilder.defineBlock(M.gridCC,np.array([-1000,-1000,-1500]),np.array([1000,1000,-1000]),conds)
|
||||
sig[~groundInd] = 1e-8
|
||||
# Set the background, not the same as the model
|
||||
sigBG = np.zeros(M.nC) + 1e-8
|
||||
sigBG[groundInd] = conds[1]
|
||||
|
||||
return (M, freqs, sig, sigBG, rx_loc)
|
||||
|
||||
def twoLayer(conds):
|
||||
''' Returns a 2 layer model based on the conductivity values given'''
|
||||
M, freqs, rx_loc, elev = getInputs()
|
||||
|
||||
# Model
|
||||
ccM = M.gridCC
|
||||
groundInd = ccM[:,2] < elev
|
||||
botInd = ccM[:,2] < -3000
|
||||
sig = np.zeros(M.nC) + 1e-8
|
||||
sig[groundInd] = conds[1]
|
||||
sig[botInd] = conds[0]
|
||||
# Set the background, not the same as the model
|
||||
sigBG = np.zeros(M.nC) + 1e-8
|
||||
sigBG[groundInd] = conds[1]
|
||||
|
||||
|
||||
return (M, freqs, sig, sigBG, rx_loc)
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import Utils
|
||||
from SurveyNSEM import Rx, Survey, Data
|
||||
from FieldsNSEM import Fields1D_ePrimSec, Fields3D_ePrimSec
|
||||
from ProblemNSEM import Problem1D_ePrimSec, Problem3D_ePrimSec
|
||||
import SrcNSEM
|
||||
+19
-1
@@ -888,6 +888,8 @@ class ProjectedGNCG(BFGS, Minimize, Remember):
|
||||
maxIterCG = 5
|
||||
tolCG = 1e-1
|
||||
|
||||
stepOffBoundsFact = 0.1 # perturbation of the inactive set off the bounds
|
||||
|
||||
lower = -np.inf
|
||||
upper = np.inf
|
||||
|
||||
@@ -990,4 +992,20 @@ class ProjectedGNCG(BFGS, Minimize, Remember):
|
||||
cgFlag = 1
|
||||
# End CG Iterations
|
||||
|
||||
return delx
|
||||
# Take a gradient step on the active cells if exist
|
||||
if temp != self.xc.size:
|
||||
|
||||
rhs_a = (Active) * -self.g
|
||||
|
||||
dm_i = max( abs( delx ) )
|
||||
dm_a = max( abs(rhs_a) )
|
||||
|
||||
# perturb inactive set off of bounds so that they are included in the step
|
||||
delx = delx + self.stepOffBoundsFact * (rhs_a * dm_i / dm_a)
|
||||
|
||||
|
||||
# Only keep gradients going in the right direction on the active set
|
||||
indx = ((self.xc<=self.lower) & (delx < 0)) | ((self.xc>=self.upper) & (delx > 0))
|
||||
delx[indx] = 0.
|
||||
|
||||
return delx
|
||||
+16
-16
@@ -88,28 +88,28 @@ class BaseProblem(object):
|
||||
return self.survey is not None
|
||||
|
||||
@Utils.timeIt
|
||||
def Jvec(self, m, v, u=None):
|
||||
"""Jvec(m, v, u=None)
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""Jvec(m, v, f=None)
|
||||
|
||||
Effect of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: Jv
|
||||
"""
|
||||
raise NotImplementedError('J is not yet implemented.')
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec(self, m, v, u=None):
|
||||
"""Jtvec(m, v, u=None)
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""Jtvec(m, v, f=None)
|
||||
|
||||
Effect of transpose of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: JTv
|
||||
"""
|
||||
@@ -117,32 +117,32 @@ class BaseProblem(object):
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def Jvec_approx(self, m, v, u=None):
|
||||
"""Jvec_approx(m, v, u=None)
|
||||
def Jvec_approx(self, m, v, f=None):
|
||||
"""Jvec_approx(m, v, f=None)
|
||||
|
||||
Approximate effect of J(m) on a vector v
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: approxJv
|
||||
"""
|
||||
return self.Jvec(m, v, u)
|
||||
return self.Jvec(m, v, f)
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec_approx(self, m, v, u=None):
|
||||
"""Jtvec_approx(m, v, u=None)
|
||||
def Jtvec_approx(self, m, v, f=None):
|
||||
"""Jtvec_approx(m, v, f=None)
|
||||
|
||||
Approximate effect of transpose of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: JTv
|
||||
"""
|
||||
return self.Jtvec(m, v, u)
|
||||
return self.Jtvec(m, v, f)
|
||||
|
||||
def fields(self, m):
|
||||
"""
|
||||
@@ -224,9 +224,9 @@ class LinearProblem(BaseProblem):
|
||||
def fields(self, m):
|
||||
return self.G.dot(m)
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
return self.G.dot(v)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
return self.G.T.dot(v)
|
||||
|
||||
|
||||
+2
-2
@@ -74,7 +74,7 @@ class Property(object):
|
||||
if linkedMap is None:
|
||||
return None
|
||||
linkMap = linkMapClass(None) * linkedMap
|
||||
m = getattr(self, '%s'%linkName)
|
||||
m = getattr(self, '%sModel'%linkName)
|
||||
return linkMap.deriv( m )
|
||||
|
||||
m = getattr(self, '%sModel'%prop.name)
|
||||
@@ -239,7 +239,7 @@ class PropMap(object):
|
||||
setattr(self, '%sMap'%name, mapping)
|
||||
setattr(self, '%sIndex'%name, slices.get(name, slice(nP, nP + mapping.nP)))
|
||||
nP += mapping.nP
|
||||
self.nP = nP
|
||||
self.nP = nP
|
||||
|
||||
@property
|
||||
def defaultInvProp(self):
|
||||
|
||||
+797
-319
File diff suppressed because it is too large
Load Diff
+20
-20
@@ -295,38 +295,38 @@ class BaseSurvey(object):
|
||||
|
||||
@Utils.count
|
||||
@Utils.requires('prob')
|
||||
def dpred(self, m, u=None):
|
||||
"""dpred(m, u=None)
|
||||
def dpred(self, m, f=None):
|
||||
"""dpred(m, f=None)
|
||||
|
||||
Create the projected data from a model.
|
||||
The field, u, (if provided) will be used for the predicted data
|
||||
The fields, f, (if provided) will be used for the predicted data
|
||||
instead of recalculating the fields (which may be expensive!).
|
||||
|
||||
.. math::
|
||||
|
||||
d_\\text{pred} = P(u(m))
|
||||
d_\\text{pred} = P(f(m))
|
||||
|
||||
Where P is a projection of the fields onto the data space.
|
||||
"""
|
||||
if u is None: u = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(u))
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(f))
|
||||
|
||||
|
||||
@Utils.count
|
||||
def eval(self, u):
|
||||
"""eval(u)
|
||||
def eval(self, f):
|
||||
"""eval(f)
|
||||
|
||||
This function projects the fields onto the data space.
|
||||
|
||||
.. math::
|
||||
|
||||
d_\\text{pred} = \mathbf{P} u(m)
|
||||
d_\\text{pred} = \mathbf{P} f(m)
|
||||
"""
|
||||
raise NotImplemented('eval is not yet implemented.')
|
||||
|
||||
@Utils.count
|
||||
def evalDeriv(self, u):
|
||||
"""evalDeriv(u)
|
||||
def evalDeriv(self, f):
|
||||
"""evalDeriv(f)
|
||||
|
||||
This function s the derivative of projects the fields onto the data space.
|
||||
|
||||
@@ -337,11 +337,11 @@ class BaseSurvey(object):
|
||||
raise NotImplemented('eval is not yet implemented.')
|
||||
|
||||
@Utils.count
|
||||
def residual(self, m, u=None):
|
||||
"""residual(m, u=None)
|
||||
def residual(self, m, f=None):
|
||||
"""residual(m, f=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array u: fields
|
||||
:param numpy.array f: fields
|
||||
:rtype: numpy.array
|
||||
:return: data residual
|
||||
|
||||
@@ -352,14 +352,14 @@ class BaseSurvey(object):
|
||||
\mu_\\text{data} = \mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}
|
||||
|
||||
"""
|
||||
return Utils.mkvc(self.dpred(m, u=u) - self.dobs)
|
||||
return Utils.mkvc(self.dpred(m, f=f) - self.dobs)
|
||||
|
||||
@property
|
||||
def isSynthetic(self):
|
||||
"Check if the data is synthetic."
|
||||
return self.mtrue is not None
|
||||
|
||||
def makeSyntheticData(self, m, std=0.05, u=None, force=False):
|
||||
def makeSyntheticData(self, m, std=0.05, f=None, force=False):
|
||||
"""
|
||||
Make synthetic data given a model, and a standard deviation.
|
||||
|
||||
@@ -372,16 +372,16 @@ class BaseSurvey(object):
|
||||
if getattr(self, 'dobs', None) is not None and not force:
|
||||
raise Exception('Survey already has dobs. You can use force=True to override this exception.')
|
||||
self.mtrue = m
|
||||
self.dtrue = self.dpred(m, u=u)
|
||||
self.dtrue = self.dpred(m, f=f)
|
||||
noise = std*abs(self.dtrue)*np.random.randn(*self.dtrue.shape)
|
||||
self.dobs = self.dtrue+noise
|
||||
self.std = self.dobs*0 + std
|
||||
return self.dobs
|
||||
|
||||
class LinearSurvey(BaseSurvey):
|
||||
def eval(self, u):
|
||||
return u
|
||||
|
||||
def eval(self, f):
|
||||
return f
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
return self.prob.G.shape[0]
|
||||
|
||||
@@ -88,12 +88,14 @@ def getIndicesBlock(p0,p1,ccMesh):
|
||||
# Return a tuple
|
||||
return ind
|
||||
|
||||
def defineBlock(ccMesh,p0,p1,vals=[0,1]):
|
||||
def defineBlock(ccMesh,p0,p1,vals=None):
|
||||
"""
|
||||
Build a block with the conductivity specified by condVal. Returns an array.
|
||||
vals[0] conductivity of the block
|
||||
vals[1] conductivity of the ground
|
||||
"""
|
||||
if vals is None:
|
||||
vals = [0,1]
|
||||
sigma = np.zeros(ccMesh.shape[0]) + vals[1]
|
||||
ind = getIndicesBlock(p0,p1,ccMesh)
|
||||
|
||||
@@ -101,7 +103,11 @@ def defineBlock(ccMesh,p0,p1,vals=[0,1]):
|
||||
|
||||
return mkvc(sigma)
|
||||
|
||||
def defineElipse(ccMesh, center=[0,0,0], anisotropy=[1,1,1], slope=10., theta=0.):
|
||||
def defineElipse(ccMesh, center=None, anisotropy=None, slope=10., theta=0.):
|
||||
if center is None:
|
||||
center = [0,0,0]
|
||||
if anisotropy is None:
|
||||
anisotropy = [1,1,1]
|
||||
G = ccMesh.copy()
|
||||
dim = ccMesh.shape[1]
|
||||
for i in range(dim):
|
||||
@@ -156,7 +162,7 @@ def getIndicesSphere(center,radius,ccMesh):
|
||||
# Return a tuple
|
||||
return ind
|
||||
|
||||
def defineTwoLayers(ccMesh,depth,vals=[0,1]):
|
||||
def defineTwoLayers(ccMesh,depth,vals=None):
|
||||
"""
|
||||
Define a two layered model. Depth of the first layer must be specified.
|
||||
CondVals vector with the conductivity values of the layers. Eg:
|
||||
@@ -167,6 +173,8 @@ def defineTwoLayers(ccMesh,depth,vals=[0,1]):
|
||||
0 depth zf
|
||||
1st layer 2nd layer
|
||||
"""
|
||||
if vals is None:
|
||||
vals = [0,1]
|
||||
sigma = np.zeros(ccMesh.shape[0]) + vals[1]
|
||||
|
||||
dim = np.size(ccMesh[0,:])
|
||||
@@ -252,7 +260,7 @@ def layeredModel(ccMesh, layerTops, layerValues):
|
||||
|
||||
|
||||
|
||||
def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]):
|
||||
def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=None):
|
||||
"""
|
||||
Create a random model by convolving a kernel with a
|
||||
uniformly distributed model.
|
||||
@@ -276,6 +284,8 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]):
|
||||
|
||||
|
||||
"""
|
||||
if bounds is None:
|
||||
bounds = [0,1]
|
||||
|
||||
if seed is None:
|
||||
seed = np.random.randint(1e3)
|
||||
|
||||
@@ -7,3 +7,4 @@ from CounterUtils import *
|
||||
import ModelBuilder
|
||||
import SolverUtils
|
||||
from coordutils import *
|
||||
from modelutils import *
|
||||
|
||||
@@ -55,8 +55,10 @@ def hook(obj, method, name=None, overwrite=False, silent=False):
|
||||
print 'Method '+name+' was not overwritten.'
|
||||
|
||||
|
||||
def setKwargs(obj, ignore=[], **kwargs):
|
||||
def setKwargs(obj, ignore=None, **kwargs):
|
||||
"""Sets key word arguments (kwargs) that are present in the object, throw an error if they don't exist."""
|
||||
if ignore is None:
|
||||
ignore = []
|
||||
for attr in kwargs:
|
||||
if attr in ignore:
|
||||
continue
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
from SimPEG import np, Mesh
|
||||
import time as tm
|
||||
import vtk, vtk.util.numpy_support as npsup
|
||||
import re
|
||||
|
||||
def read_GOCAD_ts(tsfile):
|
||||
"""
|
||||
|
||||
Read GOCAD triangulated surface (*.ts) file
|
||||
INPUT:
|
||||
tsfile: Triangulated surface
|
||||
|
||||
OUTPUT:
|
||||
vrts : Array of vertices in XYZ coordinates [n x 3]
|
||||
trgl : Array of index for triangles [m x 3]. The order of the vertices
|
||||
is important and describes the normal
|
||||
n = cross( (P2 - P1 ) , (P3 - P1) )
|
||||
|
||||
Author: @fourndo
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Remove all attributes from the GoCAD surface before exporting it!
|
||||
|
||||
"""
|
||||
|
||||
|
||||
fid = open(tsfile,'r')
|
||||
line = fid.readline()
|
||||
|
||||
# Skip all the lines until the vertices
|
||||
while re.match('TFACE',line)==None:
|
||||
line = fid.readline()
|
||||
|
||||
line = fid.readline()
|
||||
vrtx = []
|
||||
|
||||
# Run down all the vertices and save in array
|
||||
while re.match('VRTX',line):
|
||||
l_input = re.split('[\s*]',line)
|
||||
temp = np.array(l_input[2:5])
|
||||
vrtx.append(temp.astype(np.float))
|
||||
|
||||
# Read next line
|
||||
line = fid.readline()
|
||||
|
||||
vrtx = np.asarray(vrtx)
|
||||
|
||||
# Skip lines to the triangles
|
||||
while re.match('TRGL',line)==None:
|
||||
line = fid.readline()
|
||||
|
||||
# Run down the list of triangles
|
||||
trgl = []
|
||||
|
||||
# Run down all the vertices and save in array
|
||||
while re.match('TRGL',line):
|
||||
l_input = re.split('[\s*]',line)
|
||||
temp = np.array(l_input[1:4])
|
||||
trgl.append(temp.astype(np.int))
|
||||
|
||||
# Read next line
|
||||
line = fid.readline()
|
||||
|
||||
trgl = np.asarray(trgl)
|
||||
|
||||
return vrtx, trgl
|
||||
|
||||
def surface2inds(vrtx, trgl, mesh, boundaries=True, internal=True):
|
||||
""""
|
||||
Function to read gocad polystructure file and output indexes of mesh with in the structure.
|
||||
|
||||
"""
|
||||
# Adjust the index
|
||||
trgl = trgl - 1
|
||||
|
||||
# Make vtk pts
|
||||
ptsvtk = vtk.vtkPoints()
|
||||
ptsvtk.SetData(npsup.numpy_to_vtk(vrtx,deep=1))
|
||||
|
||||
# Make the polygon connection
|
||||
polys = vtk.vtkCellArray()
|
||||
for face in trgl:
|
||||
poly = vtk.vtkPolygon()
|
||||
poly.GetPointIds().SetNumberOfIds(len(face))
|
||||
for nrv, vert in enumerate(face):
|
||||
poly.GetPointIds().SetId(nrv,vert)
|
||||
polys.InsertNextCell(poly)
|
||||
|
||||
# Make the polydata, structure of connections and vrtx
|
||||
polyData = vtk.vtkPolyData()
|
||||
polyData.SetPoints(ptsvtk)
|
||||
polyData.SetPolys(polys)
|
||||
|
||||
# Make implicit func
|
||||
ImpDistFunc = vtk.vtkImplicitPolyDataDistance()
|
||||
ImpDistFunc.SetInput(polyData)
|
||||
|
||||
# Convert the mesh
|
||||
vtkMesh = vtk.vtkRectilinearGrid()
|
||||
vtkMesh.SetDimensions(mesh.nNx,mesh.nNy,mesh.nNz)
|
||||
vtkMesh.SetXCoordinates(npsup.numpy_to_vtk(mesh.vectorNx, deep=1))
|
||||
vtkMesh.SetYCoordinates(npsup.numpy_to_vtk(mesh.vectorNy, deep=1))
|
||||
vtkMesh.SetZCoordinates(npsup.numpy_to_vtk(mesh.vectorNz, deep=1))
|
||||
# Add indexes
|
||||
vtkInd = npsup.numpy_to_vtk(np.arange(mesh.nC), deep=1)
|
||||
vtkInd.SetName('Index')
|
||||
vtkMesh.GetCellData().AddArray(vtkInd)
|
||||
|
||||
extractImpDistRectGridFilt = vtk.vtkExtractGeometry() # Object constructor
|
||||
extractImpDistRectGridFilt.SetImplicitFunction(ImpDistFunc) #
|
||||
extractImpDistRectGridFilt.SetInputData(vtkMesh)
|
||||
|
||||
if boundaries is True:
|
||||
extractImpDistRectGridFilt.ExtractBoundaryCellsOn()
|
||||
|
||||
else:
|
||||
extractImpDistRectGridFilt.ExtractBoundaryCellsOff()
|
||||
|
||||
if internal is True:
|
||||
extractImpDistRectGridFilt.ExtractInsideOn()
|
||||
|
||||
else:
|
||||
extractImpDistRectGridFilt.ExtractInsideOff()
|
||||
|
||||
print "Extracting indices from grid..."
|
||||
# Executing the pipe
|
||||
extractImpDistRectGridFilt.Update()
|
||||
|
||||
# Get index inside
|
||||
insideGrid = extractImpDistRectGridFilt.GetOutput()
|
||||
insideGrid = npsup.vtk_to_numpy(insideGrid.GetCellData().GetArray('Index'))
|
||||
|
||||
|
||||
# Return the indexes inside
|
||||
return insideGrid
|
||||
@@ -0,0 +1,63 @@
|
||||
from matutils import mkvc, ndgrid
|
||||
import numpy as np
|
||||
|
||||
def surface2ind_topo(mesh, topo, gridLoc='CC'):
|
||||
# def genActiveindfromTopo(mesh, topo):
|
||||
"""
|
||||
Get active indices from topography
|
||||
"""
|
||||
|
||||
|
||||
if mesh.dim == 3:
|
||||
from scipy.interpolate import NearestNDInterpolator
|
||||
Ftopo = NearestNDInterpolator(topo[:,:2], topo[:,2])
|
||||
|
||||
if gridLoc == 'CC':
|
||||
XY = ndgrid(mesh.vectorCCx, mesh.vectorCCy)
|
||||
Zcc = mesh.gridCC[:,2].reshape((np.prod(mesh.vnC[:2]), mesh.nCz), order='F')
|
||||
|
||||
gridTopo = Ftopo(XY)
|
||||
actind = [gridTopo[ixy] <= Zcc[ixy,:] for ixy in range(np.prod(mesh.vnC[0]))]
|
||||
actind = np.hstack(actind)
|
||||
|
||||
elif gridLoc == 'N':
|
||||
|
||||
XY = ndgrid(mesh.vectorNx, mesh.vectorNy)
|
||||
gridTopo = Ftopo(XY).reshape(mesh.vnN[:2], order='F')
|
||||
|
||||
if mesh._meshType not in ['TENSOR', 'CYL', 'BASETENSOR']:
|
||||
raise NotImplementedError('Nodal surface2ind_topo not implemented for %s mesh'%mesh._meshType)
|
||||
|
||||
Nz = mesh.vectorNz[1:] # TODO: this will only work for tensor meshes
|
||||
actind = np.array([False]*mesh.nC).reshape(mesh.vnC, order='F')
|
||||
|
||||
for ii in range(mesh.nCx):
|
||||
for jj in range(mesh.nCy):
|
||||
actind[ii,jj,:] = [np.all(gridTopo[ii:ii+2, jj:jj+2] >= Nz[kk]) for kk in range(len(Nz)) ]
|
||||
|
||||
elif mesh.dim == 2:
|
||||
from scipy.interpolate import interp1d
|
||||
Ftopo = interp1d(topo[:,0], topo[:,1])
|
||||
|
||||
if gridLoc == 'CC':
|
||||
gridTopo = Ftopo(mesh.gridCC[:,0])
|
||||
actind = mesh.gridCC[:,1] <= gridTopo
|
||||
|
||||
elif gridLoc == 'N':
|
||||
|
||||
gridTopo = Ftopo(mesh.vectorNx)
|
||||
if mesh._meshType not in ['TENSOR', 'CYL', 'BASETENSOR']:
|
||||
raise NotImplementedError('Nodal surface2ind_topo not implemented for %s mesh'%mesh._meshType)
|
||||
|
||||
Ny = mesh.vectorNy[1:] # TODO: this will only work for tensor meshes
|
||||
actind = np.array([False]*mesh.nC).reshape(mesh.vnC, order='F')
|
||||
|
||||
for ii in range(mesh.nCx):
|
||||
actind[ii,:] = [np.all(gridTopo[ii:ii+2] > Ny[kk]) for kk in range(len(Ny)) ]
|
||||
|
||||
else:
|
||||
raise NotImplementedError('surface2ind_topo not implemented for 1D mesh')
|
||||
|
||||
return mkvc(actind)
|
||||
|
||||
|
||||
@@ -12,9 +12,17 @@
|
||||
DC Forward Simulation
|
||||
=====================
|
||||
|
||||
Forward model conductive spheres in a half-space and plot a pseudo-section
|
||||
Forward model two conductive spheres in a half-space and plot a
|
||||
pseudo-section. Assumes an infinite line source and measures along the
|
||||
center of the spheres.
|
||||
|
||||
Created by @fourndo on Mon Feb 01 19:28:06 2016
|
||||
INPUT:
|
||||
loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]]
|
||||
radi = Radius of spheres [r1,r2]
|
||||
param = Conductivity of background and two spheres [m0,m1,m2]
|
||||
surveyType = survey type 'pole-dipole' or 'dipole-dipole'
|
||||
unitType = Data type "appResistivity" | "appConductivity" | "volt"
|
||||
Created by @fourndo
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
.. _examples_EM_Schenkel_Morrison_Casing:
|
||||
|
||||
.. --------------------------------- ..
|
||||
.. ..
|
||||
.. THIS FILE IS AUTO GENEREATED ..
|
||||
.. ..
|
||||
.. SimPEG/Examples/__init__.py ..
|
||||
.. ..
|
||||
.. --------------------------------- ..
|
||||
|
||||
|
||||
EM: Schenkel and Morrison Casing Model
|
||||
======================================
|
||||
|
||||
Here we create and run a FDEM forward simulation to calculate the vertical
|
||||
current inside a steel-cased. The model is based on the Schenkel and
|
||||
Morrison Casing Model, and the results are used in a 2016 SEG abstract by
|
||||
Yang et al.
|
||||
|
||||
- Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686.
|
||||
|
||||
|
||||
The model consists of:
|
||||
- Air: Conductivity 1e-8 S/m, above z = 0
|
||||
- Background: conductivity 1e-2 S/m, below z = 0
|
||||
- Casing: conductivity 1e6 S/m
|
||||
- 300m long
|
||||
- radius of 0.1m
|
||||
- thickness of 6e-3m
|
||||
|
||||
Inside the casing, we take the same conductivity as the background.
|
||||
|
||||
We are using an EM code to simulate DC, so we use frequency low enough
|
||||
that the skin depth inside the casing is longer than the casing length (f
|
||||
= 1e-6 Hz). The plot produced is of the current inside the casing.
|
||||
|
||||
These results are shown in the SEG abstract by Yang et al., 2016: 3D DC
|
||||
resistivity modeling of steel casing for reservoir monitoring using
|
||||
equivalent resistor network. The solver used to produce these results and
|
||||
achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_
|
||||
|
||||
.. _pymatsolver: https://github.com/rowanc1/pymatsolver
|
||||
|
||||
This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1
|
||||
|
||||
If you would use this example for a code comparison, or build upon it, a
|
||||
citation would be much appreciated!
|
||||
|
||||
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.EM_Schenkel_Morrison_Casing.run()
|
||||
|
||||
.. literalinclude:: ../../SimPEG/Examples/EM_Schenkel_Morrison_Casing.py
|
||||
:language: python
|
||||
:linenos:
|
||||
@@ -0,0 +1,26 @@
|
||||
.. _examples_Inversion_IRLS:
|
||||
|
||||
.. --------------------------------- ..
|
||||
.. ..
|
||||
.. THIS FILE IS AUTO GENEREATED ..
|
||||
.. ..
|
||||
.. SimPEG/Examples/__init__.py ..
|
||||
.. ..
|
||||
.. --------------------------------- ..
|
||||
|
||||
|
||||
Inversion: Linear Problem
|
||||
=========================
|
||||
|
||||
Here we go over the basics of creating a linear problem and inversion.
|
||||
|
||||
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.Inversion_IRLS.run()
|
||||
|
||||
.. literalinclude:: ../../SimPEG/Examples/Inversion_IRLS.py
|
||||
:language: python
|
||||
:linenos:
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
.. _examples_Forward_BasicDirectCurrent:
|
||||
.. _examples_MT_1D_analytic_nlayer_Earth:
|
||||
|
||||
.. --------------------------------- ..
|
||||
.. ..
|
||||
@@ -8,14 +8,14 @@
|
||||
.. ..
|
||||
.. --------------------------------- ..
|
||||
|
||||
Forward BasicDirectCurrent
|
||||
==========================
|
||||
MT 1D analytic nlayer Earth
|
||||
===========================
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.Forward_BasicDirectCurrent.run()
|
||||
Examples.MT_1D_analytic_nlayer_Earth.run()
|
||||
|
||||
.. literalinclude:: ../../SimPEG/Examples/Forward_BasicDirectCurrent.py
|
||||
.. literalinclude:: ../../SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py
|
||||
:language: python
|
||||
:linenos:
|
||||
@@ -0,0 +1,25 @@
|
||||
.. _examples_Mesh_Basic_ForwardDC:
|
||||
|
||||
.. --------------------------------- ..
|
||||
.. ..
|
||||
.. THIS FILE IS AUTO GENEREATED ..
|
||||
.. ..
|
||||
.. SimPEG/Examples/__init__.py ..
|
||||
.. ..
|
||||
.. --------------------------------- ..
|
||||
|
||||
|
||||
Mesh: Basic Forward 2D DC Resistivity
|
||||
=====================================
|
||||
|
||||
2D DC forward modeling example with Tensor and Curvilinear Meshes
|
||||
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.Mesh_Basic_ForwardDC.run()
|
||||
|
||||
.. literalinclude:: ../../SimPEG/Examples/Mesh_Basic_ForwardDC.py
|
||||
:language: python
|
||||
:linenos:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user