mirror of
https://github.com/wassname/simpeg.git
synced 2026-09-13 13:03:14 +08:00
Compare commits
30
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3cbefac3ba | ||
|
|
e7e497a06d | ||
|
|
3157aa02cf | ||
|
|
c40d11ef53 | ||
|
|
c75e3d0246 | ||
|
|
14f0d90f99 | ||
|
|
425b1e292c | ||
|
|
f6cd8696d1 | ||
|
|
f788d5f05d | ||
|
|
1521b08af6 | ||
|
|
8c366463e7 | ||
|
|
6d77ae9a12 | ||
|
|
ce88c676d4 | ||
|
|
1e6ed86135 | ||
|
|
9061ef5839 | ||
|
|
0638fa308c | ||
|
|
54478ad05e | ||
|
|
2cf0edb736 | ||
|
|
3b5dfecb46 | ||
|
|
93d8ef5921 | ||
|
|
5b0a58b751 | ||
|
|
9155a9c474 | ||
|
|
64510bc606 | ||
|
|
d9f0241da3 | ||
|
|
9a7225c9f6 | ||
|
|
e8e022fcc6 | ||
|
|
341b98d23a | ||
|
|
efbc8f9057 | ||
|
|
39ece11d8a | ||
|
|
c36b5a600d |
+1
-1
@@ -1,4 +1,4 @@
|
||||
[bumpversion]
|
||||
current_version = 0.1.12
|
||||
current_version = 0.1.10
|
||||
files = setup.py SimPEG/__init__.py docs/conf.py
|
||||
|
||||
|
||||
@@ -39,5 +39,3 @@ nosetests.xml
|
||||
*.sublime-workspace
|
||||
docs/_build/
|
||||
Makefile
|
||||
docs/warnings.txt
|
||||
.DS_Store
|
||||
|
||||
+3
-27
@@ -18,32 +18,24 @@ env:
|
||||
- TEST_DIR="tests/mesh tests/base tests/utils"
|
||||
- TEST_DIR=tests/em/fdem/inverse/derivs
|
||||
- TEST_DIR=tests/em/tdem
|
||||
- TEST_DIR=tests/pf
|
||||
- TEST_DIR=tests/dcip
|
||||
- TEST_DIR=tests/flow
|
||||
- TEST_DIR=tests/mt
|
||||
- TEST_DIR=tests/examples
|
||||
- TEST_DIR=tests/em/fdem/inverse/adjoint
|
||||
- TEST_DIR=tests/em/fdem/forward
|
||||
- TEST_DIR=tests/docs;
|
||||
GAE_PYTHONPATH=${HOME}/.cache/google_appengine;
|
||||
PATH=$PATH:${HOME}/google-cloud-sdk/bin;
|
||||
PYTHONPATH=${PYTHONPATH}:${GAE_PYTHONPATH};
|
||||
CLOUDSDK_CORE_DISABLE_PROMPTS=1
|
||||
|
||||
# Setup anaconda
|
||||
before_install:
|
||||
# Install packages
|
||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then wget http://repo.continuum.io/miniconda/Miniconda-3.8.3-Linux-x86_64.sh
|
||||
-O miniconda.sh; else wget http://repo.continuum.io/miniconda/Miniconda3-3.8.3-Linux-x86_64.sh
|
||||
-O miniconda.sh; fi
|
||||
- if [ ${TRAVIS_PYTHON_VERSION:0:1} == "2" ]; then wget http://repo.continuum.io/miniconda/Miniconda-3.8.3-Linux-x86_64.sh -O miniconda.sh; else wget http://repo.continuum.io/miniconda/Miniconda3-3.8.3-Linux-x86_64.sh -O miniconda.sh; fi
|
||||
- chmod +x miniconda.sh
|
||||
- ./miniconda.sh -b
|
||||
- export PATH=/home/travis/anaconda/bin:/home/travis/miniconda/bin:$PATH
|
||||
- conda update --yes conda
|
||||
|
||||
# Install packages
|
||||
install:
|
||||
- conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython nose vtk sphinx
|
||||
- conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython nose vtk
|
||||
- pip install nose-cov python-coveralls
|
||||
|
||||
- git clone https://github.com/rowanc1/pymatsolver.git
|
||||
@@ -54,28 +46,12 @@ install:
|
||||
|
||||
# Run test
|
||||
script:
|
||||
# test docs
|
||||
- nosetests $TEST_DIR --with-cov --cov SimPEG --cov-config .coveragerc -v -s
|
||||
|
||||
# Calculate coverage
|
||||
after_success:
|
||||
- coveralls --config_file .coveragerc
|
||||
|
||||
- if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then
|
||||
if [ ${TEST_DIR} == "tests/docs" ]; then
|
||||
python scripts/fetch_gae_sdk.py $(dirname "${GAE_PYTHONPATH}");
|
||||
openssl aes-256-cbc -K $encrypted_93066031461c_key -iv $encrypted_93066031461c_iv
|
||||
-in docs/credentials.tar.gz.enc -out credentials.tar.gz -d ;
|
||||
if [ ! -d ${HOME}/google-cloud-sdk ]; then curl https://sdk.cloud.google.com | bash; fi ;
|
||||
tar -xzf credentials.tar.gz ;
|
||||
gcloud auth activate-service-account --key-file client-secret.json ;
|
||||
gcloud config set project simpegdocs;
|
||||
gcloud -q components update gae-python;
|
||||
gcloud -q preview app deploy ./docs/app.yaml --version ${TRAVIS_COMMIT} --promote;
|
||||
fi;
|
||||
fi
|
||||
|
||||
|
||||
notifications:
|
||||
email:
|
||||
- rowanc1@gmail.com
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
.. image:: https://raw.github.com/simpeg/simpeg/master/docs/images/simpeg-logo.png
|
||||
.. image:: https://raw.github.com/simpeg/simpeg/master/docs/simpeg-logo.png
|
||||
:alt: SimPEG Logo
|
||||
|
||||
======
|
||||
|
||||
@@ -162,8 +162,8 @@ class ProblemDC_CC(Problem.BaseProblem):
|
||||
"""
|
||||
Makes the matrix A(m) for the DC resistivity problem.
|
||||
|
||||
:param numpy.ndarray m: model
|
||||
:rtype: scipy.sparse.csc_matrix
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.csc_matrix
|
||||
:return: A(m)
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -71,7 +71,7 @@ class ProblemIP(Problem.BaseProblem):
|
||||
Makes the matrix A(m) for the DC resistivity problem.
|
||||
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.sparse.csc_matrix
|
||||
:rtype: scipy.csc_matrix
|
||||
:return: A(m)
|
||||
|
||||
.. math::
|
||||
|
||||
+58
-132
@@ -144,7 +144,6 @@ 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.
|
||||
@@ -167,7 +166,7 @@ class TargetMisfit(InversionDirective):
|
||||
|
||||
|
||||
|
||||
class SaveEveryIteration(InversionDirective):
|
||||
class _SaveEveryIteration(InversionDirective):
|
||||
@property
|
||||
def name(self):
|
||||
if getattr(self, '_name', None) is None:
|
||||
@@ -188,7 +187,7 @@ class SaveEveryIteration(InversionDirective):
|
||||
self._fileName = value
|
||||
|
||||
|
||||
class SaveModelEveryIteration(SaveEveryIteration):
|
||||
class SaveModelEveryIteration(_SaveEveryIteration):
|
||||
"""SaveModelEveryIteration"""
|
||||
|
||||
def initialize(self):
|
||||
@@ -198,7 +197,7 @@ class SaveModelEveryIteration(SaveEveryIteration):
|
||||
np.save('%03d-%s' % (self.opt.iter, self.fileName), self.opt.xc)
|
||||
|
||||
|
||||
class SaveOutputEveryIteration(SaveEveryIteration):
|
||||
class SaveOutputEveryIteration(_SaveEveryIteration):
|
||||
"""SaveModelEveryIteration"""
|
||||
|
||||
def initialize(self):
|
||||
@@ -212,7 +211,7 @@ class SaveOutputEveryIteration(SaveEveryIteration):
|
||||
f.write(' %3d %1.4e %1.4e %1.4e %1.4e\n'%(self.opt.iter, self.invProb.beta, self.invProb.phi_d, self.invProb.phi_m, self.opt.f))
|
||||
f.close()
|
||||
|
||||
class SaveOutputDictEveryIteration(SaveEveryIteration):
|
||||
class SaveOutputDictEveryIteration(_SaveEveryIteration):
|
||||
"""SaveOutputDictEveryIteration"""
|
||||
|
||||
def initialize(self):
|
||||
@@ -243,6 +242,12 @@ class SaveOutputDictEveryIteration(SaveEveryIteration):
|
||||
# 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)
|
||||
|
||||
|
||||
# class UpdateReferenceModel(Parameter):
|
||||
|
||||
# mref0 = None
|
||||
|
||||
# def nextIter(self):
|
||||
# mref = getattr(self, 'm_prev', None)
|
||||
# if mref is None:
|
||||
# if self.debug: print 'UpdateReferenceModel is using mref0'
|
||||
@@ -253,151 +258,56 @@ class SaveOutputDictEveryIteration(SaveEveryIteration):
|
||||
class Update_IRLS(InversionDirective):
|
||||
|
||||
eps_min = None
|
||||
eps = 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
|
||||
prctile = 95
|
||||
|
||||
# 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):
|
||||
|
||||
if self.mode == 1:
|
||||
self.reg.norms = [2., 2., 2., 2.]
|
||||
# Scale the regularization for changes in norm
|
||||
if getattr(self, 'phi_m_last', None) is not None:
|
||||
|
||||
self.reg.curModel = self.invProb.curModel
|
||||
self.reg.gamma = 1.
|
||||
phim_new = self.reg.eval(self.invProb.curModel)
|
||||
self.gamma = self.phi_m_last / phim_new
|
||||
|
||||
self.reg.curModel = self.invProb.curModel
|
||||
self.reg.gamma = self.gamma
|
||||
|
||||
if getattr(self, 'phi_d_last', None) is None:
|
||||
self.phi_d_last = self.invProb.phi_d
|
||||
|
||||
def endIter(self):
|
||||
# Cool the threshold parameter if required
|
||||
if getattr(self, 'factor', None) is not None:
|
||||
eps = self.reg.eps / self.factor
|
||||
|
||||
# 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
|
||||
|
||||
# Either use the supplied epsilon, or fix base on distribution of
|
||||
# model values
|
||||
if getattr(self, 'eps', None) is None:
|
||||
self.reg.eps_p = np.percentile(np.abs(self.invProb.curModel),self.prctile)
|
||||
if getattr(self, 'eps_min', None) is not None:
|
||||
self.reg.eps = np.max([self.eps_min,eps])
|
||||
else:
|
||||
self.reg.eps_p = self.eps[0]
|
||||
self.reg.eps = eps
|
||||
|
||||
if getattr(self, 'eps', None) is None:
|
||||
self.reg.eps_q = np.percentile(np.abs(self.reg.regmesh.cellDiffxStencil*(self.reg.mapping * self.invProb.curModel)),self.prctile)
|
||||
else:
|
||||
self.reg.eps_q = self.eps[1]
|
||||
# Get phi_m at the end of current iteration
|
||||
self.phi_m_last = self.invProb.phi_m_last
|
||||
|
||||
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
|
||||
# Update the model used for the IRLS weights
|
||||
self.reg.curModel = self.invProb.curModel
|
||||
|
||||
self.reg.l2model = self.invProb.curModel
|
||||
self.reg.curModel = self.invProb.curModel
|
||||
# Temporarely set gamma to 1. to get raw phi_m
|
||||
self.reg.gamma = 1.
|
||||
|
||||
print "L[p qx qy qz]-norm : " + str(self.reg.norms)
|
||||
print "eps_p: " + str(self.reg.eps_p) + " eps_q: " + str(self.reg.eps_q)
|
||||
# Compute new model objective function value
|
||||
phim_new = self.reg.eval(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)
|
||||
# Update gamma to scale the regularization between IRLS iterations
|
||||
self.reg.gamma = self.phi_m_last / phim_new
|
||||
|
||||
# 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
|
||||
|
||||
|
||||
# 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
|
||||
# Set the weighting matrix to None so that it is recomputed next time
|
||||
# it is called in the inversion
|
||||
self.reg._W = None
|
||||
|
||||
class Update_lin_PreCond(InversionDirective):
|
||||
"""
|
||||
@@ -450,3 +360,19 @@ class Update_Wj(InversionDirective):
|
||||
JtJdiag = JtJdiag / max(JtJdiag)
|
||||
|
||||
self.reg.wght = JtJdiag
|
||||
|
||||
class Scale_Beta(InversionDirective):
|
||||
"""
|
||||
Instead of a linear cooling schedule, beta is allowed to change based
|
||||
on the ratio between the target misfit and the current data misfit. The
|
||||
update is done only if the misfit is outside some threshold bounds.
|
||||
"""
|
||||
tol = 0.05
|
||||
|
||||
def endIter(self):
|
||||
|
||||
# Check if misfit is within the tolerance, otherwise adjust beta
|
||||
val = self.invProb.phi_d / (self.survey.nD*0.5)
|
||||
|
||||
if np.abs(1.-val) > self.tol:
|
||||
self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d
|
||||
|
||||
@@ -1,302 +0,0 @@
|
||||
from __future__ import division
|
||||
import numpy as np
|
||||
from scipy.constants import mu_0, pi, epsilon_0
|
||||
from scipy.special import erf
|
||||
from SimPEG import Utils
|
||||
|
||||
omega = lambda f: 2.*np.pi*f
|
||||
# TODO:
|
||||
# r = lambda dx, dy, dz: np.sqrt( dx**2. + dy**2. + dz**2.)
|
||||
# k = lambda f, mu, epsilon, sig: np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig )
|
||||
|
||||
def E_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=0., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Analytic Electric fields from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
mu = mu_0*(1+kappa)
|
||||
epsilon = epsilon_0*epsr
|
||||
sig_hat = sig + 1j*omega(f)*epsilon
|
||||
|
||||
XYZ = Utils.asArray_N_x_Dim(XYZ, 3)
|
||||
# Check
|
||||
if XYZ.shape[0] > 1 & f.shape[0] > 1:
|
||||
raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.")
|
||||
|
||||
dx = XYZ[:,0]-srcLoc[0]
|
||||
dy = XYZ[:,1]-srcLoc[1]
|
||||
dz = XYZ[:,2]-srcLoc[2]
|
||||
|
||||
r = np.sqrt( dx**2. + dy**2. + dz**2.)
|
||||
# k = np.sqrt( -1j*2.*np.pi*f*mu*sig )
|
||||
k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig )
|
||||
|
||||
front = current * length / (4.*np.pi*sig_hat* r**3) * np.exp(-1j*k*r)
|
||||
mid = -k**2 * r**2 + 3*1j*k*r + 3
|
||||
|
||||
if orientation.upper() == 'X':
|
||||
Ex = front*((dx**2 / r**2)*mid + (k**2 * r**2 -1j*k*r-1.))
|
||||
Ey = front*(dx*dy / r**2)*mid
|
||||
Ez = front*(dx*dz / r**2)*mid
|
||||
return Ex, Ey, Ez
|
||||
|
||||
elif orientation.upper() == 'Y':
|
||||
# x--> y, y--> z, z-->x
|
||||
Ey = front*((dy**2 / r**2)*mid + (k**2 * r**2 -1j*k*r-1.))
|
||||
Ez = front*(dy*dz / r**2)*mid
|
||||
Ex = front*(dy*dx / r**2)*mid
|
||||
return Ex, Ey, Ez
|
||||
|
||||
elif orientation.upper() == 'Z':
|
||||
# x --> z, y --> x, z --> y
|
||||
Ez = front*((dz**2 / r**2)*mid + (k**2 * r**2 -1j*k*r-1.))
|
||||
Ex = front*(dz*dx / r**2)*mid
|
||||
Ey = front*(dz*dy / r**2)*mid
|
||||
return Ex, Ey, Ez
|
||||
|
||||
|
||||
def E_galvanic_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Galvanic portion of Electric fields from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
mu = mu_0*(1+kappa)
|
||||
epsilon = epsilon_0*epsr
|
||||
sig_hat = sig + 1j*omega(f)*epsilon
|
||||
|
||||
XYZ = Utils.asArray_N_x_Dim(XYZ, 3)
|
||||
# Check
|
||||
if XYZ.shape[0] > 1 & f.shape[0] > 1:
|
||||
raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.")
|
||||
|
||||
dx = XYZ[:,0]-srcLoc[0]
|
||||
dy = XYZ[:,1]-srcLoc[1]
|
||||
dz = XYZ[:,2]-srcLoc[2]
|
||||
|
||||
r = np.sqrt( dx**2. + dy**2. + dz**2.)
|
||||
# k = np.sqrt( -1j*2.*np.pi*f*mu*sig )
|
||||
k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig )
|
||||
|
||||
front = current * length / (4.*np.pi*sig_hat* r**3) * np.exp(-1j*k*r)
|
||||
mid = -k**2 * r**2 + 3*1j*k*r + 3
|
||||
|
||||
if orientation.upper() == 'X':
|
||||
Ex_galvanic = front*((dx**2 / r**2)*mid + (-1j*k*r-1.))
|
||||
Ey_galvanic = front*(dx*dy / r**2)*mid
|
||||
Ez_galvanic = front*(dx*dz / r**2)*mid
|
||||
return Ex_galvanic, Ey_galvanic, Ez_galvanic
|
||||
|
||||
elif orientation.upper() == 'Y':
|
||||
# x--> y, y--> z, z-->x
|
||||
Ey_galvanic = front*((dy**2 / r**2)*mid + (-1j*k*r-1.))
|
||||
Ez_galvanic = front*(dy*dz / r**2)*mid
|
||||
Ex_galvanic = front*(dy*dx / r**2)*mid
|
||||
return Ex_galvanic, Ey_galvanic, Ez_galvanic
|
||||
|
||||
elif orientation.upper() == 'Z':
|
||||
# x --> z, y --> x, z --> y
|
||||
Ez_galvanic = front*((dz**2 / r**2)*mid + (-1j*k*r-1.))
|
||||
Ex_galvanic = front*(dz*dx / r**2)*mid
|
||||
Ey_galvanic = front*(dz*dy / r**2)*mid
|
||||
return Ex_galvanic, Ey_galvanic, Ez_galvanic
|
||||
|
||||
|
||||
def E_inductive_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Inductive portion of Electric fields from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
mu = mu_0*(1+kappa)
|
||||
epsilon = epsilon_0*epsr
|
||||
sig_hat = sig + 1j*omega(f)*epsilon
|
||||
|
||||
XYZ = Utils.asArray_N_x_Dim(XYZ, 3)
|
||||
# Check
|
||||
if XYZ.shape[0] > 1 & f.shape[0] > 1:
|
||||
raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.")
|
||||
|
||||
dx = XYZ[:,0]-srcLoc[0]
|
||||
dy = XYZ[:,1]-srcLoc[1]
|
||||
dz = XYZ[:,2]-srcLoc[2]
|
||||
|
||||
r = np.sqrt( dx**2. + dy**2. + dz**2.)
|
||||
# k = np.sqrt( -1j*2.*np.pi*f*mu*sig )
|
||||
k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig )
|
||||
|
||||
front = current * length / (4.*np.pi*sig_hat* r**3) * np.exp(-1j*k*r)
|
||||
|
||||
if orientation.upper() == 'X':
|
||||
Ex_inductive = front*(k**2 * r**2)
|
||||
Ey_inductive = np.zeros_like(Ex_inductive)
|
||||
Ez_inductive = np.zeros_like(Ex_inductive)
|
||||
return Ex_inductive, Ey_inductive, Ez_inductive
|
||||
|
||||
elif orientation.upper() == 'Y':
|
||||
# x--> y, y--> z, z-->x
|
||||
Ey_inductive = front*(k**2 * r**2)
|
||||
Ez_inductive = np.zeros_like(Ey_inductive)
|
||||
Ex_inductive = np.zeros_like(Ey_inductive)
|
||||
return Ex_inductive, Ey_inductive, Ez_inductive
|
||||
|
||||
elif orientation.upper() == 'Z':
|
||||
# x --> z, y --> x, z --> y
|
||||
Ez_inductive = front*(k**2 * r**2)
|
||||
Ex_inductive = np.zeros_like(Ez_inductive)
|
||||
Ey_inductive = np.zeros_like(Ez_inductive)
|
||||
return Ex_inductive, Ey_inductive, Ez_inductive
|
||||
|
||||
|
||||
def J_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Current densities from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
|
||||
Ex, Ey, Ez = E_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=current, length=length, orientation=orientation, kappa=kappa, epsr=epsr)
|
||||
Jx = sig*Ex
|
||||
Jy = sig*Ey
|
||||
Jz = sig*Ez
|
||||
return Jx, Jy, Jz
|
||||
|
||||
|
||||
def J_galvanic_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Galvanic portion of Current densities from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
|
||||
Ex_galvanic, Ey_galvanic, Ez_galvanic = E_galvanic_from_ElectricDipoleWholeSpaced(XYZ, srcLoc, sig, f, current=current, length=length, orientation=orientation, kappa=kappa, epsr=epsr)
|
||||
Jx_galvanic = sig*Ex_galvanic
|
||||
Jy_galvanic = sig*Ey_galvanic
|
||||
Jz_galvanic = sig*Ez_galvanic
|
||||
return Jx_galvanic, Jy_galvanic, Jz_galvanic
|
||||
|
||||
|
||||
def J_inductive_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Inductive portion of Current densities from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
|
||||
Ex_inductive, Ey_inductive, Ez_inductive = E_inductive_from_ElectricDipoleWholeSpaced(XYZ, srcLoc, sig, f, current=current, length=length, orientation=orientation, kappa=kappa, epsr=epsr)
|
||||
Jx_inductive = sig*Ex_inductive
|
||||
Jy_inductive = sig*Ey_inductive
|
||||
Jz_inductive = sig*Ez_inductive
|
||||
return Jx_inductive, Jy_inductive, Jz_inductive
|
||||
|
||||
|
||||
def H_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Magnetic fields from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
mu = mu_0*(1+kappa)
|
||||
epsilon = epsilon_0*epsr
|
||||
XYZ = Utils.asArray_N_x_Dim(XYZ, 3)
|
||||
# Check
|
||||
if XYZ.shape[0] > 1 & f.shape[0] > 1:
|
||||
raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.")
|
||||
|
||||
dx = XYZ[:,0]-srcLoc[0]
|
||||
dy = XYZ[:,1]-srcLoc[1]
|
||||
dz = XYZ[:,2]-srcLoc[2]
|
||||
|
||||
r = np.sqrt( dx**2. + dy**2. + dz**2.)
|
||||
# k = np.sqrt( -1j*2.*np.pi*f*mu*sig )
|
||||
k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig )
|
||||
|
||||
front = current * length / (4.*np.pi* r**2) * (-1j*k*r + 1) * np.exp(-1j*k*r)
|
||||
|
||||
if orientation.upper() == 'X':
|
||||
Hy = front*(-dz / r)
|
||||
Hz = front*(dy / r)
|
||||
Hx = np.zeros_like(Hy)
|
||||
return Hx, Hy, Hz
|
||||
|
||||
elif orientation.upper() == 'Y':
|
||||
Hx = front*(dz / r)
|
||||
Hz = front*(-dx / r)
|
||||
Hy = np.zeros_like(Hx)
|
||||
return Hx, Hy, Hz
|
||||
|
||||
elif orientation.upper() == 'Z':
|
||||
Hx = front*(-dy / r)
|
||||
Hy = front*(dx / r)
|
||||
Hz = np.zeros_like(Hx)
|
||||
return Hx, Hy, Hz
|
||||
|
||||
|
||||
def B_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Magnetic flux densites from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
|
||||
Hx, Hy, Hz = H_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=current, length=length, orientation=orientation, kappa=kappa, epsr=epsr)
|
||||
Bx = mu*Hx
|
||||
By = mu*Hy
|
||||
Bz = mu*Hz
|
||||
return Bx, By, Bz
|
||||
|
||||
|
||||
def A_from_ElectricDipoleWholeSpace(XYZ, srcLoc, sig, f, current=1., length=1., orientation='X', kappa=1., epsr=1.):
|
||||
|
||||
"""
|
||||
Computing Electric vector potentials from Electrical Dipole in a Wholespace
|
||||
TODO:
|
||||
Add description of parameters
|
||||
"""
|
||||
mu = mu_0*(1+kappa)
|
||||
epsilon = epsilon_0*epsr
|
||||
XYZ = Utils.asArray_N_x_Dim(XYZ, 3)
|
||||
# Check
|
||||
if XYZ.shape[0] > 1 & f.shape[0] > 1:
|
||||
raise Exception("I/O type error: For multiple field locations only a single frequency can be specified.")
|
||||
|
||||
dx = XYZ[:,0]-srcLoc[0]
|
||||
dy = XYZ[:,1]-srcLoc[1]
|
||||
dz = XYZ[:,2]-srcLoc[2]
|
||||
|
||||
r = np.sqrt( dx**2. + dy**2. + dz**2.)
|
||||
k = np.sqrt( omega(f)**2. *mu*epsilon -1j*omega(f)*mu*sig )
|
||||
|
||||
front = current * length / (4.*np.pi*r)
|
||||
|
||||
if orientation.upper() == 'X':
|
||||
Ax = front*np.exp(-1j*k*r)
|
||||
Ay = np.zeros_like(Ax)
|
||||
Az = np.zeros_like(Ax)
|
||||
return Ax, Ay, Az
|
||||
|
||||
elif orientation.upper() == 'Y':
|
||||
Ay = front*np.exp(-1j*k*r)
|
||||
Ax = np.zeros_like(Ay)
|
||||
Az = np.zeros_like(Ay)
|
||||
return Ax, Ay, Az
|
||||
|
||||
elif orientation.upper() == 'Z':
|
||||
Az = front*np.exp(-1j*k*r)
|
||||
Ax = np.zeros_like(Ay)
|
||||
Ay = np.zeros_like(Ay)
|
||||
return Ax, Ay, Az
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,4 +2,3 @@ from TDEM import hzAnalyticDipoleT
|
||||
from FDEM import hzAnalyticDipoleF
|
||||
from FDEMcasing import *
|
||||
from DC import DCAnalyticHalf, DCAnalyticSphere
|
||||
from FDEMDipolarfields import *
|
||||
|
||||
+3
-4
@@ -20,10 +20,10 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
Problem.BaseProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
|
||||
surveyPair = Survey.BaseSurvey #: The survey to pair with.
|
||||
dataPair = Survey.Data #: The data to pair with.
|
||||
surveyPair = Survey.BaseSurvey
|
||||
dataPair = Survey.Data
|
||||
|
||||
PropMap = EMPropMap #: The property mapping
|
||||
PropMap = EMPropMap
|
||||
|
||||
Solver = SimpegSolver
|
||||
solverOpts = {}
|
||||
@@ -217,7 +217,6 @@ class BaseEMSurvey(Survey.BaseSurvey):
|
||||
def eval(self, f):
|
||||
"""
|
||||
Project fields to receiver locations
|
||||
|
||||
:param Fields u: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: data
|
||||
|
||||
@@ -6,11 +6,11 @@ from SimPEG.EM.Utils import omega
|
||||
from SimPEG.Utils import Zero, Identity, sdiag
|
||||
|
||||
|
||||
class FieldsFDEM(SimPEG.Problem.Fields):
|
||||
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 object acts like an array and is indexed by
|
||||
each problem, the rest are computed. The fields obejct acts like an array and is indexed by
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -92,7 +92,7 @@ class FieldsFDEM(SimPEG.Problem.Fields):
|
||||
"""
|
||||
Total derivative of e with respect to the inversion model. Returns :math:`d\mathbf{e}/d\mathbf{m}` for forward and (:math:`d\mathbf{e}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint
|
||||
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source
|
||||
:param Src src: sorce
|
||||
:param numpy.ndarray du_dm_v: derivative of the solution vector with respect to the model times a vector (is None for adjoint)
|
||||
:param numpy.ndarray v: vector to take sensitivity product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -110,7 +110,7 @@ class FieldsFDEM(SimPEG.Problem.Fields):
|
||||
"""
|
||||
Total derivative of b with respect to the inversion model. Returns :math:`d\mathbf{b}/d\mathbf{m}` for forward and (:math:`d\mathbf{b}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint
|
||||
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source
|
||||
:param Src src: sorce
|
||||
:param numpy.ndarray du_dm_v: derivative of the solution vector with respect to the model times a vector (is None for adjoint)
|
||||
:param numpy.ndarray v: vector to take sensitivity product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -128,7 +128,7 @@ class FieldsFDEM(SimPEG.Problem.Fields):
|
||||
"""
|
||||
Total derivative of h with respect to the inversion model. Returns :math:`d\mathbf{h}/d\mathbf{m}` for forward and (:math:`d\mathbf{h}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint
|
||||
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source
|
||||
:param Src src: sorce
|
||||
:param numpy.ndarray du_dm_v: derivative of the solution vector with respect to the model times a vector (is None for adjoint)
|
||||
:param numpy.ndarray v: vector to take sensitivity product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -146,7 +146,7 @@ class FieldsFDEM(SimPEG.Problem.Fields):
|
||||
"""
|
||||
Total derivative of j with respect to the inversion model. Returns :math:`d\mathbf{j}/d\mathbf{m}` for forward and (:math:`d\mathbf{j}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint
|
||||
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source
|
||||
:param Src src: sorce
|
||||
:param numpy.ndarray du_dm_v: derivative of the solution vector with respect to the model times a vector (is None for adjoint)
|
||||
:param numpy.ndarray v: vector to take sensitivity product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -160,12 +160,12 @@ class FieldsFDEM(SimPEG.Problem.Fields):
|
||||
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 Fields3D_e(FieldsFDEM):
|
||||
class Fields3D_e(Fields):
|
||||
"""
|
||||
Fields object for Problem3D_e.
|
||||
|
||||
:param BaseMesh mesh: mesh
|
||||
:param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'eSolution':'E'}
|
||||
@@ -180,6 +180,9 @@ class Fields3D_e(FieldsFDEM):
|
||||
'h' : ['eSolution','CCV','_h'],
|
||||
}
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields.__init__(self, mesh, survey, **kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
self._edgeCurl = self.survey.prob.mesh.edgeCurl
|
||||
@@ -254,7 +257,7 @@ class Fields3D_e(FieldsFDEM):
|
||||
"""
|
||||
|
||||
# assuming primary does not depend on the model
|
||||
return Zero()
|
||||
return src.ePrimaryDeriv(self.prob, v, adjoint) #Zero()
|
||||
|
||||
def _bPrimary(self, eSolution, srcList):
|
||||
"""
|
||||
@@ -423,12 +426,12 @@ class Fields3D_e(FieldsFDEM):
|
||||
|
||||
|
||||
|
||||
class Fields3D_b(FieldsFDEM):
|
||||
class Fields3D_b(Fields):
|
||||
"""
|
||||
Fields object for Problem3D_b.
|
||||
|
||||
:param BaseMesh mesh: mesh
|
||||
:param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'bSolution':'F'}
|
||||
@@ -443,6 +446,9 @@ class Fields3D_b(FieldsFDEM):
|
||||
'h' : ['bSolution','CCV','_h'],
|
||||
}
|
||||
|
||||
def __init__(self,mesh,survey,**kwargs):
|
||||
Fields.__init__(self,mesh,survey,**kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
self._edgeCurl = self.survey.prob.mesh.edgeCurl
|
||||
@@ -594,8 +600,8 @@ class Fields3D_b(FieldsFDEM):
|
||||
|
||||
|
||||
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 + src.ePrimaryDeriv(self.prob, v, adjoint)
|
||||
return self._MeSigmaIDeriv(w) * v - self._MeSigmaI * s_eDeriv + src.ePrimaryDeriv(self.prob, v, adjoint)
|
||||
|
||||
def _j(self, bSolution, srcList):
|
||||
"""
|
||||
@@ -687,12 +693,12 @@ class Fields3D_b(FieldsFDEM):
|
||||
return Zero()
|
||||
|
||||
|
||||
class Fields3D_j(FieldsFDEM):
|
||||
class Fields3D_j(Fields):
|
||||
"""
|
||||
Fields object for Problem3D_j.
|
||||
|
||||
:param BaseMesh mesh: mesh
|
||||
:param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'jSolution':'F'}
|
||||
@@ -707,6 +713,9 @@ class Fields3D_j(FieldsFDEM):
|
||||
'b' : ['jSolution','CCV','_b'],
|
||||
}
|
||||
|
||||
def __init__(self,mesh,survey,**kwargs):
|
||||
Fields.__init__(self,mesh,survey,**kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
self._edgeCurl = self.survey.prob.mesh.edgeCurl
|
||||
@@ -979,12 +988,12 @@ class Fields3D_j(FieldsFDEM):
|
||||
return 1./(1j * omega(src.freq)) * VI * (self._aveE2CCV * ( s_mDeriv(v) - self._edgeCurl.T * ( self._MfRhoDeriv(jSolution) * v ) ) )
|
||||
|
||||
|
||||
class Fields3D_h(FieldsFDEM):
|
||||
class Fields3D_h(Fields):
|
||||
"""
|
||||
Fields object for Problem3D_h.
|
||||
|
||||
:param BaseMesh mesh: mesh
|
||||
:param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'hSolution':'E'}
|
||||
@@ -999,6 +1008,9 @@ class Fields3D_h(FieldsFDEM):
|
||||
'b' : ['hSolution','CCV','_b'],
|
||||
}
|
||||
|
||||
def __init__(self,mesh,survey,**kwargs):
|
||||
Fields.__init__(self,mesh,survey,**kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
self._edgeCurl = self.survey.prob.mesh.edgeCurl
|
||||
|
||||
@@ -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 FieldsFDEM, Fields3D_e, Fields3D_b, Fields3D_h, Fields3D_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
|
||||
|
||||
@@ -31,11 +31,10 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
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}\\\)
|
||||
|
||||
"""
|
||||
|
||||
surveyPair = SurveyFDEM
|
||||
fieldsPair = FieldsFDEM
|
||||
fieldsPair = Fields
|
||||
|
||||
def fields(self, m):
|
||||
"""
|
||||
@@ -65,7 +64,7 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
|
||||
:param numpy.array m: inversion model (nP,)
|
||||
:param numpy.array v: vector which we take sensitivity product with (nP,)
|
||||
:param SimPEG.EM.FDEM.FieldsFDEM.FieldsFDEM u: fields object
|
||||
:param SimPEG.EM.FDEM.Fields u: fields object
|
||||
:rtype numpy.array:
|
||||
:return: Jv (ndata,)
|
||||
"""
|
||||
@@ -75,7 +74,8 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey)
|
||||
# Jv = self.dataPair(self.survey)
|
||||
Jv = []
|
||||
|
||||
for freq in self.survey.freqs:
|
||||
A = self.getA(freq)
|
||||
@@ -90,9 +90,9 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
for rx in src.rxList:
|
||||
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, f, df_dm_v)
|
||||
Jv.append(rx.evalDeriv(src, self.mesh, f, df_dm_v))
|
||||
Ainv.clean()
|
||||
return Utils.mkvc(Jv)
|
||||
return np.hstack(Jv)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""
|
||||
@@ -100,7 +100,7 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
|
||||
:param numpy.array m: inversion model (nP,)
|
||||
:param numpy.array v: vector which we take adjoint product with (nP,)
|
||||
:param SimPEG.EM.FDEM.FieldsFDEM.FieldsFDEM u: fields object
|
||||
:param SimPEG.EM.FDEM.Fields u: fields object
|
||||
:rtype numpy.array:
|
||||
:return: Jv (ndata,)
|
||||
"""
|
||||
@@ -154,8 +154,8 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
Evaluates the sources for a given frequency and puts them in matrix form
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: tuple
|
||||
: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':
|
||||
@@ -167,7 +167,6 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
smi, sei = src.eval(self)
|
||||
#Why are you adding?
|
||||
s_m[:,i] = s_m[:,i] + smi
|
||||
s_e[:,i] = s_e[:,i] + sei
|
||||
|
||||
@@ -195,7 +194,7 @@ class Problem3D_e(BaseFDEMProblem):
|
||||
|
||||
which we solve for :math:`\mathbf{e}`.
|
||||
|
||||
:param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
"""
|
||||
|
||||
_solutionType = 'eSolution'
|
||||
@@ -270,7 +269,7 @@ class Problem3D_e(BaseFDEMProblem):
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -306,7 +305,7 @@ class Problem3D_b(BaseFDEMProblem):
|
||||
.. note ::
|
||||
The inverse problem will not work with full anisotropy
|
||||
|
||||
:param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
"""
|
||||
|
||||
_solutionType = 'bSolution'
|
||||
@@ -401,7 +400,7 @@ class Problem3D_b(BaseFDEMProblem):
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -445,7 +444,6 @@ class Problem3D_j(BaseFDEMProblem):
|
||||
|
||||
\mathbf{h} = \\frac{1}{i \omega} \mathbf{M_{\mu}^e}^{-1} \\left(-\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{j} + \mathbf{M^e} \mathbf{s_m} \\right)
|
||||
|
||||
|
||||
and solve for \\\(\\\mathbf{j}\\\) using
|
||||
|
||||
.. math ::
|
||||
@@ -455,7 +453,7 @@ class Problem3D_j(BaseFDEMProblem):
|
||||
.. note::
|
||||
This implementation does not yet work with full anisotropy!!
|
||||
|
||||
:param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
"""
|
||||
|
||||
_solutionType = 'jSolution'
|
||||
@@ -531,8 +529,8 @@ class Problem3D_j(BaseFDEMProblem):
|
||||
\mathbf{RHS} = \mathbf{C} \mathbf{M_{\mu}^e}^{-1}\mathbf{s_m} -i\omega \mathbf{s_e}
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
:rtype: numpy.ndarray (nE, nSrc)
|
||||
:return: RHS
|
||||
"""
|
||||
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
@@ -551,7 +549,7 @@ class Problem3D_j(BaseFDEMProblem):
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -593,7 +591,7 @@ class Problem3D_h(BaseFDEMProblem):
|
||||
|
||||
\\left(\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{C} + i \omega \mathbf{M_{\mu}^e}\\right) \mathbf{h} = \mathbf{M^e} \mathbf{s_m} + \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{s_e}
|
||||
|
||||
:param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
"""
|
||||
|
||||
_solutionType = 'hSolution'
|
||||
@@ -610,11 +608,9 @@ class Problem3D_h(BaseFDEMProblem):
|
||||
.. math::
|
||||
\mathbf{A} = \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{C} + i \omega \mathbf{M_{\mu}^e}
|
||||
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: A
|
||||
|
||||
"""
|
||||
|
||||
MeMu = self.MeMu
|
||||
@@ -657,7 +653,6 @@ class Problem3D_h(BaseFDEMProblem):
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
|
||||
"""
|
||||
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
@@ -671,7 +666,7 @@ class Problem3D_h(BaseFDEMProblem):
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
|
||||
@@ -25,10 +25,10 @@ class BaseRx(SimPEG.Survey.BaseRx):
|
||||
|
||||
def eval(self, src, mesh, f):
|
||||
"""
|
||||
Project fields to receivers to get data.
|
||||
Project fields to recievers to get data.
|
||||
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param BaseMesh mesh: mesh used
|
||||
:param Source src: FDEM source
|
||||
:param Mesh mesh: mesh used
|
||||
:param Fields f: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
@@ -44,8 +44,8 @@ class BaseRx(SimPEG.Survey.BaseRx):
|
||||
"""
|
||||
Derivative of projected fields with respect to the inversion model times a vector.
|
||||
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param BaseMesh mesh: mesh used
|
||||
: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
|
||||
|
||||
+227
-29
@@ -23,8 +23,8 @@ class BaseSrc(Survey.BaseSrc):
|
||||
- :math:`s_m` : magnetic source term
|
||||
- :math:`s_e` : electric source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: tuple
|
||||
: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)
|
||||
@@ -37,10 +37,10 @@ class BaseSrc(Survey.BaseSrc):
|
||||
- :code:`s_mDeriv` : derivative of the magnetic source term
|
||||
- :code:`s_eDeriv` : derivative of the electric source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: tuple
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: tuple with magnetic source term and electric source term derivatives times a vector
|
||||
"""
|
||||
if v is not None:
|
||||
@@ -52,7 +52,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
Primary magnetic flux density
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic flux density
|
||||
"""
|
||||
@@ -60,11 +60,23 @@ class BaseSrc(Survey.BaseSrc):
|
||||
return Zero()
|
||||
return self._bPrimary
|
||||
|
||||
def bPrimaryDeriv(self, prob, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the primary magnetic flux density
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic flux density
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def hPrimary(self, prob):
|
||||
"""
|
||||
Primary magnetic field
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -72,11 +84,23 @@ class BaseSrc(Survey.BaseSrc):
|
||||
return Zero()
|
||||
return self._hPrimary
|
||||
|
||||
def hPrimaryDeriv(self, prob, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the primary magnetic field
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic flux density
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def ePrimary(self, prob):
|
||||
"""
|
||||
Primary electric field
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary electric field
|
||||
"""
|
||||
@@ -84,11 +108,23 @@ class BaseSrc(Survey.BaseSrc):
|
||||
return Zero()
|
||||
return self._ePrimary
|
||||
|
||||
def ePrimaryDeriv(self, prob, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the primary electric field
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic flux density
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def jPrimary(self, prob):
|
||||
"""
|
||||
Primary current density
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary current density
|
||||
"""
|
||||
@@ -96,11 +132,23 @@ class BaseSrc(Survey.BaseSrc):
|
||||
return Zero()
|
||||
return self._jPrimary
|
||||
|
||||
def jPrimaryDeriv(self, prob, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the primary current density
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic flux density
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: magnetic source term on mesh
|
||||
"""
|
||||
@@ -110,7 +158,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: electric source term on mesh
|
||||
"""
|
||||
@@ -120,7 +168,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
Derivative of magnetic source term with respect to the inversion model
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -133,7 +181,7 @@ class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
Derivative of electric source term with respect to the inversion model
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -162,7 +210,7 @@ class RawVec_e(BaseSrc):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: electric source term on mesh
|
||||
"""
|
||||
@@ -191,7 +239,7 @@ class RawVec_m(BaseSrc):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: magnetic source term on mesh
|
||||
"""
|
||||
@@ -220,7 +268,7 @@ class RawVec(BaseSrc):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: magnetic source term on mesh
|
||||
"""
|
||||
@@ -232,7 +280,7 @@ class RawVec(BaseSrc):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: electric source term on mesh
|
||||
"""
|
||||
@@ -301,7 +349,7 @@ class MagDipole(BaseSrc):
|
||||
"""
|
||||
The primary magnetic flux density from a magnetic vector potential
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -339,7 +387,7 @@ class MagDipole(BaseSrc):
|
||||
"""
|
||||
The primary magnetic field from a magnetic vector potential
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -350,7 +398,7 @@ class MagDipole(BaseSrc):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -364,7 +412,7 @@ class MagDipole(BaseSrc):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -416,7 +464,7 @@ class MagDipole_Bfield(BaseSrc):
|
||||
"""
|
||||
The primary magnetic flux density from the analytic solution for magnetic fields from a dipole
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -455,7 +503,7 @@ class MagDipole_Bfield(BaseSrc):
|
||||
"""
|
||||
The primary magnetic field from a magnetic vector potential
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -466,7 +514,7 @@ class MagDipole_Bfield(BaseSrc):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -479,7 +527,7 @@ class MagDipole_Bfield(BaseSrc):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -530,7 +578,7 @@ class CircularLoop(BaseSrc):
|
||||
"""
|
||||
The primary magnetic flux density from a magnetic vector potential
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -555,7 +603,7 @@ class CircularLoop(BaseSrc):
|
||||
a = MagneticLoopVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
|
||||
|
||||
else:
|
||||
srcfct = MagneticDipoleVectorPotential
|
||||
srcfct = MagneticLoopVectorPotential
|
||||
ax = srcfct(self.loc, gridX, 'x', self.radius, mu=self.mu)
|
||||
ay = srcfct(self.loc, gridY, 'y', self.radius, mu=self.mu)
|
||||
az = srcfct(self.loc, gridZ, 'z', self.radius, mu=self.mu)
|
||||
@@ -567,7 +615,7 @@ class CircularLoop(BaseSrc):
|
||||
"""
|
||||
The primary magnetic field from a magnetic vector potential
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -578,7 +626,7 @@ class CircularLoop(BaseSrc):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -591,7 +639,7 @@ class CircularLoop(BaseSrc):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:param Problem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -614,5 +662,155 @@ class CircularLoop(BaseSrc):
|
||||
return -C.T * (MMui_s * self.bPrimary(prob))
|
||||
|
||||
|
||||
class PrimSecSigma(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, freq, sigBack, ePrimary, **kwargs):
|
||||
self.sigBack = sigBack
|
||||
|
||||
BaseSrc.__init__(self, rxList, freq=freq, _ePrimary=ePrimary, **kwargs)
|
||||
|
||||
def s_e(self, prob):
|
||||
return (prob.MeSigma - prob.mesh.getEdgeInnerProduct(self.sigBack)) * self.ePrimary(prob)
|
||||
|
||||
def s_eDeriv(self, prob, v, adjoint=False):
|
||||
if adjoint:
|
||||
return prob.MeSigmaDeriv(self.ePrimary(prob)).T * v
|
||||
return prob.MeSigmaDeriv(self.ePrimary(prob)) * v
|
||||
|
||||
|
||||
class PrimSecMappedSigma(BaseSrc):
|
||||
|
||||
"""
|
||||
Primary-Secondary Source in which a mapping is provided to put the current model
|
||||
onto the primary mesh. This is solved on every model update.
|
||||
|
||||
There are a lot of layers to the derivatives here!
|
||||
|
||||
**Required**
|
||||
:param list rxList: Receiver List
|
||||
:param float freq: frequency
|
||||
:param ProblemFDEM primaryProblem: FDEM primary problem
|
||||
:param SurveyFDEM primarySurvey: FDEM primary survey
|
||||
|
||||
**Optional**
|
||||
:param Mapping map2meshSecondary: mapping current model to act as primary model on the secondary mesh
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, primaryProblem, primarySurvey, map2meshSecondary = None ,**kwargs):
|
||||
|
||||
self.primaryProblem = primaryProblem
|
||||
self.primarySurvey = primarySurvey
|
||||
|
||||
if self.primaryProblem.ispaired is False:
|
||||
self.primaryProblem.pair(self.primarySurvey)
|
||||
|
||||
self.map2meshSecondary = map2meshSecondary
|
||||
|
||||
BaseSrc.__init__(self, rxList, freq=freq, **kwargs)
|
||||
|
||||
def _ProjPrimary(self, prob):
|
||||
# if getattr(self, '__ProjPrimary', None) is None:
|
||||
return self.primaryProblem.mesh.getInterpolationMatCartMesh(prob.mesh, locType='F', locTypeTo='E')
|
||||
# return self.__ProjPrimary
|
||||
|
||||
|
||||
def _primaryFields(self, prob, fieldType=None):
|
||||
|
||||
# TODO: cache and check if prob.curModel has changed
|
||||
fields = self.primaryProblem.fields(prob.curModel.sigmaModel)
|
||||
|
||||
if fieldType is not None:
|
||||
return fields[:,fieldType]
|
||||
return fields
|
||||
|
||||
def _primaryFieldsDeriv(self, prob, v, adjoint=False, f=None):
|
||||
if adjoint:
|
||||
raise NotImplementedError
|
||||
|
||||
# TODO: this should not be hard-coded for j
|
||||
# jp = self._primaryFields(prob)[:,'j']
|
||||
|
||||
# TODO: pull apart Jvec so that don't have to copy paste this code in
|
||||
# A = self.primaryProblem.getA(self.freq)
|
||||
# Ainv = self.primaryProblem.Solver(A, **self.primaryProblem.solverOpts) # create the concept of Ainv (actually a solve)
|
||||
|
||||
if f is None:
|
||||
f = self._primaryFields(prob.curModel.sigmaModel)
|
||||
|
||||
freq = self.freq
|
||||
|
||||
A = self.primaryProblem.getA(freq)
|
||||
Ainv = self.primaryProblem.Solver(A, **self.primaryProblem.solverOpts) # create the concept of Ainv (actually a solve)
|
||||
|
||||
src = self.primarySurvey.srcList[0]
|
||||
# for src in self.survey.getSrcByFreq(freq):
|
||||
u_src = Utils.mkvc(f[src, self.primaryProblem._solutionType])
|
||||
dA_dm_v = self.primaryProblem.getADeriv(freq, u_src, v)
|
||||
dRHS_dm_v = self.primaryProblem.getRHSDeriv(freq, src, v)
|
||||
du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
|
||||
df_dmFun = getattr(f, '_{0}Deriv'.format('j'), 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)
|
||||
Ainv.clean()
|
||||
|
||||
return df_dm_v
|
||||
|
||||
# return self.primaryProblem.Jvec(prob.curModel, v, f=f)
|
||||
|
||||
def ePrimary(self, prob, f=None):
|
||||
if f is None:
|
||||
f = self._primaryFields(prob)
|
||||
|
||||
ep = self._ProjPrimary(prob) * (
|
||||
self.primaryProblem.MfI * (
|
||||
self.primaryProblem.MfRho * f[:,'j'])
|
||||
)
|
||||
|
||||
return Utils.mkvc(ep)
|
||||
|
||||
def ePrimaryDeriv(self, prob, v, adjoint=False, f=None):
|
||||
|
||||
if adjoint is True:
|
||||
raise NotImplementedError
|
||||
|
||||
if f is None:
|
||||
f = self._primaryFields(prob)
|
||||
|
||||
epDeriv = self._ProjPrimary(prob) * (
|
||||
self.primaryProblem.MfI * (
|
||||
(self.primaryProblem.MfRhoDeriv(f[:,'j']) * v)
|
||||
+
|
||||
(self.primaryProblem.MfRho * self._primaryFieldsDeriv(prob, v, f=f))
|
||||
)
|
||||
)
|
||||
|
||||
return Utils.mkvc(epDeriv)
|
||||
|
||||
|
||||
def s_e(self, prob):
|
||||
sigmaPrimary = self.map2meshSecondary * prob.curModel.sigmaModel
|
||||
|
||||
return Utils.mkvc((prob.MeSigma - prob.mesh.getEdgeInnerProduct(sigmaPrimary)) * self.ePrimary(prob))
|
||||
|
||||
|
||||
def s_eDeriv(self, prob, v, adjoint=False):
|
||||
if adjoint:
|
||||
raise NotImplementedError
|
||||
return prob.MeSigmaDeriv(self.ePrimary(prob)).T * v
|
||||
|
||||
sigmaPrimary = self.map2meshSecondary * prob.curModel.sigmaModel
|
||||
sigmaPrimaryDeriv = self.map2meshSecondary.deriv(prob.curModel.sigmaModel)
|
||||
|
||||
f = self._primaryFields(prob)
|
||||
ePrimary = self.ePrimary(prob,f=f)
|
||||
|
||||
return (prob.MeSigmaDeriv(ePrimary) * v
|
||||
- prob.mesh.getEdgeInnerProductDeriv(sigmaPrimary)(ePrimary) * sigmaPrimaryDeriv * v
|
||||
+ (prob.MeSigma - prob.mesh.getEdgeInnerProduct(sigmaPrimary)) * self.ePrimaryDeriv(prob, v, None, f=f)
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,14 @@ class BaseRx(SimPEG.Survey.BaseRx):
|
||||
elif adjoint:
|
||||
return P.T*v
|
||||
|
||||
# DC.Rx.Dipole(locs)
|
||||
# DC.Rx.Pole(locs)
|
||||
class Pole(BaseRx):
|
||||
|
||||
def __init__(self, locs, rxType = 'phi', **kwargs):
|
||||
BaseRx.__init__(self, locs, rxType)
|
||||
|
||||
|
||||
# DC.Rx.Dipole(locsM, locsN)
|
||||
class Dipole(BaseRx):
|
||||
|
||||
def __init__(self, locsM, locsN, rxType = 'phi', **kwargs):
|
||||
|
||||
@@ -112,7 +112,7 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param numpy.ndarray v: vector (model object)
|
||||
:param FieldsTDEM f: Fields resulting from m
|
||||
:param simpegEM.TDEM.FieldsTDEM f: Fields resulting from m
|
||||
:rtype: numpy.ndarray
|
||||
:return: w (data object)
|
||||
|
||||
@@ -136,8 +136,8 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param numpy.ndarray v: vector (or a :class:`SimPEG.Survey.Data` object)
|
||||
:param FieldsTDEM u: Fields resulting from m
|
||||
:param numpy.ndarray,SimPEG.Survey.Data v: vector (data object)
|
||||
:param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m
|
||||
:rtype: numpy.ndarray
|
||||
:return: w (model object)
|
||||
|
||||
|
||||
+13
-13
@@ -87,8 +87,8 @@ class ProblemTDEM_b(BaseTDEMProblem):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param numpy.array vec: vector (like a model)
|
||||
:param FieldsTDEM u: Fields resulting from m
|
||||
:rtype: FieldsTDEM
|
||||
:param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:return: f
|
||||
|
||||
Multiply G by a vector
|
||||
@@ -125,9 +125,9 @@ class ProblemTDEM_b(BaseTDEMProblem):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param numpy.array vec: vector (like a fields)
|
||||
:param FieldsTDEM u: Fields resulting from m
|
||||
:rtype: numpy.ndarray
|
||||
:return: p (like a model)
|
||||
:param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m
|
||||
:rtype: np.ndarray (like a model)
|
||||
:return: p
|
||||
|
||||
Multiply G.T by a vector
|
||||
"""
|
||||
@@ -153,8 +153,8 @@ class ProblemTDEM_b(BaseTDEMProblem):
|
||||
def solveAh(self, m, p):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param FieldsTDEM p: Fields object
|
||||
:rtype: FieldsTDEM
|
||||
:param simpegEM.TDEM.FieldsTDEM p: Fields object
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:return: y
|
||||
|
||||
Solve the block-matrix system \\\(\\\hat{A} \\\hat{y} = \\\hat{p}\\\):
|
||||
@@ -200,8 +200,8 @@ class ProblemTDEM_b(BaseTDEMProblem):
|
||||
def solveAht(self, m, p):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param FieldsTDEM p: Fields object
|
||||
:rtype: FieldsTDEM
|
||||
:param simpegEM.TDEM.FieldsTDEM p: Fields object
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:return: y
|
||||
|
||||
Solve the block-matrix system \\\(\\\hat{A}^\\\\top \\\hat{y} = \\\hat{p}\\\):
|
||||
@@ -270,8 +270,8 @@ class ProblemTDEM_b(BaseTDEMProblem):
|
||||
def _AhVec(self, m, vec):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param FieldsTDEM vec: Fields object
|
||||
:rtype: FieldsTDEM
|
||||
:param simpegEM.TDEM.FieldsTDEM vec: Fields object
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:return: f
|
||||
|
||||
Multiply the matrix \\\(\\\hat{A}\\\) by a fields vector where
|
||||
@@ -315,8 +315,8 @@ class ProblemTDEM_b(BaseTDEMProblem):
|
||||
def _AhtVec(self, m, vec):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param FieldsTDEM vec: Fields object
|
||||
:rtype: FieldsTDEM
|
||||
:param simpegEM.TDEM.FieldsTDEM vec: Fields object
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:return: f
|
||||
|
||||
Multiply the matrix \\\(\\\hat{A}\\\) by a fields vector where
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from SimPEG import *
|
||||
import SimPEG.EM.Static.DC as DC
|
||||
import SimPEG.DCIP as DC
|
||||
|
||||
def run(plotIt=True):
|
||||
def run(plotIt=False):
|
||||
cs = 25.
|
||||
hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
@@ -21,10 +21,10 @@ def run(plotIt=True):
|
||||
# ax.plot(xyz_rxP[:,0],xyz_rxP[:,1], 'w.')
|
||||
# ax.plot(xyz_rxN[:,0],xyz_rxN[:,1], 'r.', ms = 3)
|
||||
|
||||
rx = DC.Rx.Dipole(xyz_rxP, xyz_rxN)
|
||||
src = DC.Src.Dipole([rx], np.r_[-200, 0, -12.5], np.r_[+200, 0, -12.5])
|
||||
survey = DC.Survey([src])
|
||||
problem = DC.Problem3D_CC(mesh)
|
||||
rx = DC.RxDipole(xyz_rxP, xyz_rxN)
|
||||
src = DC.SrcDipole([rx], [-200, 0, -12.5], [+200, 0, -12.5])
|
||||
survey = DC.SurveyDC([src])
|
||||
problem = DC.ProblemDC_CC(mesh)
|
||||
problem.pair(survey)
|
||||
try:
|
||||
from pymatsolver import MumpsSolver
|
||||
@@ -65,4 +65,4 @@ def run(plotIt=True):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print run()
|
||||
print run(plotIt=True)
|
||||
|
||||
@@ -19,13 +19,10 @@ def run(plotIt=True):
|
||||
Morrison Casing Model, and the results are used in a 2016 SEG abstract by
|
||||
Yang et al.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
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.
|
||||
- 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
|
||||
@@ -218,7 +215,7 @@ def run(plotIt=True):
|
||||
# ------------ Problem and Survey ---------------
|
||||
survey = FDEM.Survey(sg_p + dg_p)
|
||||
mapping = [('sigma', Maps.IdentityMap(mesh))]
|
||||
problem = FDEM.Problem3D_h(mesh, mapping=mapping, Solver=solver)
|
||||
problem = FDEM.Problem3D_h(mesh, mapping=mapping)
|
||||
problem.pair(survey)
|
||||
|
||||
# ------------- Solve ---------------------------
|
||||
|
||||
+31
-12
@@ -1,25 +1,22 @@
|
||||
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(sigma, invProp=True, invMat=True)
|
||||
A = -D*MsigI*D.T
|
||||
Msigi = mesh.getFaceInnerProduct(1./sigma)
|
||||
MsigI = Utils.sdInv(Msigi)
|
||||
A = D*MsigI*G
|
||||
A[-1,-1] /= mesh.vol[-1] # Remove null space
|
||||
rhs = np.zeros(mesh.nC)
|
||||
txind = Utils.meshutils.closestPoints(mesh, pts)
|
||||
@@ -40,17 +37,39 @@ 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)
|
||||
dat = rM.plotImage(phirM, ax=axes[1], 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)
|
||||
|
||||
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()
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from SimPEG import *
|
||||
|
||||
|
||||
def run(N=100, plotIt=True):
|
||||
def run(N=200, plotIt=True):
|
||||
"""
|
||||
Inversion: Linear Problem
|
||||
=========================
|
||||
@@ -18,8 +18,6 @@ def run(N=100, plotIt=True):
|
||||
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.
|
||||
@@ -42,35 +40,67 @@ def run(N=100, plotIt=True):
|
||||
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.wght = wr
|
||||
|
||||
dmis = DataMisfit.l2_DataMisfit(survey)
|
||||
dmis.Wd = 1./wd
|
||||
|
||||
opt = Optimization.ProjectedGNCG(maxIter=30,lower=-2.,upper=2., maxIterCG= 20, 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
|
||||
|
||||
#==============================================================================
|
||||
# fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2))
|
||||
# dmdx = reg.mesh.cellDiffxStencil * mrec
|
||||
# plt.plot(np.sort(dmdx))
|
||||
#==============================================================================
|
||||
|
||||
#reg.recModel = mrec
|
||||
reg.wght = np.ones(mesh.nC)
|
||||
reg.mref = np.zeros(mesh.nC)
|
||||
|
||||
reg.eps_p = 5e-2
|
||||
reg.eps_q = 1e-2
|
||||
reg.norms = [0., 0., 2., 2.]
|
||||
reg.wght = wr
|
||||
|
||||
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()
|
||||
|
||||
# Set the IRLS directive, penalize the lowest 25 percentile of model values
|
||||
# Start with an l2-l2, then switch to lp-norms
|
||||
norms = [0., 0., 2., 2.]
|
||||
IRLS = Directives.Update_IRLS( norms=norms, prctile = 25, maxIRLSiter = 15, minGNiter=3)
|
||||
opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 20, tolCG = 1e-3)
|
||||
invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.)
|
||||
beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1)
|
||||
#betaest = Directives.BetaEstimate_ByEig()
|
||||
target = Directives.TargetMisfit()
|
||||
IRLS =Directives.Update_IRLS( phi_m_last = phim, phi_d_last = phid )
|
||||
|
||||
inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest,update_Jacobi])
|
||||
inv = Inversion.BaseInversion(invProb, directiveList=[beta,IRLS])
|
||||
|
||||
m0 = mrec
|
||||
|
||||
# Run inversion
|
||||
mrec = inv.run(m0)
|
||||
@@ -87,7 +117,7 @@ def run(N=100, plotIt=True):
|
||||
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].plot(mesh.vectorCCx, ml2, 'r-')
|
||||
#axes[1].legend(('True Model', 'Recovered Model'))
|
||||
axes[1].set_ylim(-1.0,1.25)
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import matplotlib.pyplot as plt
|
||||
def run(plotIt=True):
|
||||
"""
|
||||
MT: 1D: Inversion
|
||||
=================
|
||||
=======================
|
||||
|
||||
Forward model 1D MT data.
|
||||
Setup and run a MT 1D inversion.
|
||||
@@ -50,7 +50,7 @@ def run(plotIt=True):
|
||||
m_0 = np.log(sigma_0[active])
|
||||
|
||||
# Set the mapping
|
||||
actMap = simpeg.Maps.InjectActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx)
|
||||
actMap = simpeg.Maps.ActiveCells(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
|
||||
@@ -76,7 +76,7 @@ def run(plotIt=True):
|
||||
survey.dobs = survey.dtrue + 0.025*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
|
||||
|
||||
if plotIt:
|
||||
fig = MT.Utils.dataUtils.plotMT1DModelData(problem, [m_0])
|
||||
fig = MT.Utils.dataUtils.plotMT1DModelData(problem)
|
||||
fig.suptitle('Target - smooth true')
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ except:
|
||||
def run(plotIt=True, nFreq=1):
|
||||
"""
|
||||
MT: 3D: Forward
|
||||
===============
|
||||
=======================
|
||||
|
||||
Forward model 3D MT data.
|
||||
|
||||
@@ -46,15 +46,16 @@ def run(plotIt=True, nFreq=1):
|
||||
survey = MT.Survey(srcList)
|
||||
|
||||
## Setup the problem object
|
||||
problem = MT.Problem3D.eForm_ps(M, sigmaPrimary=sigBG, Solver=Solver)
|
||||
problem = MT.Problem3D.eForm_ps(M, sigmaPrimary=sigBG)
|
||||
problem.pair(survey)
|
||||
problem.Solver = Solver
|
||||
|
||||
# Calculate the data
|
||||
fields = problem.fields(sig)
|
||||
dataVec = survey.eval(fields)
|
||||
|
||||
# Make the data
|
||||
mtData = MT.Data(survey, dataVec)
|
||||
mtData = MT.Data(survey,dataVec)
|
||||
# Add plots
|
||||
if plotIt:
|
||||
pass
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
from SimPEG import Mesh, Maps, np
|
||||
|
||||
def run(plotIt=True):
|
||||
"""
|
||||
|
||||
Maps: ComboMaps
|
||||
===============
|
||||
|
||||
We will use an example where we want a 1D layered earth as
|
||||
our model, but we want to map this to a 2D discretization to do our forward
|
||||
modeling. We will also assume that we are working in log conductivity still,
|
||||
so after the transformation we want to map to conductivity space.
|
||||
To do this we will introduce the vertical 1D map (:class:`SimPEG.Maps.SurjectVertical1D`),
|
||||
which does the first part of what we just described. The second part will be
|
||||
done by the :class:`SimPEG.Maps.ExpMap` described above.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
M = Mesh.TensorMesh([7,5])
|
||||
v1dMap = Maps.SurjectVertical1D(M)
|
||||
expMap = Maps.ExpMap(M)
|
||||
myMap = expMap * v1dMap
|
||||
m = np.r_[0.2,1,0.1,2,2.9] # only 5 model parameters!
|
||||
sig = myMap * m
|
||||
|
||||
If you noticed, it was pretty easy to combine maps. What is even cooler is
|
||||
that the derivatives also are made for you (if everything goes right).
|
||||
Just to be sure that the derivative is correct, you should always run the test
|
||||
on the mapping that you create.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
M = Mesh.TensorMesh([7,5])
|
||||
v1dMap = Maps.SurjectVertical1D(M)
|
||||
expMap = Maps.ExpMap(M)
|
||||
myMap = expMap * v1dMap
|
||||
m = np.r_[0.2,1,0.1,2,2.9] # only 5 model parameters!
|
||||
sig = myMap * m
|
||||
|
||||
if not plotIt: return
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
figs, axs = plt.subplots(1,2)
|
||||
axs[0].plot(m, M.vectorCCy, 'b-o')
|
||||
axs[0].set_title('Model')
|
||||
axs[0].set_ylabel('Depth, y')
|
||||
axs[0].set_xlabel('Value, $m_i$')
|
||||
axs[0].set_xlim(0,3)
|
||||
axs[0].set_ylim(0,1)
|
||||
clbar = plt.colorbar(M.plotImage(sig,ax=axs[1],grid=True,gridOpts=dict(color='grey'))[0])
|
||||
axs[1].set_title('Physical Property')
|
||||
axs[1].set_ylabel('Depth, y')
|
||||
clbar.set_label('$\sigma = \exp(\mathbf{P}m)$')
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
from SimPEG import Mesh, Maps, Utils
|
||||
|
||||
def run(plotIt=True):
|
||||
"""
|
||||
|
||||
Maps: Mesh2Mesh
|
||||
===============
|
||||
|
||||
This mapping allows you to go from one mesh to another.
|
||||
|
||||
"""
|
||||
|
||||
M = Mesh.TensorMesh([100,100])
|
||||
h1 = Utils.meshTensor([(6,7,-1.5),(6,10),(6,7,1.5)])
|
||||
h1 = h1/h1.sum()
|
||||
M2 = Mesh.TensorMesh([h1,h1])
|
||||
V = Utils.ModelBuilder.randomModel(M.vnC, seed=79, its=50)
|
||||
v = Utils.mkvc(V)
|
||||
modh = Maps.Mesh2Mesh([M,M2])
|
||||
modH = Maps.Mesh2Mesh([M2,M])
|
||||
H = modH * v
|
||||
h = modh * H
|
||||
|
||||
if not plotIt: return
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
ax = plt.subplot(131)
|
||||
M.plotImage(v, ax=ax)
|
||||
ax.set_title('Fine Mesh (Original)')
|
||||
ax = plt.subplot(132)
|
||||
M2.plotImage(H,clim=[0,1],ax=ax)
|
||||
ax.set_title('Course Mesh')
|
||||
ax = plt.subplot(133)
|
||||
M.plotImage(h,clim=[0,1],ax=ax)
|
||||
ax.set_title('Fine Mesh (Interpolated)')
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
from SimPEG import Mesh, Utils, np
|
||||
|
||||
from SimPEG import *
|
||||
|
||||
def run(plotIt=True):
|
||||
"""
|
||||
@@ -9,15 +8,15 @@ def run(plotIt=True):
|
||||
Here we show SimPEG used to create three different types of meshes.
|
||||
|
||||
"""
|
||||
sz = [16, 16]
|
||||
sz = [16,16]
|
||||
tM = Mesh.TensorMesh(sz)
|
||||
qM = Mesh.TreeMesh(sz)
|
||||
qM.refine(lambda cell: 4 if np.sqrt(((np.r_[cell.center]-0.5)**2).sum()) < 0.4 else 3)
|
||||
rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz, 'rotate'))
|
||||
rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz,'rotate'))
|
||||
|
||||
if plotIt:
|
||||
import matplotlib.pyplot as plt
|
||||
fig, axes = plt.subplots(1, 3, figsize=(14, 5))
|
||||
fig, axes = plt.subplots(1,3,figsize=(14,5))
|
||||
opts = {}
|
||||
tM.plotGrid(ax=axes[0], **opts)
|
||||
axes[0].set_title('TensorMesh')
|
||||
|
||||
@@ -1,65 +0,0 @@
|
||||
from SimPEG import Mesh, np, PF
|
||||
|
||||
|
||||
def run(plotIt=True):
|
||||
"""
|
||||
PF: Magnetics: Analytics
|
||||
========================
|
||||
|
||||
Comparing the magnetics field in Vancouver to Seoul
|
||||
|
||||
"""
|
||||
|
||||
xr = np.linspace(-300, 300, 41)
|
||||
yr = np.linspace(-300, 300, 41)
|
||||
X, Y = np.meshgrid(xr, yr)
|
||||
Z = np.ones((np.size(xr), np.size(yr)))*150
|
||||
|
||||
# Bz component in Korea
|
||||
inckr = -8. + 3./60
|
||||
deckr = 54. + 9./60
|
||||
btotkr = 50898.6
|
||||
Bokr = PF.MagAnalytics.IDTtoxyz(inckr, deckr, btotkr)
|
||||
|
||||
bx, by, bz = PF.MagAnalytics.MagSphereAnaFunA(
|
||||
X, Y, Z, 100., 0., 0., 0., 0.01, Bokr, 'secondary'
|
||||
)
|
||||
Bzkr = np.reshape(bz, (np.size(xr), np.size(yr)), order='F')
|
||||
|
||||
# Bz component in Canada
|
||||
incca = 16. + 49./60
|
||||
decca = 70. + 19./60
|
||||
btotca = 54692.1
|
||||
Boca = PF.MagAnalytics.IDTtoxyz(incca, decca, btotca)
|
||||
|
||||
bx, by, bz = PF.MagAnalytics.MagSphereAnaFunA(
|
||||
X, Y, Z, 100., 0., 0., 0., 0.01, Boca, 'secondary'
|
||||
)
|
||||
Bzca = np.reshape(bz, (np.size(xr), np.size(yr)), order='F')
|
||||
|
||||
if plotIt:
|
||||
import matplotlib.pyplot as plt
|
||||
from mpl_toolkits.axes_grid1 import make_axes_locatable
|
||||
fig = plt.figure(figsize=(14, 5))
|
||||
|
||||
ax1 = plt.subplot(121)
|
||||
dat1 = plt.imshow(Bzkr, extent=[min(xr), max(xr), min(yr), max(yr)])
|
||||
divider = make_axes_locatable(ax1)
|
||||
cax1 = divider.append_axes("right", size="5%", pad=0.05)
|
||||
ax1.set_xlabel('East-West (m)')
|
||||
ax1.set_ylabel('South-North (m)')
|
||||
plt.colorbar(dat1, cax=cax1)
|
||||
ax1.set_title('$B_z$ field at Seoul, South Korea')
|
||||
|
||||
ax2 = plt.subplot(122)
|
||||
dat2 = plt.imshow(Bzca, extent=[min(xr), max(xr), min(yr), max(yr)])
|
||||
divider = make_axes_locatable(ax2)
|
||||
cax2 = divider.append_axes("right", size="5%", pad=0.05)
|
||||
ax2.set_xlabel('East-West (m)')
|
||||
ax2.set_ylabel('South-North (m)')
|
||||
plt.colorbar(dat2, cax=cax2)
|
||||
ax2.set_title('$B_z$ field at Vancouver, Canada')
|
||||
plt.show()
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
@@ -2,12 +2,8 @@ from SimPEG import *
|
||||
from SimPEG.Utils import surface2ind_topo
|
||||
|
||||
|
||||
def run(plotIt=True, nx=5, ny=5):
|
||||
def run(plotIt=False, nx = 5, ny = 5):
|
||||
"""
|
||||
|
||||
Utils: surface2ind_topo
|
||||
=======================
|
||||
|
||||
Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below
|
||||
a topographic surface.
|
||||
|
||||
@@ -17,25 +13,27 @@ def run(plotIt=True, nx=5, ny=5):
|
||||
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
|
||||
Topo = np.hstack([Utils.mkvc(xtopo,2),Utils.mkvc(topo,2)]) #make it an array
|
||||
|
||||
indcc = surface2ind_topo(mesh, Topo, 'CC')
|
||||
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))
|
||||
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)
|
||||
ax.pcolor(mesh.vectorNx,mesh.vectorNy,masked_array.T, cmap = plt.cm.gray,alpha=0.2)
|
||||
plt.show()
|
||||
|
||||
|
||||
|
||||
@@ -8,11 +8,9 @@ import EM_FDEM_Analytic_MagDipoleWholespace
|
||||
import EM_Schenkel_Morrison_Casing
|
||||
import EM_TDEM_1D_Inversion
|
||||
import FLOW_Richards_1D_Celia1990
|
||||
import Forward_BasicDirectCurrent
|
||||
import Inversion_IRLS
|
||||
import Inversion_Linear
|
||||
import Maps_ComboMaps
|
||||
import Maps_Mesh2Mesh
|
||||
import Mesh_Basic_ForwardDC
|
||||
import Mesh_Basic_PlotImage
|
||||
import Mesh_Basic_Types
|
||||
import Mesh_Operators_CahnHilliard
|
||||
@@ -24,7 +22,7 @@ import MT_1D_ForwardAndInversion
|
||||
import MT_3D_Foward
|
||||
import Utils_surface2ind_topo
|
||||
|
||||
__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Inversion_IRLS", "Inversion_Linear", "Maps_ComboMaps", "Maps_Mesh2Mesh", "Mesh_Basic_ForwardDC", "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", "Utils_surface2ind_topo"]
|
||||
__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "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", "Utils_surface2ind_topo"]
|
||||
|
||||
##### AUTOIMPORTS #####
|
||||
|
||||
@@ -40,7 +38,7 @@ if __name__ == '__main__':
|
||||
|
||||
# Create the examples dir in the docs folder.
|
||||
fName = os.path.realpath(__file__)
|
||||
docExamplesDir = os.path.sep.join(fName.split(os.path.sep)[:-3] + ['docs', 'content', 'examples'])
|
||||
docExamplesDir = os.path.sep.join(fName.split(os.path.sep)[:-3] + ['docs', 'examples'])
|
||||
shutil.rmtree(docExamplesDir)
|
||||
os.makedirs(docExamplesDir)
|
||||
|
||||
@@ -97,12 +95,12 @@ if __name__ == '__main__':
|
||||
from SimPEG import Examples
|
||||
Examples.%s.run()
|
||||
|
||||
.. literalinclude:: ../../../SimPEG/Examples/%s.py
|
||||
.. literalinclude:: ../../SimPEG/Examples/%s.py
|
||||
:language: python
|
||||
:linenos:
|
||||
"""%(name,doc,name,name)
|
||||
|
||||
rst = os.path.sep.join((filePath.split(os.path.sep)[:-3] + ['docs', 'content', 'examples', name + '.rst']))
|
||||
rst = os.path.sep.join((filePath.split(os.path.sep)[:-3] + ['docs', 'examples', name + '.rst']))
|
||||
|
||||
print 'Creating: %s.rst'%name
|
||||
f = open(rst, 'w')
|
||||
|
||||
@@ -31,7 +31,7 @@ class NonLinearMap(object):
|
||||
"""
|
||||
:param numpy.array u: fields
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: derivative of transformed model
|
||||
|
||||
The *transform* changes the model into the physical property.
|
||||
@@ -44,7 +44,7 @@ class NonLinearMap(object):
|
||||
"""
|
||||
:param numpy.array u: fields
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: derivative of transformed model
|
||||
|
||||
The *transform* changes the model into the physical property.
|
||||
|
||||
+2
-2
@@ -86,7 +86,7 @@ class polxy_1Dprimary(BaseMTSrc):
|
||||
Get the electrical field source
|
||||
"""
|
||||
e_p = self.ePrimary(problem)
|
||||
Map_sigma_p = Maps.SurjectVertical1D(problem.mesh)
|
||||
Map_sigma_p = Maps.Vertical1DMap(problem.mesh)
|
||||
sigma_p = Map_sigma_p._transform(self.sigma1d)
|
||||
# Make mass matrix
|
||||
# Note: M(sig) - M(sig_p) = M(sig - sig_p)
|
||||
@@ -163,7 +163,7 @@ class polxy_3Dprimary(BaseMTSrc):
|
||||
Get the electrical field source
|
||||
"""
|
||||
e_p = self.ePrimary(problem)
|
||||
Map_sigma_p = Maps.SurjectVertical1D(problem.mesh)
|
||||
Map_sigma_p = Maps.Vertical1DMap(problem.mesh)
|
||||
sigma_p = Map_sigma_p._transform(self.sigma1d)
|
||||
# Make mass matrix
|
||||
# Note: M(sig) - M(sig_p) = M(sig - sig_p)
|
||||
|
||||
@@ -19,7 +19,7 @@ def getAppRes(MTdata):
|
||||
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(MTdata,rotAngle):
|
||||
'''
|
||||
Function that rotates clockwist by rotAngle (- negative for a counter-clockwise rotation)
|
||||
'''
|
||||
@@ -44,19 +44,19 @@ def rotateData(MTdata, rotAngle):
|
||||
return MT.Data.fromRecArray(outRec)
|
||||
|
||||
|
||||
def appResPhs(freq, z):
|
||||
def appResPhs(freq,z):
|
||||
app_res = ((1./(8e-7*np.pi**2))/freq)*np.abs(z)**2
|
||||
app_phs = np.arctan2(z.imag,z.real)*(180/np.pi)
|
||||
return app_res, app_phs
|
||||
|
||||
def skindepth(rho, freq):
|
||||
def skindepth(rho,freq):
|
||||
''' Function to calculate the skindepth of EM waves'''
|
||||
return np.sqrt( (rho*((1/(freq * mu_0 * np.pi )))))
|
||||
|
||||
def rec2ndarr(x, dt=float):
|
||||
def rec2ndarr(x,dt=float):
|
||||
return x.view((dt, len(x.dtype.names)))
|
||||
|
||||
def makeAnalyticSolution(mesh, model, elev, freqs):
|
||||
def makeAnalyticSolution(mesh,model,elev,freqs):
|
||||
from SimPEG import MT
|
||||
data1D = []
|
||||
for freq in freqs:
|
||||
@@ -70,7 +70,7 @@ def makeAnalyticSolution(mesh, model, elev, freqs):
|
||||
dataRec = np.array(data1D,dtype=[('freq',float),('x',float),('y',float),('z',float),('zyx',complex)])
|
||||
return dataRec
|
||||
|
||||
def plotMT1DModelData(problem, models, symList=None):
|
||||
def plotMT1DModelData(problem,models,symList=None):
|
||||
from SimPEG import MT
|
||||
# Setup the figure
|
||||
fontSize = 15
|
||||
|
||||
+783
-14
@@ -1,3 +1,4 @@
|
||||
from __future__ import division
|
||||
import Utils, numpy as np, scipy.sparse as sp
|
||||
from scipy.sparse.linalg import LinearOperator
|
||||
from Tests import checkDerivative
|
||||
@@ -5,6 +6,7 @@ from PropMaps import PropMap, Property
|
||||
from numpy.polynomial import polynomial
|
||||
from scipy.interpolate import UnivariateSpline
|
||||
import warnings
|
||||
from SimPEG.Utils import Zero
|
||||
|
||||
class IdentityMap(object):
|
||||
"""
|
||||
@@ -17,7 +19,7 @@ class IdentityMap(object):
|
||||
Utils.setKwargs(self, **kwargs)
|
||||
|
||||
if nP is not None:
|
||||
assert type(nP) in [int, long], ' Number of parameters must be an integer.'
|
||||
assert type(nP) in [int, long, np.int64], ' Number of parameters must be an integer.'
|
||||
|
||||
self.mesh = mesh
|
||||
self._nP = nP
|
||||
@@ -41,8 +43,8 @@ class IdentityMap(object):
|
||||
If this is a meshless mapping (i.e. nP is defined independently)
|
||||
the shape will be the the shape (nP,nP).
|
||||
|
||||
:rtype: tuple
|
||||
:return: shape of the operator as a tuple (int,int)
|
||||
:rtype: (int,int)
|
||||
:return: shape of the operator as a tuple
|
||||
"""
|
||||
if self._nP is not None:
|
||||
return (self.nP, self.nP)
|
||||
@@ -86,7 +88,7 @@ class IdentityMap(object):
|
||||
The derivative of the transformation.
|
||||
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: derivative of transformed model
|
||||
|
||||
"""
|
||||
@@ -129,7 +131,15 @@ class IdentityMap(object):
|
||||
|
||||
|
||||
class ComboMap(IdentityMap):
|
||||
"""Combination of various maps."""
|
||||
"""
|
||||
Combination of various maps.
|
||||
|
||||
The ComboMap holds the information for multiplying and combining
|
||||
maps. It also uses the chain rule to create the derivative.
|
||||
Remember, any time that you make your own combination of mappings
|
||||
be sure to test that the derivative is correct.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, maps, **kwargs):
|
||||
IdentityMap.__init__(self, None, **kwargs)
|
||||
@@ -178,6 +188,12 @@ class ComboMap(IdentityMap):
|
||||
|
||||
class ExpMap(IdentityMap):
|
||||
"""
|
||||
Electrical conductivity varies over many orders of magnitude, so it is a common
|
||||
technique when solving the inverse problem to parameterize and optimize in terms
|
||||
of log conductivity. This makes sense not only because it ensures all conductivities
|
||||
will be positive, but because this is fundamentally the space where conductivity
|
||||
lives (i.e. it varies logarithmically).
|
||||
|
||||
Changes the model into the physical property.
|
||||
|
||||
A common example of this is to invert for electrical conductivity
|
||||
@@ -216,7 +232,7 @@ class ExpMap(IdentityMap):
|
||||
def deriv(self, m):
|
||||
"""
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: derivative of transformed model
|
||||
|
||||
The *transform* changes the model into the physical property.
|
||||
@@ -366,7 +382,7 @@ class SurjectVertical1D(IdentityMap):
|
||||
def deriv(self, m):
|
||||
"""
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: derivative of transformed model
|
||||
"""
|
||||
repNum = self.mesh.vnC[:self.mesh.dim-1].prod()
|
||||
@@ -427,7 +443,7 @@ class Surject2Dto3D(IdentityMap):
|
||||
def deriv(self, m):
|
||||
"""
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: derivative of transformed model
|
||||
"""
|
||||
inds = self * np.arange(self.nP)
|
||||
@@ -449,6 +465,32 @@ class Mesh2Mesh(IdentityMap):
|
||||
"""
|
||||
Takes a model on one mesh are translates it to another mesh.
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import *
|
||||
import matplotlib.pyplot as plt
|
||||
M = Mesh.TensorMesh([100,100])
|
||||
h1 = Utils.meshTensor([(6,7,-1.5),(6,10),(6,7,1.5)])
|
||||
h1 = h1/h1.sum()
|
||||
M2 = Mesh.TensorMesh([h1,h1])
|
||||
V = Utils.ModelBuilder.randomModel(M.vnC, seed=79, its=50)
|
||||
v = Utils.mkvc(V)
|
||||
modh = Maps.Mesh2Mesh([M,M2])
|
||||
modH = Maps.Mesh2Mesh([M2,M])
|
||||
H = modH * v
|
||||
h = modh * H
|
||||
ax = plt.subplot(131)
|
||||
M.plotImage(v, ax=ax)
|
||||
ax.set_title('Fine Mesh (Original)')
|
||||
ax = plt.subplot(132)
|
||||
M2.plotImage(H,clim=[0,1],ax=ax)
|
||||
ax.set_title('Course Mesh')
|
||||
ax = plt.subplot(133)
|
||||
M.plotImage(h,clim=[0,1],ax=ax)
|
||||
ax.set_title('Fine Mesh (Interpolated)')
|
||||
plt.show()
|
||||
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, meshes, **kwargs):
|
||||
@@ -501,13 +543,19 @@ class InjectActiveCells(IdentityMap):
|
||||
self.indInactive = np.logical_not(indActive)
|
||||
if Utils.isScalar(valInactive):
|
||||
self.valInactive = np.ones(self.nC)*float(valInactive)
|
||||
self.valInactive[self.indActive] = 0.
|
||||
else:
|
||||
self.valInactive = np.ones(self.nC)
|
||||
self.valInactive[self.indInactive] = valInactive.copy()
|
||||
|
||||
self.valInactive[self.indActive] = 0
|
||||
if len(valInactive) == sum(self.indInactive):
|
||||
self.valInactive = np.zeros(nC)
|
||||
self.valInactive[self.indInactive] = valInactive.copy()
|
||||
else:
|
||||
assert len(self.valInactive) == self.nC, 'valInactive must be the size of nC or nInactive'
|
||||
self.valInactive = valInactive.copy()
|
||||
if any(self.valInactive[self.indActive] != 0.):
|
||||
warnings.warn('the inactive has non-zero values in the active set.')
|
||||
|
||||
inds = np.nonzero(self.indActive)[0]
|
||||
# inds[self.indActive]
|
||||
self.P = sp.csr_matrix((np.ones(inds.size),(inds, range(inds.size))), shape=(self.nC, self.nP))
|
||||
|
||||
@property
|
||||
@@ -576,6 +624,37 @@ class Weighting(IdentityMap):
|
||||
def deriv(self, m):
|
||||
return self.P
|
||||
|
||||
class Projection(IdentityMap):
|
||||
"""
|
||||
A map to rearrange parameters
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def __init__(self, indTo, indFrom, shape, mesh=None, **kwargs):
|
||||
|
||||
assert len(indTo) == len(indFrom)
|
||||
|
||||
self.P = sp.csr_matrix((np.ones(len(indTo)), (indTo, indFrom)), shape=shape)
|
||||
self._shape = shape
|
||||
|
||||
super(Projection, self).__init__(mesh, **kwargs)
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
return self._shape
|
||||
|
||||
@property
|
||||
def nP(self):
|
||||
"""Number of parameters in the model."""
|
||||
return self.shape[1]
|
||||
|
||||
def _transform(self, m):
|
||||
return self.P*m
|
||||
|
||||
def deriv(self, m):
|
||||
return self.P
|
||||
|
||||
|
||||
class ComplexMap(IdentityMap):
|
||||
"""ComplexMap
|
||||
@@ -618,13 +697,13 @@ class CircleMap(IdentityMap):
|
||||
|
||||
Parameterize the model space using a circle in a wholespace.
|
||||
|
||||
..math::
|
||||
.. math::
|
||||
|
||||
\sigma(m) = \sigma_1 + (\sigma_2 - \sigma_1)\left(\\arctan\left(100*\sqrt{(\\vec{x}-x_0)^2 + (\\vec{y}-y_0)}-r\\right) \pi^{-1} + 0.5\\right)
|
||||
|
||||
Define the model as:
|
||||
|
||||
..math::
|
||||
.. math::
|
||||
|
||||
m = [\sigma_1, \sigma_2, x_0, y_0, r]
|
||||
|
||||
@@ -977,7 +1056,697 @@ class SplineMap(IdentityMap):
|
||||
return sp.csr_matrix(np.c_[g1,g2,g3])
|
||||
|
||||
|
||||
class ParametrizedLayer(IdentityMap):
|
||||
"""
|
||||
Parametrized Layer Space
|
||||
|
||||
m = [val_background, val_layer, layer_center, layer_thickness]
|
||||
|
||||
|
||||
.. plot::
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh, Maps, np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
fig, ax = plt.subplots(1,1,figsize=(2,3))
|
||||
|
||||
mesh = Mesh.TensorMesh([50,50],x0='CC')
|
||||
mapping = Maps.ParametrizedLayer(mesh)
|
||||
m = np.hstack(np.r_[1., 2., -0.1, 0.2])
|
||||
rho = mapping._transform(m)
|
||||
mesh.plotImage(rho, ax=ax)
|
||||
|
||||
**Required**
|
||||
|
||||
:param Mesh mesh: SimPEG Mesh, 2D or 3D
|
||||
|
||||
**Optional**
|
||||
|
||||
:param float slopeFact: arctan slope factor - divided by the minimum h spacing to give the slope of the arctan functions
|
||||
:param float slope: slope of the arctan function
|
||||
:param numpy.ndarray indActive: bool vector with
|
||||
|
||||
"""
|
||||
|
||||
slopeFact = 1e2 # will be scaled by the mesh.
|
||||
slope = None
|
||||
indActive = None
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
|
||||
super(ParametrizedLayer, self).__init__(mesh, **kwargs)
|
||||
|
||||
|
||||
if self.slope is None:
|
||||
self.slope = self.slopeFact / np.hstack(self.mesh.h).min()
|
||||
|
||||
self.x = [self.mesh.gridCC[:,0] if self.indActive is None else self.mesh.gridCC[self.indActive,0]][0]
|
||||
|
||||
if self.mesh.dim > 1:
|
||||
self.y = [self.mesh.gridCC[:,1] if self.indActive is None else self.mesh.gridCC[self.indActive,1]][0]
|
||||
|
||||
if self.mesh.dim > 2:
|
||||
self.z = [self.mesh.gridCC[:,2] if self.indActive is None else self.mesh.gridCC[self.indActive,2]][0]
|
||||
|
||||
@property
|
||||
def nP(self):
|
||||
return 4
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
if self.indActive is not None:
|
||||
return (sum(self.indActive), self.nP)
|
||||
return (self.mesh.nC, self.nP)
|
||||
|
||||
def mDict(self, m):
|
||||
return {
|
||||
'val_background': m[0],
|
||||
'val_layer': m[1],
|
||||
'layer_center': m[2],
|
||||
'layer_thickness': m[3],
|
||||
}
|
||||
|
||||
def _atanfct(self, xyz, xyzi, slope):
|
||||
return np.arctan(slope * (xyz - xyzi))/np.pi + 0.5
|
||||
|
||||
def _atanfctDeriv(self, xyz, xyzi, slope):
|
||||
# d/dx(atan(x)) = 1/(1+x**2)
|
||||
x = slope * (xyz - xyzi)
|
||||
dx = - slope
|
||||
return (1./(1 + x**2))/np.pi * dx
|
||||
|
||||
def _atanLayer(self, mDict):
|
||||
if self.mesh.dim == 2:
|
||||
z = self.y
|
||||
elif self.mesh.dim == 3:
|
||||
z = self.z
|
||||
|
||||
layer_bottom = mDict['layer_center'] - mDict['layer_thickness'] / 2.
|
||||
layer_top = mDict['layer_center'] + mDict['layer_thickness'] / 2.
|
||||
return self._atanfct(z, layer_bottom, self.slope)*self._atanfct(z, layer_top, -self.slope)
|
||||
|
||||
def _atanLayerDeriv_layer_center(self, mDict):
|
||||
if self.mesh.dim == 2:
|
||||
z = self.y
|
||||
elif self.mesh.dim == 3:
|
||||
z = self.z
|
||||
|
||||
layer_bottom = mDict['layer_center'] - mDict['layer_thickness'] / 2.
|
||||
layer_top = mDict['layer_center'] + mDict['layer_thickness'] / 2.
|
||||
|
||||
return (self._atanfctDeriv(z, layer_bottom, self.slope)*self._atanfct(z, layer_top, -self.slope)
|
||||
+ self._atanfct(z, layer_bottom, self.slope)*self._atanfctDeriv(z, layer_top, -self.slope))
|
||||
|
||||
def _atanLayerDeriv_layer_thickness(self, mDict):
|
||||
if self.mesh.dim == 2:
|
||||
z = self.y
|
||||
elif self.mesh.dim == 3:
|
||||
z = self.z
|
||||
|
||||
layer_bottom = mDict['layer_center'] - mDict['layer_thickness'] / 2.
|
||||
layer_top = mDict['layer_center'] + mDict['layer_thickness'] / 2.
|
||||
|
||||
return (-0.5*self._atanfctDeriv(z, layer_bottom, self.slope)*self._atanfct(z, layer_top, -self.slope)
|
||||
+ 0.5*self._atanfct(z, layer_bottom, self.slope)*self._atanfctDeriv(z, layer_top, -self.slope))
|
||||
|
||||
def layer_cont(self, mDict):
|
||||
return mDict['val_background'] + (mDict['val_layer'] - mDict['val_background'])*self._atanLayer(mDict)
|
||||
|
||||
def _transform(self, m):
|
||||
mDict = self.mDict(m)
|
||||
return self.layer_cont(mDict)
|
||||
|
||||
def _deriv_val_background(self, mDict):
|
||||
return np.ones_like(self.x) - self._atanLayer(mDict)
|
||||
|
||||
def _deriv_val_layer(self, mDict):
|
||||
return self._atanLayer(mDict)
|
||||
|
||||
def _deriv_layer_center(self, mDict):
|
||||
return (mDict['val_layer']-mDict['val_background'])*self._atanLayerDeriv_layer_center(mDict)
|
||||
|
||||
def _deriv_layer_thickness(self, mDict):
|
||||
return (mDict['val_layer']-mDict['val_background'])*self._atanLayerDeriv_layer_thickness(mDict)
|
||||
|
||||
def deriv(self, m):
|
||||
|
||||
mDict = self.mDict(m)
|
||||
|
||||
return sp.csr_matrix(np.vstack([
|
||||
self._deriv_val_background(mDict),
|
||||
self._deriv_val_layer(mDict),
|
||||
self._deriv_layer_center(mDict),
|
||||
self._deriv_layer_thickness(mDict),
|
||||
]).T)
|
||||
|
||||
|
||||
class ParametrizedCasingAndLayer(ParametrizedLayer):
|
||||
"""
|
||||
Parametrized layered space with casing.
|
||||
|
||||
m = [val_background, val_layer, val_casing, val_insideCasing, layer_center, layer_thickness, casing_radius, casing_thickness, casing_bottom, casing_top]
|
||||
"""
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
|
||||
assert mesh._meshType == 'CYL', 'Parametrized Casing in a layer map only works for a cyl mesh.'
|
||||
|
||||
super(ParametrizedCasingAndLayer, self).__init__(mesh, **kwargs)
|
||||
|
||||
|
||||
@property
|
||||
def nP(self):
|
||||
return 10
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
if self.indActive is not None:
|
||||
return (sum(self.indActive), self.nP)
|
||||
return (self.mesh.nC, self.nP)
|
||||
|
||||
def mDict(self, m):
|
||||
#m = [val_background, val_layer, val_casing, val_insideCasing, layer_center, layer_thickness, casing_radius, casing_thickness, casing_bottom, casing_top]
|
||||
return {
|
||||
'val_background': m[0],
|
||||
'val_layer': m[1],
|
||||
'val_casing': m[2],
|
||||
'val_insideCasing': m[3],
|
||||
'layer_center': m[4],
|
||||
'layer_thickness': m[5],
|
||||
'casing_radius': m[6],
|
||||
'casing_thickness': m[7],
|
||||
'casing_bottom': m[8],
|
||||
'casing_top': m[9]
|
||||
}
|
||||
|
||||
def _atanCasingLength(self, mDict):
|
||||
return (self._atanfct(self.z, mDict['casing_top'], -self.slope)
|
||||
* self._atanfct(self.z, mDict['casing_bottom'], self.slope))
|
||||
|
||||
def _atanCasingLengthDeriv_casing_top(self, mDict):
|
||||
return (self._atanfctDeriv(self.z, mDict['casing_top'], -self.slope)
|
||||
* self._atanfct(self.z, mDict['casing_bottom'], self.slope))
|
||||
|
||||
def _atanCasingLengthDeriv_casing_bottom(self, mDict):
|
||||
return (self._atanfct(self.z, mDict['casing_top'], -self.slope)
|
||||
* self._atanfctDeriv(self.z, mDict['casing_bottom'], self.slope))
|
||||
|
||||
def _atanInsideCasing(self, mDict):
|
||||
casing_a = mDict['casing_radius'] - 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLength(mDict)
|
||||
* self._atanfct(self.x, casing_a, -self.slope))
|
||||
|
||||
def _atanInsideCasingDeriv_casing_radius(self, mDict):
|
||||
casing_a = mDict['casing_radius'] - 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLength(mDict)
|
||||
* self._atanfctDeriv(self.x, casing_a, -self.slope))
|
||||
|
||||
def _atanInsideCasingDeriv_casing_thickness(self, mDict):
|
||||
casing_a = mDict['casing_radius'] - 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLength(mDict)
|
||||
* - 0.5*self._atanfctDeriv(self.x, casing_a, -self.slope))
|
||||
|
||||
def _atanInsideCasingDeriv_casing_top(self, mDict):
|
||||
casing_a = mDict['casing_radius'] - 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLengthDeriv_casing_top(mDict)
|
||||
* self._atanfct(self.x, casing_a, -self.slope))
|
||||
|
||||
def _atanInsideCasingDeriv_casing_bottom(self, mDict):
|
||||
casing_a = mDict['casing_radius'] - 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLengthDeriv_casing_bottom(mDict)
|
||||
* self._atanfct(self.x, casing_a, -self.slope))
|
||||
|
||||
def _atanCasing(self, mDict):
|
||||
casing_a, casing_b = mDict['casing_radius'] - 0.5*mDict['casing_thickness'], mDict['casing_radius'] + 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLength(mDict)
|
||||
* self._atanfct(self.x, casing_a, self.slope)
|
||||
* self._atanfct(self.x, casing_b, -self.slope))
|
||||
|
||||
def _atanCasingDeriv_casing_radius(self, mDict):
|
||||
casing_a, casing_b = mDict['casing_radius'] - 0.5*mDict['casing_thickness'], mDict['casing_radius'] + 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLength(mDict) * (
|
||||
self._atanfctDeriv(self.x, casing_a, self.slope)
|
||||
* self._atanfct(self.x, casing_b, -self.slope)
|
||||
+
|
||||
self._atanfct(self.x, casing_a, self.slope)
|
||||
* self._atanfctDeriv(self.x, casing_b, -self.slope)
|
||||
))
|
||||
|
||||
def _atanCasingDeriv_casing_thickness(self, mDict):
|
||||
casing_a, casing_b = mDict['casing_radius'] - 0.5*mDict['casing_thickness'], mDict['casing_radius'] + 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLength(mDict) * (
|
||||
- 0.5*self._atanfctDeriv(self.x, casing_a, self.slope)
|
||||
* 0.5*self._atanfct(self.x, casing_b, -self.slope)
|
||||
+
|
||||
- 0.5*self._atanfct(self.x, casing_a, self.slope)
|
||||
* 0.5*self._atanfctDeriv(self.x, casing_b, -self.slope)
|
||||
))
|
||||
|
||||
def _atanCasingDeriv_casing_bottom(self, mDict):
|
||||
casing_a, casing_b = mDict['casing_radius'] - 0.5*mDict['casing_thickness'], mDict['casing_radius'] + 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLengthDeriv_casing_bottom(mDict)
|
||||
* self._atanfct(self.x, casing_a, self.slope)
|
||||
* self._atanfct(self.x, casing_b, -self.slope))
|
||||
|
||||
def _atanCasingDeriv_casing_top(self, mDict):
|
||||
casing_a, casing_b = mDict['casing_radius'] - 0.5*mDict['casing_thickness'], mDict['casing_radius'] + 0.5*mDict['casing_thickness']
|
||||
return (self._atanCasingLengthDeriv_casing_top(mDict)
|
||||
* self._atanfct(self.x, casing_a, self.slope)
|
||||
* self._atanfct(self.x, casing_b, -self.slope))
|
||||
|
||||
def layer_cont(self, mDict):
|
||||
return mDict['val_background'] + (mDict['val_layer']-mDict['val_background']) * self._atanLayer(mDict) # contribution from the layered background
|
||||
|
||||
|
||||
def _transform(self, m):
|
||||
|
||||
mDict = self.mDict(m)
|
||||
|
||||
# assemble the model
|
||||
layer = self.layer_cont(mDict)
|
||||
casing = (mDict['val_casing'] - layer) * self._atanCasing(mDict)
|
||||
insideCasing = (mDict['val_insideCasing'] - layer) * self._atanInsideCasing(mDict)
|
||||
|
||||
return layer + casing + insideCasing
|
||||
|
||||
|
||||
def _deriv_val_background(self, mDict):
|
||||
d_layer_cont_dval_background = 1. - self._atanLayer(mDict) # contribution from the layered background
|
||||
d_casing_cont_dval_background = -1. * d_layer_cont_dval_background * self._atanCasing(mDict)
|
||||
d_insideCasing_cont_dval_background = -1. * d_layer_cont_dval_background * self._atanInsideCasing(mDict)
|
||||
return d_layer_cont_dval_background + d_casing_cont_dval_background + d_insideCasing_cont_dval_background
|
||||
|
||||
def _deriv_val_layer(self, mDict):
|
||||
d_layer_cont_dval_layer = self._atanLayer(mDict)
|
||||
d_casing_cont_dval_layer = -1. * d_layer_cont_dval_layer * self._atanCasing(mDict)
|
||||
d_insideCasing_cont_dval_layer = -1. * d_layer_cont_dval_layer * self._atanInsideCasing(mDict)
|
||||
return d_layer_cont_dval_layer + d_casing_cont_dval_layer + d_insideCasing_cont_dval_layer
|
||||
|
||||
def _deriv_val_casing(self, mDict):
|
||||
d_layer_cont_dval_casing = 0.
|
||||
d_casing_cont_dval_casing = self._atanCasing(mDict)
|
||||
d_insideCasing_cont_dval_casing = 0.
|
||||
return d_layer_cont_dval_casing + d_casing_cont_dval_casing + d_insideCasing_cont_dval_casing
|
||||
|
||||
def _deriv_val_insideCasing(self, mDict):
|
||||
d_layer_cont_dval_insideCasing = 0.
|
||||
d_casing_cont_dval_insideCasing = 0.
|
||||
d_insideCasing_cont_dval_insideCasing = self._atanInsideCasing(mDict)
|
||||
return d_layer_cont_dval_insideCasing + d_casing_cont_dval_insideCasing + d_insideCasing_cont_dval_insideCasing
|
||||
|
||||
def _deriv_layer_center(self, mDict):
|
||||
d_layer_cont_dlayer_center = (mDict['val_layer'] - mDict['val_background']) * self._atanLayerDeriv_layer_center(mDict)
|
||||
d_casing_cont_dlayer_center = - d_layer_cont_dlayer_center * self._atanCasing(mDict)
|
||||
d_insideCasing_cont_dlayer_center = - d_layer_cont_dlayer_center * self._atanInsideCasing(mDict)
|
||||
return d_layer_cont_dlayer_center + d_casing_cont_dlayer_center + d_insideCasing_cont_dlayer_center
|
||||
|
||||
def _deriv_layer_thickness(self, mDict):
|
||||
d_layer_cont_dlayer_thickness = (mDict['val_layer']-mDict['val_background']) * self._atanLayerDeriv_layer_thickness(mDict)
|
||||
d_casing_cont_dlayer_thickness = - d_layer_cont_dlayer_thickness * self._atanCasing(mDict)
|
||||
d_insideCasing_cont_dlayer_thickness = - d_layer_cont_dlayer_thickness * self._atanInsideCasing(mDict)
|
||||
return d_layer_cont_dlayer_thickness + d_casing_cont_dlayer_thickness + d_insideCasing_cont_dlayer_thickness
|
||||
|
||||
def _deriv_casing_radius(self, mDict):
|
||||
layer = self.layer_cont(mDict)
|
||||
d_layer_cont_dcasing_radius = 0.
|
||||
d_casing_cont_dcasing_radius = (mDict['val_casing'] - layer) * self._atanCasingDeriv_casing_radius(mDict)
|
||||
d_insideCasing_cont_dcasing_radius = (mDict['val_insideCasing'] - layer) * self._atanInsideCasingDeriv_casing_radius(mDict)
|
||||
return d_layer_cont_dcasing_radius + d_casing_cont_dcasing_radius + d_insideCasing_cont_dcasing_radius
|
||||
|
||||
def _deriv_casing_thickness(self, mDict):
|
||||
d_layer_cont_dcasing_thickness = 0.
|
||||
d_casing_cont_dcasing_thickness = (mDict['val_casing'] - self.layer_cont(mDict)) * self._atanCasingDeriv_casing_thickness(mDict)
|
||||
d_insideCasing_cont_dcasing_thickness = (mDict['val_insideCasing'] - self.layer_cont(mDict)) * self._atanInsideCasingDeriv_casing_thickness(mDict)
|
||||
return d_layer_cont_dcasing_thickness + d_casing_cont_dcasing_thickness + d_insideCasing_cont_dcasing_thickness
|
||||
|
||||
def _deriv_casing_bottom(self, mDict):
|
||||
d_layer_cont_dcasing_bottom = 0.
|
||||
d_casing_cont_dcasing_bottom = (mDict['val_casing'] - self.layer_cont(mDict)) * self._atanCasingDeriv_casing_bottom(mDict)
|
||||
d_insideCasing_cont_dcasing_bottom = (mDict['val_insideCasing'] - self.layer_cont(mDict)) * self._atanInsideCasingDeriv_casing_bottom(mDict)
|
||||
return d_layer_cont_dcasing_bottom + d_casing_cont_dcasing_bottom + d_insideCasing_cont_dcasing_bottom
|
||||
|
||||
def _deriv_casing_top(self, mDict):
|
||||
d_layer_cont_dcasing_top = 0.
|
||||
d_casing_cont_dcasing_top = (mDict['val_casing'] - self.layer_cont(mDict)) * self._atanCasingDeriv_casing_top(mDict)
|
||||
d_insideCasing_cont_dcasing_top = (mDict['val_insideCasing'] - self.layer_cont(mDict)) * self._atanInsideCasingDeriv_casing_top(mDict)
|
||||
return d_layer_cont_dcasing_top + d_casing_cont_dcasing_top + d_insideCasing_cont_dcasing_top
|
||||
|
||||
|
||||
def deriv(self, m):
|
||||
|
||||
mDict = self.mDict(m)
|
||||
|
||||
return sp.csr_matrix(np.vstack([
|
||||
self._deriv_val_background(mDict),
|
||||
self._deriv_val_layer(mDict),
|
||||
self._deriv_val_casing(mDict),
|
||||
self._deriv_val_insideCasing(mDict),
|
||||
self._deriv_layer_center(mDict),
|
||||
self._deriv_layer_thickness(mDict),
|
||||
self._deriv_casing_radius(mDict),
|
||||
self._deriv_casing_thickness(mDict),
|
||||
self._deriv_casing_bottom(mDict),
|
||||
self._deriv_casing_top(mDict),
|
||||
]).T)
|
||||
|
||||
|
||||
|
||||
class ParametrizedBlockInLayer(ParametrizedLayer):
|
||||
"""
|
||||
Parametrized Block in a Layered Space
|
||||
|
||||
For 2D:
|
||||
m = [val_background, val_layer, val_block, layer_center, layer_thickness, block_x0, block_dx]
|
||||
|
||||
For 3D:
|
||||
m = [val_background, val_layer, val_block, layer_center, layer_thickness, block_x0, block_y0, block_dx, block_dy]
|
||||
|
||||
.. plot::
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh, Maps, np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
fig, ax = plt.subplots(1,1,figsize=(2,3))
|
||||
|
||||
mesh = Mesh.TensorMesh([50,50],x0='CC')
|
||||
mapping = Maps.ParametrizedBlockInLayer(mesh)
|
||||
m = np.hstack(np.r_[1., 2., 3., -0.1, 0.2, 0.3, 0.2])
|
||||
rho = mapping._transform(m)
|
||||
mesh.plotImage(rho, ax=ax)
|
||||
|
||||
**Required**
|
||||
|
||||
:param Mesh mesh: SimPEG Mesh, 2D or 3D
|
||||
|
||||
**Optional**
|
||||
|
||||
:param float slopeFact: arctan slope factor - divided by the minimum h spacing to give the slope of the arctan functions
|
||||
:param float slope: slope of the arctan function
|
||||
:param numpy.ndarray indActive: bool vector with
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
|
||||
super(ParametrizedBlockInLayer, self).__init__(mesh, **kwargs)
|
||||
|
||||
@property
|
||||
def nP(self):
|
||||
if self.mesh.dim == 2:
|
||||
return 7
|
||||
elif self.mesh.dim == 3:
|
||||
return 9
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
if self.indActive is not None:
|
||||
return (sum(self.indActive), self.nP)
|
||||
return (self.mesh.nC, self.nP)
|
||||
|
||||
def _mDict2d(self, m):
|
||||
return{
|
||||
'val_background': m[0],
|
||||
'val_layer': m[1],
|
||||
'val_block': m[2],
|
||||
'layer_center': m[3],
|
||||
'layer_thickness': m[4],
|
||||
'x0_block': m[5],
|
||||
'dx_block': m[6]
|
||||
}
|
||||
|
||||
def _mDict3d(self, m):
|
||||
return{
|
||||
'val_background': m[0],
|
||||
'val_layer': m[1],
|
||||
'val_block': m[2],
|
||||
'layer_center': m[3],
|
||||
'layer_thickness': m[4],
|
||||
'x0_block': m[5],
|
||||
'y0_block': m[6],
|
||||
'dx_block': m[7],
|
||||
'dy_block': m[8]
|
||||
}
|
||||
|
||||
def mDict(self, m):
|
||||
if self.mesh.dim == 2:
|
||||
return self._mDict2d(m)
|
||||
elif self.mesh.dim == 3:
|
||||
return self._mDict3d(m)
|
||||
|
||||
def _atanBlock2d(self, mDict):
|
||||
return (self._atanLayer(mDict)
|
||||
* self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope))
|
||||
|
||||
def _atanBlock2dDeriv_layer_center(self, mDict):
|
||||
return (self._atanLayerDeriv_layer_center(mDict)
|
||||
* self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope))
|
||||
|
||||
def _atanBlock2dDeriv_layer_thickness(self, mDict):
|
||||
return (self._atanLayerDeriv_layer_thickness(mDict)
|
||||
* self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope))
|
||||
|
||||
|
||||
def _atanBlock2dDeriv_x0(self, mDict):
|
||||
return self._atanLayer(mDict) * (
|
||||
(self._atanfctDeriv(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope))
|
||||
+
|
||||
(self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfctDeriv(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope))
|
||||
)
|
||||
|
||||
def _atanBlock2dDeriv_dx(self, mDict):
|
||||
return self._atanLayer(mDict) * (
|
||||
(self._atanfctDeriv(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope) * -0.5
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope))
|
||||
+
|
||||
(self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfctDeriv(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope) * 0.5)
|
||||
)
|
||||
|
||||
def _atanBlock3d(self, mDict):
|
||||
return (self._atanLayer(mDict)
|
||||
* self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
|
||||
|
||||
def _atanBlock3dDeriv_layer_center(self, mDict):
|
||||
return (self._atanLayerDeriv_layer_center(mDict)
|
||||
* self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
|
||||
def _atanBlock3dDeriv_layer_thickness(self, mDict):
|
||||
return (self._atanLayerDeriv_layer_thickness(mDict)
|
||||
* self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
|
||||
|
||||
def _atanBlock3dDeriv_x0(self, mDict):
|
||||
return self._atanLayer(mDict) * (
|
||||
(self._atanfctDeriv(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
+
|
||||
(self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfctDeriv(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
)
|
||||
|
||||
def _atanBlock3dDeriv_y0(self, mDict):
|
||||
return self._atanLayer(mDict) * (
|
||||
(self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfctDeriv(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
+
|
||||
(self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfctDeriv(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
)
|
||||
|
||||
def _atanBlock3dDeriv_dx(self, mDict):
|
||||
return self._atanLayer(mDict) * (
|
||||
(self._atanfctDeriv(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope) * -0.5
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
+
|
||||
(self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfctDeriv(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope) * 0.5
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
)
|
||||
|
||||
def _atanBlock3dDeriv_dy(self, mDict):
|
||||
return self._atanLayer(mDict) * (
|
||||
(self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfctDeriv(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope) * -0.5
|
||||
* self._atanfct(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope))
|
||||
+
|
||||
(self._atanfct(self.x, mDict['x0_block'] - 0.5*mDict['dx_block'], self.slope)
|
||||
* self._atanfct(self.x, mDict['x0_block'] + 0.5*mDict['dx_block'], -self.slope)
|
||||
* self._atanfct(self.y, mDict['y0_block'] - 0.5*mDict['dy_block'], self.slope)
|
||||
* self._atanfctDeriv(self.y, mDict['y0_block'] + 0.5*mDict['dy_block'], -self.slope) * 0.5)
|
||||
)
|
||||
|
||||
|
||||
def _transform2d(self, m):
|
||||
mDict = self.mDict(m)
|
||||
# assemble the model
|
||||
layer_cont = mDict['val_background'] + (mDict['val_layer']-mDict['val_background'])*self._atanLayer(mDict) # contribution from the layered background
|
||||
block_cont = (mDict['val_block']-layer_cont)*self._atanBlock2d(mDict) # perturbation due to the block
|
||||
|
||||
return layer_cont + block_cont
|
||||
|
||||
def _deriv2d_val_background(self, mDict):
|
||||
d_layer_dval_background = np.ones_like(self.x) - self._atanLayer(mDict)
|
||||
d_block_dval_background = (-d_layer_dval_background)*self._atanBlock2d(mDict)
|
||||
return d_layer_dval_background + d_block_dval_background
|
||||
|
||||
def _deriv2d_val_layer(self, mDict):
|
||||
d_layer_dval_layer = self._atanLayer(mDict)
|
||||
d_block_dval_layer = (-d_layer_dval_layer)*self._atanBlock2d(mDict)
|
||||
return d_layer_dval_layer + d_block_dval_layer
|
||||
|
||||
def _deriv2d_val_block(self, mDict):
|
||||
d_layer_dval_block = 0.
|
||||
d_block_dval_block = (1.-d_layer_dval_block)*self._atanBlock2d(mDict)
|
||||
return d_layer_dval_block + d_block_dval_block
|
||||
|
||||
def _deriv2d_layer_center(self, mDict):
|
||||
d_layer_dlayer_center = (mDict['val_layer']-mDict['val_background'])*self._atanLayerDeriv_layer_center(mDict)
|
||||
d_block_dlayer_center = ((mDict['val_block']-self.layer_cont(mDict))*self._atanBlock2dDeriv_layer_center(mDict)
|
||||
- d_layer_dlayer_center*self._atanBlock2d(mDict))
|
||||
return d_layer_dlayer_center + d_block_dlayer_center
|
||||
|
||||
def _deriv2d_layer_thickness(self, mDict):
|
||||
d_layer_dlayer_thickness = (mDict['val_layer']-mDict['val_background'])*self._atanLayerDeriv_layer_thickness(mDict)
|
||||
d_block_dlayer_thickness = ((mDict['val_block']-self.layer_cont(mDict))*self._atanBlock2dDeriv_layer_thickness(mDict)
|
||||
- d_layer_dlayer_thickness*self._atanBlock2d(mDict))
|
||||
return d_layer_dlayer_thickness + d_block_dlayer_thickness
|
||||
|
||||
def _deriv2d_x0_block(self, mDict):
|
||||
d_layer_dx0 = 0.
|
||||
d_block_dx0 = (mDict['val_block']-self.layer_cont(mDict))*self._atanBlock2dDeriv_x0(mDict)
|
||||
return d_layer_dx0 + d_block_dx0
|
||||
|
||||
def _deriv2d_dx_block(self, mDict):
|
||||
d_layer_ddx = 0.
|
||||
d_block_ddx = (mDict['val_block']-self.layer_cont(mDict))*self._atanBlock2dDeriv_dx(mDict)
|
||||
return d_layer_ddx + d_block_ddx
|
||||
|
||||
def _deriv2d(self, m):
|
||||
mDict = self.mDict(m)
|
||||
|
||||
return np.vstack([
|
||||
self._deriv2d_val_background(mDict),
|
||||
self._deriv2d_val_layer(mDict),
|
||||
self._deriv2d_val_block(mDict),
|
||||
self._deriv2d_layer_center(mDict),
|
||||
self._deriv2d_layer_thickness(mDict),
|
||||
self._deriv2d_x0_block(mDict),
|
||||
self._deriv2d_dx_block(mDict)
|
||||
]).T
|
||||
|
||||
def _transform3d(self, m):
|
||||
# parse model
|
||||
mDict = self.mDict(m)
|
||||
|
||||
# assemble the model
|
||||
layer_cont = mDict['val_background'] + (mDict['val_layer']-mDict['val_background'])*self._atanLayer(mDict) # contribution from the layered background
|
||||
block_cont = (mDict['val_block']-layer_cont)*self._atanBlock3d(mDict) # perturbation due to the block
|
||||
|
||||
return layer_cont + block_cont
|
||||
|
||||
def _deriv3d_val_background(self, mDict):
|
||||
d_layer_dval_background = np.ones_like(self.x) - self._atanLayer(mDict)
|
||||
d_block_dval_background = (-d_layer_dval_background)*self._atanBlock3d(mDict)
|
||||
return d_layer_dval_background + d_block_dval_background
|
||||
|
||||
def _deriv3d_val_layer(self, mDict):
|
||||
d_layer_dval_layer = self._atanLayer(mDict)
|
||||
d_block_dval_layer = (-d_layer_dval_layer)*self._atanBlock3d(mDict)
|
||||
return d_layer_dval_layer + d_block_dval_layer
|
||||
|
||||
def _deriv3d_val_block(self, mDict):
|
||||
d_layer_dval_block = 0.
|
||||
d_block_dval_block = (1.-d_layer_dval_block)*self._atanBlock3d(mDict)
|
||||
return d_layer_dval_block + d_block_dval_block
|
||||
|
||||
def _deriv3d_layer_center(self, mDict):
|
||||
d_layer_dlayer_center = (mDict['val_layer']-mDict['val_background'])*self._atanLayerDeriv_layer_center(mDict)
|
||||
d_block_dlayer_center = ((mDict['val_block']-self.layer_cont(mDict))*self._atanBlock3dDeriv_layer_center(mDict)
|
||||
- d_layer_dlayer_center*self._atanBlock3d(mDict))
|
||||
return d_layer_dlayer_center + d_block_dlayer_center
|
||||
|
||||
def _deriv3d_layer_thickness(self, mDict):
|
||||
d_layer_dlayer_thickness = (mDict['val_layer']-mDict['val_background'])*self._atanLayerDeriv_layer_thickness(mDict)
|
||||
d_block_dlayer_thickness = ((mDict['val_block']-self.layer_cont(mDict))*self._atanBlock3dDeriv_layer_thickness(mDict)
|
||||
- d_layer_dlayer_thickness*self._atanBlock3d(mDict))
|
||||
return d_layer_dlayer_thickness + d_block_dlayer_thickness
|
||||
|
||||
def _deriv3d_x0_block(self, mDict):
|
||||
d_layer_dx0 = 0.
|
||||
d_block_dx0 = (mDict['val_block']-self.layer_cont(mDict))*self._atanBlock3dDeriv_x0(mDict)
|
||||
return d_layer_dx0 + d_block_dx0
|
||||
|
||||
def _deriv3d_y0_block(self, mDict):
|
||||
d_layer_dy0 = 0.
|
||||
d_block_dy0 = (mDict['val_block']-self.layer_cont(mDict))*self._atanBlock3dDeriv_y0(mDict)
|
||||
return d_layer_dy0 + d_block_dy0
|
||||
|
||||
def _deriv3d_dx_block(self, mDict):
|
||||
d_layer_ddx = 0.
|
||||
d_block_ddx = (mDict['val_block']-self.layer_cont(mDict))*self._atanBlock3dDeriv_dx(mDict)
|
||||
return d_layer_ddx + d_block_ddx
|
||||
|
||||
def _deriv3d_dy_block(self, mDict):
|
||||
d_layer_ddy = 0.
|
||||
d_block_ddy = (mDict['val_block']-self.layer_cont(mDict))*self._atanBlock3dDeriv_dy(mDict)
|
||||
return d_layer_ddy + d_block_ddy
|
||||
|
||||
def _deriv3d(self, m):
|
||||
|
||||
mDict = self.mDict(m)
|
||||
|
||||
return np.vstack([
|
||||
self._deriv3d_val_background(mDict),
|
||||
self._deriv3d_val_layer(mDict),
|
||||
self._deriv3d_val_block(mDict),
|
||||
self._deriv3d_layer_center(mDict),
|
||||
self._deriv3d_layer_thickness(mDict),
|
||||
self._deriv3d_x0_block(mDict),
|
||||
self._deriv3d_y0_block(mDict),
|
||||
self._deriv3d_dx_block(mDict),
|
||||
self._deriv3d_dy_block(mDict),
|
||||
]).T
|
||||
|
||||
def _transform(self, m):
|
||||
|
||||
if self.mesh.dim == 2:
|
||||
return self._transform2d(m)
|
||||
elif self.mesh.dim == 3:
|
||||
return self._transform3d(m)
|
||||
|
||||
def deriv(self, m):
|
||||
|
||||
if self.mesh.dim == 2:
|
||||
return sp.csr_matrix(self._deriv2d(m))
|
||||
elif self.mesh.dim == 3:
|
||||
return sp.csr_matrix(self._deriv3d(m))
|
||||
|
||||
|
||||
+24
-26
@@ -7,8 +7,8 @@ class BaseMesh(object):
|
||||
BaseMesh does all the counting you don't want to do.
|
||||
BaseMesh should be inherited by meshes with a regular structure.
|
||||
|
||||
:param numpy.array n: (or list) number of cells in each direction (dim, )
|
||||
:param numpy.array x0: (or list) Origin of the mesh (dim, )
|
||||
:param numpy.array,list n: number of cells in each direction (dim, )
|
||||
:param numpy.array,list x0: Origin of the mesh (dim, )
|
||||
|
||||
"""
|
||||
|
||||
@@ -34,8 +34,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Origin of the mesh
|
||||
|
||||
:rtype: numpy.array
|
||||
:return: x0, (dim, )
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: x0
|
||||
"""
|
||||
return self._x0
|
||||
|
||||
@@ -116,8 +116,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Total number of edges in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:return: [nEx, nEy, nEz], (dim, )
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: [nEx, nEy, nEz]
|
||||
|
||||
.. plot::
|
||||
:include-source:
|
||||
@@ -173,8 +173,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Total number of faces in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:return: [nFx, nFy, nFz], (dim, )
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: [nFx, nFy, nFz]
|
||||
|
||||
.. plot::
|
||||
:include-source:
|
||||
@@ -200,8 +200,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Face Normals
|
||||
|
||||
:rtype: numpy.array
|
||||
:return: normals, (sum(nF), dim)
|
||||
:rtype: numpy.array (sum(nF), dim)
|
||||
:return: normals
|
||||
"""
|
||||
if self.dim == 2:
|
||||
nX = np.c_[np.ones(self.nFx), np.zeros(self.nFx)]
|
||||
@@ -218,8 +218,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Edge Tangents
|
||||
|
||||
:rtype: numpy.array
|
||||
:return: normals, (sum(nE), dim)
|
||||
:rtype: numpy.array (sum(nE), dim)
|
||||
:return: normals
|
||||
"""
|
||||
if self.dim == 2:
|
||||
tX = np.c_[np.ones(self.nEx), np.zeros(self.nEx)]
|
||||
@@ -236,9 +236,8 @@ class BaseMesh(object):
|
||||
Given a vector, fV, in cartesian coordinates, this will project it onto the mesh using the normals
|
||||
|
||||
:param numpy.array fV: face vector with shape (nF, dim)
|
||||
:rtype: numpy.array
|
||||
:return: projected face vector, (nF, )
|
||||
|
||||
:rtype: numpy.array with shape (nF, )
|
||||
:return: projected face vector
|
||||
"""
|
||||
assert isinstance(fV, np.ndarray), 'fV must be an ndarray'
|
||||
assert len(fV.shape) == 2 and fV.shape[0] == self.nF and fV.shape[1] == self.dim, 'fV must be an ndarray of shape (nF x dim)'
|
||||
@@ -249,9 +248,8 @@ class BaseMesh(object):
|
||||
Given a vector, eV, in cartesian coordinates, this will project it onto the mesh using the tangents
|
||||
|
||||
:param numpy.array eV: edge vector with shape (nE, dim)
|
||||
:rtype: numpy.array
|
||||
:return: projected edge vector, (nE, )
|
||||
|
||||
:rtype: numpy.array with shape (nE, )
|
||||
:return: projected edge vector
|
||||
"""
|
||||
assert isinstance(eV, np.ndarray), 'eV must be an ndarray'
|
||||
assert len(eV.shape) == 2 and eV.shape[0] == self.nE and eV.shape[1] == self.dim, 'eV must be an ndarray of shape (nE x dim)'
|
||||
@@ -297,7 +295,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Total number of cells in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: [nCx, nCy, nCz]
|
||||
"""
|
||||
return np.array([x for x in [self.nCx, self.nCy, self.nCz] if not x is None])
|
||||
@@ -337,7 +335,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Total number of nodes in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: [nNx, nNy, nNz]
|
||||
"""
|
||||
return np.array([x for x in [self.nNx, self.nNy, self.nNz] if not x is None])
|
||||
@@ -347,7 +345,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of x-edges in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnEx
|
||||
"""
|
||||
return np.array([x for x in [self.nCx, self.nNy, self.nNz] if not x is None])
|
||||
@@ -357,7 +355,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of y-edges in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnEy or None if dim < 2
|
||||
"""
|
||||
return None if self.dim < 2 else np.array([x for x in [self.nNx, self.nCy, self.nNz] if not x is None])
|
||||
@@ -367,7 +365,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of z-edges in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnEz or None if dim < 3
|
||||
"""
|
||||
return None if self.dim < 3 else np.array([x for x in [self.nNx, self.nNy, self.nCz] if not x is None])
|
||||
@@ -377,7 +375,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of x-faces in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnFx
|
||||
"""
|
||||
return np.array([x for x in [self.nNx, self.nCy, self.nCz] if not x is None])
|
||||
@@ -387,7 +385,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of y-faces in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnFy or None if dim < 2
|
||||
"""
|
||||
return None if self.dim < 2 else np.array([x for x in [self.nCx, self.nNy, self.nCz] if not x is None])
|
||||
@@ -397,7 +395,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of z-faces in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnFz or None if dim < 3
|
||||
"""
|
||||
return None if self.dim < 3 else np.array([x for x in [self.nCx, self.nCy, self.nNz] if not x is None])
|
||||
|
||||
@@ -2,7 +2,6 @@ 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
|
||||
@@ -11,7 +10,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, CurvView):
|
||||
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
|
||||
"""
|
||||
CurvilinearMesh is a mesh class that deals with curvilinear meshes.
|
||||
|
||||
@@ -331,6 +330,102 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts, CurvVie
|
||||
|
||||
|
||||
|
||||
#############################################
|
||||
# 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)])
|
||||
|
||||
@@ -68,8 +68,8 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
"""
|
||||
Number of x-faces in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:return: vnFx, (dim, )
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnFx
|
||||
"""
|
||||
return self.vnC
|
||||
|
||||
@@ -78,8 +78,8 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
"""
|
||||
Number of y-edges in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:return: vnEy or None if dim < 2, (dim, )
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnEy or None if dim < 2
|
||||
"""
|
||||
nNx = self.nNx if self.isSymmetric else self.nNx - 1
|
||||
return np.r_[nNx, self.nCy, self.nNz]
|
||||
@@ -89,8 +89,8 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
"""
|
||||
Number of z-edges in each direction
|
||||
|
||||
:rtype: numpy.array
|
||||
:return: vnEz or None if nCy > 1, (dim, )
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnEz or None if nCy > 1
|
||||
"""
|
||||
if self.isSymmetric:
|
||||
return np.r_[self.nNx, self.nNy, self.nCz]
|
||||
|
||||
@@ -16,7 +16,7 @@ class InnerProducts(object):
|
||||
:param bool invProp: inverts the material property
|
||||
:param bool invMat: inverts the matrix
|
||||
:param bool doFast: do a faster implementation if available.
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: M, the inner product matrix (nF, nF)
|
||||
"""
|
||||
return self._getInnerProduct('F', prop=prop, invProp=invProp, invMat=invMat, doFast=doFast)
|
||||
@@ -27,7 +27,7 @@ class InnerProducts(object):
|
||||
:param bool invProp: inverts the material property
|
||||
:param bool invMat: inverts the matrix
|
||||
:param bool doFast: do a faster implementation if available.
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: M, the inner product matrix (nE, nE)
|
||||
"""
|
||||
return self._getInnerProduct('E', prop=prop, invProp=invProp, invMat=invMat, doFast=doFast)
|
||||
@@ -39,7 +39,7 @@ class InnerProducts(object):
|
||||
:param bool invProp: inverts the material property
|
||||
:param bool invMat: inverts the matrix
|
||||
:param bool doFast: do a faster implementation if available.
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: M, the inner product matrix (nE, nE)
|
||||
"""
|
||||
assert projType in ['F', 'E'], "projType must be 'F' for faces or 'E' for edges"
|
||||
@@ -115,12 +115,13 @@ class InnerProducts(object):
|
||||
:param bool doFast: do a faster implementation if available.
|
||||
:param bool invProp: inverts the material property
|
||||
:param bool invMat: inverts the matrix
|
||||
:rtype: function
|
||||
:return: dMdmu(u), the derivative of the inner product matrix (u)
|
||||
|
||||
Given u, dMdmu returns (nF, nC*nA)
|
||||
|
||||
:param numpy.ndarray u: vector that multiplies dMdmu
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:param np.ndarray u: vector that multiplies dMdmu
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: dMdmu, the derivative of the inner product matrix for a certain u
|
||||
"""
|
||||
return self._getInnerProductDeriv(prop, 'F', doFast=doFast, invProp=invProp, invMat=invMat)
|
||||
@@ -132,7 +133,7 @@ class InnerProducts(object):
|
||||
:param bool doFast: do a faster implementation if available.
|
||||
:param bool invProp: inverts the material property
|
||||
:param bool invMat: inverts the matrix
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: dMdm, the derivative of the inner product matrix (nE, nC*nA)
|
||||
"""
|
||||
return self._getInnerProductDeriv(prop, 'E', doFast=doFast, invProp=invProp, invMat=invMat)
|
||||
@@ -144,7 +145,7 @@ class InnerProducts(object):
|
||||
:param bool doFast: do a faster implementation if available.
|
||||
:param bool invProp: inverts the material property
|
||||
:param bool invMat: inverts the matrix
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: dMdm, the derivative of the inner product matrix (nE, nC*nA)
|
||||
"""
|
||||
fast = None
|
||||
@@ -168,7 +169,7 @@ class InnerProducts(object):
|
||||
:param numpy.array v: vector to multiply (required in the general implementation)
|
||||
:param list P: list of projection matrices
|
||||
:param str projType: 'F' for faces 'E' for edges
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: dMdm, the derivative of the inner product matrix (n, nC*nA)
|
||||
"""
|
||||
assert projType in ['F', 'E'], "projType must be 'F' for faces or 'E' for edges"
|
||||
|
||||
+35
-22
@@ -6,11 +6,13 @@ class TensorMeshIO(object):
|
||||
@classmethod
|
||||
def readUBC(TensorMesh, fileName):
|
||||
"""
|
||||
Read UBC GIF 3D tensor mesh and generate 3D TensorMesh in SimPEG.
|
||||
Read UBC GIF 3DTensor mesh and generate 3D Tensor mesh in simpegTD
|
||||
|
||||
:param string fileName: path to the UBC GIF mesh file
|
||||
:rtype: TensorMesh
|
||||
:return: The tensor mesh for the fileName.
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF mesh file
|
||||
|
||||
Output:
|
||||
:param SimPEG TensorMesh object
|
||||
"""
|
||||
|
||||
# Interal function to read cell size lines for the UBC mesh files.
|
||||
@@ -46,9 +48,11 @@ class TensorMeshIO(object):
|
||||
Read VTK Rectilinear (vtr xml file) and return SimPEG Tensor mesh and model
|
||||
|
||||
Input:
|
||||
:param string fileName: path to the vtr model file to read
|
||||
:rtype: tuple
|
||||
:return: (TensorMesh, modelDictionary)
|
||||
:param vtrFileName, path to the vtr model file to write to
|
||||
|
||||
Output:
|
||||
:return SimPEG TensorMesh object
|
||||
:return SimPEG model dictionary
|
||||
|
||||
"""
|
||||
# Import
|
||||
@@ -98,8 +102,9 @@ class TensorMeshIO(object):
|
||||
Makes and saves a VTK rectilinear file (vtr) for a simpeg Tensor mesh and model.
|
||||
|
||||
Input:
|
||||
:param string fileName: path to the output vtk file
|
||||
:param dict models: dictionary of numpy.array - Name('s) and array('s). Match number of cells
|
||||
: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
|
||||
@@ -157,9 +162,12 @@ class TensorMeshIO(object):
|
||||
"""
|
||||
Read UBC 3DTensor mesh model and generate 3D Tensor mesh model in simpeg
|
||||
|
||||
:param string fileName: path to the UBC GIF mesh file to read
|
||||
:rtype: numpy.ndarray
|
||||
:return: model with TensorMesh ordered
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF mesh file to read
|
||||
:param mesh, TensorMesh object, mesh that coresponds to the model
|
||||
|
||||
Output:
|
||||
:return numpy array, model with TensorMesh ordered
|
||||
"""
|
||||
f = open(fileName, 'r')
|
||||
model = np.array(map(float, f.readlines()))
|
||||
@@ -175,7 +183,8 @@ class TensorMeshIO(object):
|
||||
Writes a model associated with a SimPEG TensorMesh
|
||||
to a UBC-GIF format model file.
|
||||
|
||||
:param string fileName: File to write to
|
||||
:param str fileName: File to write to
|
||||
:param simpeg.Mesh.TensorMesh mesh: The mesh
|
||||
:param numpy.ndarray model: The model
|
||||
"""
|
||||
|
||||
@@ -192,8 +201,8 @@ class TensorMeshIO(object):
|
||||
"""
|
||||
Writes a SimPEG TensorMesh to a UBC-GIF format mesh file.
|
||||
|
||||
:param string fileName: File to write to
|
||||
:param dict models: A dictionary of the models
|
||||
:param str fileName: File to write to
|
||||
:param simpeg.Mesh.TensorMesh mesh: The mesh
|
||||
|
||||
"""
|
||||
assert mesh.dim == 3
|
||||
@@ -222,8 +231,9 @@ class TreeMeshIO(object):
|
||||
"""
|
||||
Write UBC ocTree mesh and model files from a simpeg ocTree mesh and model.
|
||||
|
||||
:param string fileName: File to write to
|
||||
:param dict models: The models in a dictionary, where the keys is the name of the of the model file
|
||||
:param str fileName: File to write to
|
||||
:param simpeg.Mesh.TreeMesh mesh: The mesh
|
||||
:param dictionary models: The models in a dictionary, where the keys is the name of the of the model file
|
||||
"""
|
||||
|
||||
# Calculate information to write in the file.
|
||||
@@ -276,9 +286,10 @@ class TreeMeshIO(object):
|
||||
|
||||
Input:
|
||||
:param str meshFile: path to the UBC GIF OcTree mesh file to read
|
||||
:rtype: SimPEG.Mesh.TreeMesh
|
||||
:return: The octree mesh
|
||||
|
||||
Output:
|
||||
:return SimPEG.Mesh.TreeMesh mesh: The octree mesh
|
||||
:return list of ndarray's: models as a list of numpy array's
|
||||
"""
|
||||
|
||||
## Read the file lines
|
||||
@@ -324,9 +335,11 @@ class TreeMeshIO(object):
|
||||
"""
|
||||
Read UBC OcTree model and get vector
|
||||
|
||||
:param string fileName: path to the UBC GIF model file to read
|
||||
:rtype: numpy.ndarray
|
||||
:return: OcTree model
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF model file to read
|
||||
|
||||
Output:
|
||||
:return numpy array, OcTree model
|
||||
"""
|
||||
|
||||
if type(fileName) is list:
|
||||
|
||||
@@ -198,8 +198,8 @@ class BaseTensorMesh(BaseMesh):
|
||||
Determines if a set of points are inside a mesh.
|
||||
|
||||
:param numpy.ndarray pts: Location of points to test
|
||||
:rtype numpy.ndarray:
|
||||
:return: inside, numpy array of booleans
|
||||
:rtype numpy.ndarray
|
||||
:return inside, numpy array of booleans
|
||||
"""
|
||||
pts = Utils.asArray_N_x_Dim(pts, self.dim)
|
||||
|
||||
@@ -221,7 +221,7 @@ class BaseTensorMesh(BaseMesh):
|
||||
|
||||
:param numpy.ndarray loc: Location of points to interpolate to
|
||||
:param str locType: What to interpolate (see below)
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.sparse.csr.csr_matrix
|
||||
:return: M, the interpolation matrix
|
||||
|
||||
locType can be::
|
||||
@@ -289,7 +289,7 @@ class BaseTensorMesh(BaseMesh):
|
||||
:param bool returnP: returns the projection matrices
|
||||
:param bool invProp: inverts the material property
|
||||
:param bool invMat: inverts the matrix
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.csr_matrix
|
||||
:return: M, the inner product matrix (nF, nF)
|
||||
"""
|
||||
assert projType in ['F', 'E'], "projType must be 'F' for faces or 'E' for edges"
|
||||
|
||||
@@ -1875,7 +1875,7 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO):
|
||||
|
||||
:param numpy.ndarray locs: Location of points to interpolate to
|
||||
:param str locType: What to interpolate (see below)
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.sparse.csr.csr_matrix
|
||||
:return: M, the interpolation matrix
|
||||
|
||||
locType can be::
|
||||
|
||||
+40
-78
@@ -552,8 +552,7 @@ class CurvView(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
|
||||
def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False):
|
||||
def plotGrid(self, length=0.05, showIt=False):
|
||||
"""Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions.
|
||||
|
||||
|
||||
@@ -561,63 +560,60 @@ class CurvView(object):
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh, Utils
|
||||
X, Y = Utils.exampleLrmGrid([3,3],'rotate')
|
||||
X, Y = Utils.exampleCurvGird([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()
|
||||
|
||||
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()
|
||||
|
||||
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]
|
||||
|
||||
X = np.r_[X1, X2]
|
||||
Y = np.r_[Y1, Y2]
|
||||
plt.plot(X, Y)
|
||||
|
||||
ax.plot(X, Y, 'b-')
|
||||
if centers:
|
||||
ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro')
|
||||
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')
|
||||
|
||||
# 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')
|
||||
plt.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
|
||||
|
||||
# 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()
|
||||
plt.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
|
||||
plt.plot(nX, nY, 'r-')
|
||||
|
||||
# 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()
|
||||
#plt.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
|
||||
plt.plot(nX, nY, 'g-')
|
||||
|
||||
# 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()
|
||||
plt.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
|
||||
plt.plot(tX, tY, '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()
|
||||
# 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-')
|
||||
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')
|
||||
|
||||
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()
|
||||
@@ -634,50 +630,16 @@ class CurvView(object):
|
||||
Y = np.r_[Y1, Y2, Y3]
|
||||
Z = np.r_[Z1, Z2, Z3]
|
||||
|
||||
ax.plot(X, Y, 'b', zs=Z)
|
||||
plt.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 *
|
||||
|
||||
@@ -131,7 +131,7 @@ class Minimize(object):
|
||||
|
||||
Minimizes the function (evalFunction) starting at the location x0.
|
||||
|
||||
:param callable evalFunction: function handle that evaluates: f, g, H = F(x)
|
||||
:param def evalFunction: function handle that evaluates: f, g, H = F(x)
|
||||
:param numpy.ndarray x0: starting location
|
||||
:rtype: numpy.ndarray
|
||||
:return: x, the last iterate of the optimization algorithm
|
||||
@@ -372,8 +372,8 @@ class Minimize(object):
|
||||
Else, a modifySearchDirectionBreak call is preformed.
|
||||
|
||||
:param numpy.ndarray p: searchDirection
|
||||
:rtype: tuple
|
||||
:return: (xt, passLS) numpy.ndarray, bool
|
||||
:rtype: numpy.ndarray,bool
|
||||
:return: (xt, passLS)
|
||||
"""
|
||||
# Projected Armijo linesearch
|
||||
self._LS_t = 1
|
||||
@@ -408,8 +408,8 @@ class Minimize(object):
|
||||
evalFunction returns a False indicating the break was not caught.
|
||||
|
||||
:param numpy.ndarray p: searchDirection
|
||||
:rtype: tuple
|
||||
:return: (xt, breakCaught) numpy.ndarray, bool
|
||||
:rtype: numpy.ndarray,bool
|
||||
:return: (xt, breakCaught)
|
||||
"""
|
||||
self.printDone(inLS=True)
|
||||
print 'The linesearch got broken. Boo.'
|
||||
@@ -1008,4 +1008,4 @@ class ProjectedGNCG(BFGS, Minimize, Remember):
|
||||
indx = ((self.xc<=self.lower) & (delx < 0)) | ((self.xc>=self.upper) & (delx > 0))
|
||||
delx[indx] = 0.
|
||||
|
||||
return delx
|
||||
return delx
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
from SimPEG import Maps, Survey, Utils, np, sp
|
||||
from scipy.constants import mu_0
|
||||
import re
|
||||
|
||||
|
||||
class LinearSurvey(Survey.BaseSurvey):
|
||||
"""Base Magnetics Survey"""
|
||||
|
||||
rxLoc = None #: receiver locations
|
||||
rxType = None #: receiver type
|
||||
|
||||
def __init__(self, srcField, **kwargs):
|
||||
self.srcField = srcField
|
||||
Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
|
||||
def eval(self, u):
|
||||
return u
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
return self.prob.G.shape[0]
|
||||
|
||||
@property
|
||||
def nRx(self):
|
||||
return self.srcField.rxList[0].locs.shape[0]
|
||||
# def setBackgroundField(self, SrcField):
|
||||
|
||||
# if getattr(self, 'B0', None) is None:
|
||||
# self._B0 = SrcField.param[0] * dipazm_2_xyz(SrcField.param[1],SrcField.param[2])
|
||||
|
||||
# return self._B0
|
||||
|
||||
|
||||
class SrcField(Survey.BaseSrc):
|
||||
""" Define the inducing field """
|
||||
|
||||
param = None #: Inducing field param (Amp, Incl, Decl)
|
||||
|
||||
def __init__(self, rxList, **kwargs):
|
||||
super(SrcField, self).__init__(rxList, **kwargs)
|
||||
|
||||
|
||||
class RxObs(Survey.BaseRx):
|
||||
"""A station location must have be located in 3-D"""
|
||||
def __init__(self, locsXYZ, **kwargs):
|
||||
locs = locsXYZ
|
||||
assert locsXYZ.shape[1] == 3, 'locs must in 3-D (x,y,z).'
|
||||
super(RxObs, self).__init__(locs, 'tmi', storeProjections=False, **kwargs)
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data in the receiver."""
|
||||
return self.locs[0].shape[0]
|
||||
@@ -1,194 +0,0 @@
|
||||
from SimPEG import Maps, Survey, Utils, np, sp
|
||||
from scipy.constants import mu_0
|
||||
import re
|
||||
|
||||
|
||||
class BaseMagSurvey(Survey.BaseSurvey):
|
||||
"""Base Magnetics Survey"""
|
||||
|
||||
rxLoc = None #: receiver locations
|
||||
rxType = None #: receiver type
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
|
||||
def setBackgroundField(self, Inc, Dec, Btot):
|
||||
|
||||
Bx = Btot*np.cos(Inc/180.*np.pi)*np.sin(Dec/180.*np.pi)
|
||||
By = Btot*np.cos(Inc/180.*np.pi)*np.cos(Dec/180.*np.pi)
|
||||
Bz = -Btot*np.sin(Inc/180.*np.pi)
|
||||
|
||||
self.B0 = np.r_[Bx, By, Bz]
|
||||
|
||||
@property
|
||||
def Qfx(self):
|
||||
if getattr(self, '_Qfx', None) is None:
|
||||
self._Qfx = self.prob.mesh.getInterpolationMat(self.rxLoc, 'Fx')
|
||||
return self._Qfx
|
||||
|
||||
@property
|
||||
def Qfy(self):
|
||||
if getattr(self, '_Qfy', None) is None:
|
||||
self._Qfy = self.prob.mesh.getInterpolationMat(self.rxLoc, 'Fy')
|
||||
return self._Qfy
|
||||
|
||||
@property
|
||||
def Qfz(self):
|
||||
if getattr(self, '_Qfz', None) is None:
|
||||
self._Qfz = self.prob.mesh.getInterpolationMat(self.rxLoc, 'Fz')
|
||||
return self._Qfz
|
||||
|
||||
def projectFields(self, u):
|
||||
"""
|
||||
This function projects the fields onto the data space.
|
||||
|
||||
Especially, here for we use total magnetic intensity (TMI) data,
|
||||
which is common in practice.
|
||||
|
||||
First we project our B on to data location
|
||||
|
||||
.. math::
|
||||
|
||||
\mathbf{B}_{rec} = \mathbf{P} \mathbf{B}
|
||||
|
||||
then we take the dot product between B and b_0
|
||||
|
||||
.. math ::
|
||||
|
||||
\\text{TMI} = \\vec{B}_s \cdot \hat{B}_0
|
||||
|
||||
"""
|
||||
# TODO: There can be some different tyes of data like |B| or B
|
||||
|
||||
bfx = self.Qfx*u['B']
|
||||
bfy = self.Qfy*u['B']
|
||||
bfz = self.Qfz*u['B']
|
||||
|
||||
# Generate unit vector
|
||||
B0 = self.prob.survey.B0
|
||||
Bot = np.sqrt(B0[0]**2+B0[1]**2+B0[2]**2)
|
||||
box = B0[0]/Bot
|
||||
boy = B0[1]/Bot
|
||||
boz = B0[2]/Bot
|
||||
|
||||
# return bfx*box + bfx*boy + bfx*boz
|
||||
return bfx*box + bfy*boy + bfz*boz
|
||||
|
||||
@Utils.count
|
||||
def projectFieldsDeriv(self, B):
|
||||
"""
|
||||
This function projects the fields onto the data space.
|
||||
|
||||
.. math::
|
||||
|
||||
\\frac{\partial d_\\text{pred}}{\partial \mathbf{B}} = \mathbf{P}
|
||||
|
||||
Especially, this function is for TMI data type
|
||||
|
||||
"""
|
||||
# Generate unit vector
|
||||
B0 = self.prob.survey.B0
|
||||
Bot = np.sqrt(B0[0]**2+B0[1]**2+B0[2]**2)
|
||||
box = B0[0]/Bot
|
||||
boy = B0[1]/Bot
|
||||
boz = B0[2]/Bot
|
||||
|
||||
return self.Qfx*box+self.Qfy*boy+self.Qfz*boz
|
||||
|
||||
def projectFieldsAsVector(self, B):
|
||||
|
||||
bfx = self.Qfx*B
|
||||
bfy = self.Qfy*B
|
||||
bfz = self.Qfz*B
|
||||
|
||||
return np.r_[bfx, bfy, bfz]
|
||||
|
||||
|
||||
class LinearSurvey(Survey.BaseSurvey):
|
||||
"""Base Magnetics Survey"""
|
||||
|
||||
rxLoc = None #: receiver locations
|
||||
rxType = None #: receiver type
|
||||
|
||||
def __init__(self, srcField, **kwargs):
|
||||
self.srcField = srcField
|
||||
Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
|
||||
def eval(self, u):
|
||||
return u
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
return self.prob.G.shape[0]
|
||||
|
||||
@property
|
||||
def nRx(self):
|
||||
return self.srcField.rxList[0].locs.shape[0]
|
||||
# def setBackgroundField(self, SrcField):
|
||||
|
||||
# if getattr(self, 'B0', None) is None:
|
||||
# self._B0 = SrcField.param[0] * dipazm_2_xyz(SrcField.param[1],SrcField.param[2])
|
||||
|
||||
# return self._B0
|
||||
|
||||
|
||||
class SrcField(Survey.BaseSrc):
|
||||
""" Define the inducing field """
|
||||
|
||||
param = None #: Inducing field param (Amp, Incl, Decl)
|
||||
|
||||
def __init__(self, rxList, **kwargs):
|
||||
super(SrcField, self).__init__(rxList, **kwargs)
|
||||
|
||||
|
||||
class RxObs(Survey.BaseRx):
|
||||
"""A station location must have be located in 3-D"""
|
||||
def __init__(self, locsXYZ, **kwargs):
|
||||
locs = locsXYZ
|
||||
assert locsXYZ.shape[1] == 3, 'locs must in 3-D (x,y,z).'
|
||||
super(RxObs, self).__init__(locs, 'tmi', storeProjections=False, **kwargs)
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data in the receiver."""
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
|
||||
class MagSurveyBx(object):
|
||||
"""docstring for MagSurveyBx"""
|
||||
def __init__(self, **kwargs):
|
||||
Survey.BaseData.__init__(self, **kwargs)
|
||||
|
||||
def projectFields(self, B):
|
||||
bfx = self.Qfx*B
|
||||
return bfx
|
||||
|
||||
|
||||
class BaseMagMap(Maps.IdentityMap):
|
||||
"""BaseMagMap"""
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
Maps.IdentityMap.__init__(self, mesh)
|
||||
|
||||
def _transform(self, m):
|
||||
|
||||
return mu_0*(1 + m)
|
||||
|
||||
def deriv(self, m):
|
||||
|
||||
return mu_0*sp.identity(self.nP)
|
||||
|
||||
|
||||
class WeightMap(Maps.IdentityMap):
|
||||
"""Weighted Map for distributed parameters"""
|
||||
|
||||
def __init__(self, nP, weight, **kwargs):
|
||||
Maps.IdentityMap.__init__(self, nP)
|
||||
self.mesh = None
|
||||
self.weight = weight
|
||||
|
||||
def _transform(self, m):
|
||||
return m*self.weight
|
||||
|
||||
def deriv(self, m):
|
||||
return Utils.sdiag(self.weight)
|
||||
@@ -1,576 +0,0 @@
|
||||
from SimPEG import *
|
||||
import BaseGrav as GRAV
|
||||
import re
|
||||
|
||||
|
||||
class GravityIntegral(Problem.BaseProblem):
|
||||
|
||||
# surveyPair = Survey.LinearSurvey
|
||||
forwardOnly = False #: Determine if the forward matrix is stored (defaut:yes)
|
||||
actInd = None #: Active cell indices provided
|
||||
rtype = 'z'
|
||||
|
||||
def __init__(self, mesh, mapping=None, **kwargs):
|
||||
Problem.BaseProblem.__init__(self, mesh, mapping=mapping, **kwargs)
|
||||
|
||||
def fwr_op(self):
|
||||
# Add forward function
|
||||
# kappa = self.curModel.kappa TODO
|
||||
rho = self.mapping*self.curModel
|
||||
|
||||
if self.forwardOnly:
|
||||
|
||||
if getattr(self, 'actInd', None) is not None:
|
||||
|
||||
if self.actInd.dtype=='bool':
|
||||
inds = np.asarray([inds for inds, elem in enumerate(self.actInd, 1) if elem], dtype = int) - 1
|
||||
else:
|
||||
inds = self.actInd
|
||||
|
||||
else:
|
||||
|
||||
inds = np.asarray(range(self.mesh.nC))
|
||||
|
||||
nC = len(inds)
|
||||
|
||||
# Create active cell projector
|
||||
P = sp.csr_matrix(
|
||||
(np.ones(nC), (inds, range(nC))),
|
||||
shape=(self.mesh.nC, nC)
|
||||
)
|
||||
|
||||
# Create vectors of nodal location (lower and upper corners for each cell)
|
||||
xn = self.mesh.vectorNx
|
||||
yn = self.mesh.vectorNy
|
||||
zn = self.mesh.vectorNz
|
||||
|
||||
yn2, xn2, zn2 = np.meshgrid(yn[1:], xn[1:], zn[1:])
|
||||
yn1, xn1, zn1 = np.meshgrid(yn[0:-1], xn[0:-1], zn[0:-1])
|
||||
|
||||
Yn = P.T*np.c_[mkvc(yn1), mkvc(yn2)]
|
||||
Xn = P.T*np.c_[mkvc(xn1), mkvc(xn2)]
|
||||
Zn = P.T*np.c_[mkvc(zn1), mkvc(zn2)]
|
||||
|
||||
rxLoc = self.survey.srcField.rxList[0].locs
|
||||
ndata = rxLoc.shape[0]
|
||||
|
||||
|
||||
# Pre-allocate space and create magnetization matrix if required
|
||||
# Pre-allocate space
|
||||
if self.rtype == 'z':
|
||||
|
||||
fwr_d = np.zeros(self.survey.nRx)
|
||||
|
||||
elif self.rtype == 'xyz':
|
||||
|
||||
fwr_d = np.zeros(3*self.survey.nRx)
|
||||
|
||||
else:
|
||||
|
||||
print """Flag must be either 'z' | 'xyz', please revised"""
|
||||
return
|
||||
|
||||
|
||||
# Add counter to dsiplay progress. Good for large problems
|
||||
count = -1;
|
||||
for ii in range(ndata):
|
||||
|
||||
|
||||
tx, ty, tz = get_T_mat(Xn, Yn, Zn, rxLoc[ii, :])
|
||||
|
||||
|
||||
if self.rtype =='z':
|
||||
fwr_d[ii] =tz.dot(rho)
|
||||
|
||||
elif self.rtype =='xyz':
|
||||
fwr_d[ii] = tx.dot(rho)
|
||||
fwr_d[ii+ndata] = ty.dot(rho)
|
||||
fwr_d[ii+2*ndata] = tz.dot(rho)
|
||||
|
||||
|
||||
# Display progress
|
||||
count = progress(ii,count,ndata)
|
||||
|
||||
print "Done 100% ...forward operator completed!!\n"
|
||||
|
||||
return fwr_d
|
||||
|
||||
else:
|
||||
return self.G.dot(rho)
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
|
||||
fields = self.fwr_op()
|
||||
|
||||
return fields
|
||||
|
||||
# return self.G.dot(self.mapping*(m))
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
dmudm = self.mapping.deriv(m)
|
||||
return self.G.dot(dmudm*v)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
dmudm = self.mapping.deriv(m)
|
||||
return dmudm.T * (self.G.T.dot(v))
|
||||
|
||||
@property
|
||||
def G(self):
|
||||
if not self.ispaired:
|
||||
raise Exception('Need to pair!')
|
||||
|
||||
if getattr(self, '_G', None) is None:
|
||||
self._G = self.Intrgl_Fwr_Op( 'z' )
|
||||
|
||||
return self._G
|
||||
|
||||
def Intrgl_Fwr_Op(self, flag):
|
||||
|
||||
"""
|
||||
|
||||
Gravity forward operator in integral form
|
||||
|
||||
flag = 'z' | 'xyz'
|
||||
|
||||
Return
|
||||
_G = Linear forward modeling operation
|
||||
|
||||
Created on March, 15th 2016
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
"""
|
||||
# Find non-zero cells
|
||||
# inds = np.nonzero(actv)[0]
|
||||
if getattr(self, 'actInd', None) is not None:
|
||||
|
||||
if self.actInd.dtype=='bool':
|
||||
inds = np.asarray([inds for inds, elem in enumerate(self.actInd, 1) if elem], dtype = int) - 1
|
||||
else:
|
||||
inds = self.actInd
|
||||
|
||||
else:
|
||||
|
||||
inds = np.asarray(range(self.mesh.nC))
|
||||
|
||||
nC = len(inds)
|
||||
|
||||
# Create active cell projector
|
||||
P = sp.csr_matrix(
|
||||
(np.ones(nC), (inds, range(nC))),
|
||||
shape=(self.mesh.nC, nC)
|
||||
)
|
||||
|
||||
# Create vectors of nodal location (lower and upper corners for each cell)
|
||||
xn = self.mesh.vectorNx
|
||||
yn = self.mesh.vectorNy
|
||||
zn = self.mesh.vectorNz
|
||||
|
||||
yn2, xn2, zn2 = np.meshgrid(yn[1:], xn[1:], zn[1:])
|
||||
yn1, xn1, zn1 = np.meshgrid(yn[0:-1], xn[0:-1], zn[0:-1])
|
||||
|
||||
Yn = P.T*np.c_[mkvc(yn1), mkvc(yn2)]
|
||||
Xn = P.T*np.c_[mkvc(xn1), mkvc(xn2)]
|
||||
Zn = P.T*np.c_[mkvc(zn1), mkvc(zn2)]
|
||||
|
||||
rxLoc = self.survey.srcField.rxList[0].locs
|
||||
ndata = rxLoc.shape[0]
|
||||
|
||||
# Pre-allocate space and create magnetization matrix if required
|
||||
# Pre-allocate space
|
||||
if flag == 'z':
|
||||
|
||||
G = np.zeros((ndata, nC))
|
||||
|
||||
elif flag == 'xyz':
|
||||
|
||||
G = np.zeros((int(3*ndata), nC))
|
||||
|
||||
else:
|
||||
|
||||
print """Flag must be either 'z' | 'xyz', please revised"""
|
||||
return
|
||||
|
||||
|
||||
# Loop through all observations and create forward operator (ndata-by-nC)
|
||||
print "Begin calculation of forward operator: " + flag
|
||||
|
||||
# Add counter to dsiplay progress. Good for large problems
|
||||
count = -1;
|
||||
for ii in range(ndata):
|
||||
|
||||
if flag=='z':
|
||||
tt = get_T_mat(Xn, Yn, Zn, rxLoc[ii, :])
|
||||
G[ii, :] = tt
|
||||
|
||||
elif flag == 'xyz':
|
||||
print "Sorry 3-component not implemented yet"
|
||||
|
||||
# Display progress
|
||||
count = progress(ii, count, ndata)
|
||||
|
||||
print "Done 100% ...forward operator completed!!\n"
|
||||
|
||||
return G
|
||||
|
||||
|
||||
def get_T_mat(Xn, Yn, Zn, rxLoc):
|
||||
"""
|
||||
Load in the active nodes of a tensor mesh and computes the gravity tensor
|
||||
for a given observation location rxLoc[obsx, obsy, obsz]
|
||||
|
||||
INPUT:
|
||||
Xn, Yn, Zn: Node location matrix for the lower and upper most corners of
|
||||
all cells in the mesh shape[nC,2]
|
||||
M
|
||||
OUTPUT:
|
||||
Tx = [Txx Txy Txz]
|
||||
Ty = [Tyx Tyy Tyz]
|
||||
Tz = [Tzx Tzy Tzz]
|
||||
|
||||
where each elements have dimension 1-by-nC.
|
||||
Only the upper half 5 elements have to be computed since symetric.
|
||||
Currently done as for-loops but will eventually be changed to vector
|
||||
indexing, once the topography has been figured out.
|
||||
|
||||
"""
|
||||
NewtG=6.6738e-3
|
||||
eps = 1e-10 # add a small value to the locations to avoid /0
|
||||
|
||||
nC = Xn.shape[0]
|
||||
|
||||
# Pre-allocate space for 1D array
|
||||
tx = np.zeros((1,nC))
|
||||
ty = np.zeros((1,nC))
|
||||
tz = np.zeros((1,nC))
|
||||
|
||||
dz = rxLoc[2] - Zn + eps
|
||||
|
||||
dy = Yn - rxLoc[1] + eps
|
||||
|
||||
dx = Xn - rxLoc[0] + eps
|
||||
|
||||
# Compute contribution from each corners
|
||||
for aa in range(2):
|
||||
for bb in range(2):
|
||||
for cc in range(2):
|
||||
|
||||
r = (
|
||||
dx[:, aa] ** 2 +
|
||||
dy[:, bb] ** 2 +
|
||||
dz[:, cc] ** 2
|
||||
) ** (0.50)
|
||||
|
||||
tx = tx - NewtG * (-1) ** aa * (-1) ** bb * (-1) ** cc * (
|
||||
dy[:, bb] * np.log(dz[:, cc] + r) +
|
||||
dz[:, cc] * np.log(dy[:, bb] + r) -
|
||||
dx[:, aa] * np.arctan(dy[:, bb] * dz[:, cc] / (dx[:, aa] * r)))
|
||||
|
||||
ty = ty - NewtG * (-1) ** aa * (-1) ** bb * (-1) ** cc * (
|
||||
dx[:, aa] * np.log(dz[:, cc] + r) +
|
||||
dz[:, cc] * np.log(dx[:, aa] + r) -
|
||||
dy[:, bb] * np.arctan(dx[:, aa] * dz[:, cc] / (dy[:, bb] * r)))
|
||||
|
||||
tz = tz - NewtG * (-1) ** aa * (-1) ** bb * (-1) ** cc * (
|
||||
dx[:, aa] * np.log(dy[:, bb] + r) +
|
||||
dy[:, bb] * np.log(dx[:, aa] + r) -
|
||||
dz[:, cc] * np.arctan(dx[:, aa] * dy[:, bb] / (dz[:, cc] * r)))
|
||||
|
||||
return tx,ty,tz
|
||||
|
||||
|
||||
def progress(iter, prog, final):
|
||||
"""
|
||||
progress(iter,prog,final)
|
||||
|
||||
Function measuring the progress of a process and print to screen the %.
|
||||
Useful to estimate the remaining runtime of a large problem.
|
||||
|
||||
Created on Dec, 20th 2015
|
||||
|
||||
@author: dominiquef
|
||||
"""
|
||||
arg = np.floor(float(iter)/float(final)*10.)
|
||||
|
||||
if arg > prog:
|
||||
|
||||
strg = "Done " + str(arg*10) + " %"
|
||||
print strg
|
||||
prog = arg
|
||||
|
||||
return prog
|
||||
|
||||
|
||||
def writeUBCobs(filename, survey, d):
|
||||
"""
|
||||
writeUBCobs(filename,survey,d)
|
||||
|
||||
Function writing an observation file in UBC-GRAV3D format.
|
||||
|
||||
INPUT
|
||||
filename : Name of out file including directory
|
||||
survey
|
||||
flag : dobs | dpred
|
||||
|
||||
OUTPUT
|
||||
Obsfile
|
||||
|
||||
"""
|
||||
|
||||
rxLoc = survey.srcField.rxList[0].locs
|
||||
|
||||
wd = survey.std
|
||||
|
||||
data = np.c_[rxLoc, d, wd]
|
||||
|
||||
with file(filename, 'w') as fid:
|
||||
fid.write('%i\n' % len(d))
|
||||
np.savetxt(fid, data, fmt='%e', delimiter=' ', newline='\n')
|
||||
|
||||
print "Observation file saved to: " + filename
|
||||
|
||||
|
||||
def getActiveTopo(mesh, topo, flag):
|
||||
"""
|
||||
getActiveTopo(mesh,topo)
|
||||
|
||||
Function creates an active cell model from topography
|
||||
|
||||
INPUT
|
||||
mesh : Mesh in SimPEG format
|
||||
topo : Scatter points defining topography [x,y,z]
|
||||
|
||||
OUTPUT
|
||||
actv : Active cell model
|
||||
|
||||
"""
|
||||
import scipy.interpolate as interpolation
|
||||
|
||||
if flag == 'N':
|
||||
Zn = np.zeros((mesh.nNx, mesh.nNy))
|
||||
# wght = np.zeros((mesh.nNx,mesh.nNy))
|
||||
cx = mesh.vectorNx
|
||||
cy = mesh.vectorNy
|
||||
|
||||
F = interpolation.NearestNDInterpolator(topo[:, 0:2], topo[:, 2])
|
||||
[Y, X] = np.meshgrid(cy, cx)
|
||||
|
||||
Zn = F(X, Y)
|
||||
|
||||
actv = np.zeros((mesh.nCx, mesh.nCy, mesh.nCz))
|
||||
|
||||
if flag == 'N':
|
||||
Nz = mesh.vectorNz[1:]
|
||||
|
||||
for jj in range(mesh.nCy):
|
||||
|
||||
for ii in range(mesh.nCx):
|
||||
|
||||
temp = [kk for kk in range(len(Nz)) if np.all(Zn[ii:(ii+2), jj:(jj+2)] > Nz[kk]) ]
|
||||
actv[ii, jj, temp] = 1
|
||||
|
||||
actv = mkvc(actv == 1)
|
||||
|
||||
inds = np.asarray([inds for inds, elem in enumerate(actv, 1) if elem], dtype = int) - 1
|
||||
|
||||
return inds
|
||||
|
||||
def plot_obs_2D(survey,varstr, fig = None):
|
||||
""" Function plot_obs(rxLoc,d,wd)
|
||||
Generate a 2d interpolated plot from scatter points of data
|
||||
|
||||
INPUT
|
||||
rxLoc : Observation locations [x,y,z]
|
||||
d : Data vector
|
||||
wd : Uncertainty vector
|
||||
|
||||
OUTPUT
|
||||
figure()
|
||||
|
||||
Created on Dec, 27th 2015
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
"""
|
||||
|
||||
from scipy.interpolate import griddata
|
||||
import pylab as plt
|
||||
|
||||
rxLoc = survey.srcField.rxList[0].locs
|
||||
d = survey.dobs
|
||||
wd = survey.std
|
||||
|
||||
# Create grid of points
|
||||
x = np.linspace(rxLoc[:,0].min(), rxLoc[:,0].max(), 100)
|
||||
y = np.linspace(rxLoc[:,1].min(), rxLoc[:,1].max(), 100)
|
||||
|
||||
X, Y = np.meshgrid(x,y)
|
||||
|
||||
# Interpolate
|
||||
d_grid = griddata(rxLoc[:,0:2],d,(X,Y), method ='linear')
|
||||
|
||||
# Plot result
|
||||
if fig is None:
|
||||
fig = plt.figure()
|
||||
|
||||
ax = plt.subplot()
|
||||
plt.imshow(d_grid, extent=[x.min(), x.max(), y.min(), y.max()],origin = 'lower', cmap='plasma')
|
||||
plt.colorbar(fraction=0.02)
|
||||
plt.contour(X,Y, d_grid,10)
|
||||
plt.scatter(rxLoc[:,0],rxLoc[:,1], c=d, s=20)
|
||||
plt.title(varstr)
|
||||
plt.gca().set_aspect('equal', adjustable='box')
|
||||
|
||||
def readUBCgravObs(obs_file):
|
||||
|
||||
"""
|
||||
Read UBC grav file format
|
||||
|
||||
INPUT:
|
||||
:param fileName, path to the UBC obs grav file
|
||||
|
||||
OUTPUT:
|
||||
:param survey
|
||||
|
||||
"""
|
||||
|
||||
fid = open(obs_file,'r')
|
||||
|
||||
# First line has the number of rows
|
||||
line = fid.readline()
|
||||
ndat = np.array(line.split(),dtype=int)
|
||||
|
||||
# Pre-allocate space for obsx, obsy, obsz, data, uncert
|
||||
line = fid.readline()
|
||||
temp = np.array(line.split(),dtype=float)
|
||||
|
||||
d = np.zeros(ndat, dtype=float)
|
||||
wd = np.zeros(ndat, dtype=float)
|
||||
locXYZ = np.zeros( (ndat,3), dtype=float)
|
||||
|
||||
for ii in range(ndat):
|
||||
|
||||
temp = np.array(line.split(),dtype=float)
|
||||
locXYZ[ii,:] = temp[:3]
|
||||
d[ii] = temp[3]
|
||||
wd[ii] = temp[4]
|
||||
line = fid.readline()
|
||||
|
||||
rxLoc = GRAV.RxObs(locXYZ)
|
||||
srcField = GRAV.SrcField([rxLoc])
|
||||
survey = GRAV.LinearSurvey(srcField)
|
||||
survey.dobs = d
|
||||
survey.std = wd
|
||||
return survey
|
||||
|
||||
|
||||
def read_GRAVinv_inp(input_file):
|
||||
"""Read input files for forward modeling MAG data with integral form
|
||||
INPUT:
|
||||
input_file: File name containing the forward parameter
|
||||
|
||||
OUTPUT:
|
||||
mshfile
|
||||
obsfile
|
||||
topofile
|
||||
start model
|
||||
ref model
|
||||
weightfile
|
||||
chi_target
|
||||
as, ax ,ay, az
|
||||
upper, lower bounds
|
||||
lp, lqx, lqy, lqz
|
||||
|
||||
# All files should be in the working directory, otherwise the path must
|
||||
# be specified.
|
||||
|
||||
Created on Dec 21th, 2015
|
||||
|
||||
@author: dominiquef
|
||||
"""
|
||||
|
||||
|
||||
fid = open(input_file,'r')
|
||||
|
||||
# Line 1
|
||||
line = fid.readline()
|
||||
l_input = line.split('!')
|
||||
mshfile = l_input[0].rstrip()
|
||||
|
||||
# Line 2
|
||||
line = fid.readline()
|
||||
l_input = line.split('!')
|
||||
obsfile = l_input[0].rstrip()
|
||||
|
||||
# Line 3
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input=='null':
|
||||
topofile = []
|
||||
|
||||
else:
|
||||
topofile = l_input[0].rstrip()
|
||||
|
||||
|
||||
# Line 4
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
mstart = float(l_input[1])
|
||||
|
||||
else:
|
||||
mstart = l_input[0].rstrip()
|
||||
|
||||
# Line 5
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
mref = float(l_input[1])
|
||||
|
||||
else:
|
||||
mref = l_input[0].rstrip()
|
||||
|
||||
|
||||
# Line 7
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='DEFAULT':
|
||||
wgtfile = None
|
||||
|
||||
else:
|
||||
wgtfile = l_input[0].rstrip()
|
||||
|
||||
# Line 8
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
chi = float(l_input[0])
|
||||
|
||||
# Line 9
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
val = np.array(l_input[0:4])
|
||||
alphas = val.astype(np.float)
|
||||
|
||||
# Line 10
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
val = np.array(l_input[1:3])
|
||||
bounds = val.astype(np.float)
|
||||
|
||||
else:
|
||||
bounds = l_input[0].rstrip()
|
||||
|
||||
# Line 11
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
val = np.array(l_input[1:6])
|
||||
lpnorms = val.astype(np.float)
|
||||
|
||||
else:
|
||||
lpnorms = l_input[0].rstrip()
|
||||
|
||||
return mshfile, obsfile, topofile, mstart, mref, wgtfile, chi, alphas, bounds, lpnorms
|
||||
|
||||
@@ -1,295 +0,0 @@
|
||||
import re, os
|
||||
from SimPEG import Mesh, np, Utils
|
||||
import BaseGrav, Gravity
|
||||
|
||||
|
||||
class GravityDriver_Inv(object):
|
||||
"""docstring for GravityDriver_Inv"""
|
||||
|
||||
def __init__(self, input_file=None):
|
||||
if input_file is not None:
|
||||
self.basePath = os.path.sep.join(input_file.split(os.path.sep)[:-1])
|
||||
if len(self.basePath) > 0:
|
||||
self.basePath += os.path.sep
|
||||
self.readDriverFile(input_file.split(os.path.sep)[-1])
|
||||
|
||||
def readDriverFile(self, input_file):
|
||||
"""
|
||||
Read input files for forward modeling GRAV data with integral form
|
||||
INPUT:
|
||||
input_file: File name containing the forward parameter
|
||||
|
||||
OUTPUT:
|
||||
mshfile
|
||||
obsfile
|
||||
topofile
|
||||
start model
|
||||
ref model
|
||||
active cells model
|
||||
weightfile
|
||||
chi_target
|
||||
as, ax ,ay, az
|
||||
upper, lower bounds
|
||||
lp, lqx, lqy, lqz
|
||||
eps_p, eps_q
|
||||
# All files should be in the working directory, otherwise the path must
|
||||
# be specified.
|
||||
|
||||
"""
|
||||
|
||||
fid = open(self.basePath + input_file, 'r')
|
||||
|
||||
# Line 1
|
||||
line = fid.readline()
|
||||
l_input = line.split('!')
|
||||
mshfile = l_input[0].rstrip()
|
||||
|
||||
# Line 2
|
||||
line = fid.readline()
|
||||
l_input = line.split('!')
|
||||
obsfile = l_input[0].rstrip()
|
||||
|
||||
# Line 3
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
if l_input=='null':
|
||||
topofile = []
|
||||
|
||||
else:
|
||||
topofile = l_input[0].rstrip()
|
||||
|
||||
|
||||
# Line 4
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
if l_input[0]=='VALUE':
|
||||
mstart = float(l_input[1])
|
||||
|
||||
else:
|
||||
mstart = l_input[0].rstrip()
|
||||
|
||||
# Line 5
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
mref = float(l_input[1])
|
||||
|
||||
else:
|
||||
mref = l_input[0].rstrip()
|
||||
|
||||
# Line 6
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
if l_input[0]=='VALUE':
|
||||
staticInput = float(l_input[1])
|
||||
|
||||
elif l_input[0]=='DEFAULT':
|
||||
staticInput = None
|
||||
|
||||
else:
|
||||
staticInput = l_input[0].rstrip()
|
||||
|
||||
# Line 7
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
if l_input=='DEFAULT':
|
||||
wgtfile = []
|
||||
|
||||
else:
|
||||
wgtfile = l_input[0].rstrip()
|
||||
|
||||
# Line 8
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
chi = float(l_input[0])
|
||||
|
||||
# Line 9
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
val = np.array(l_input[0:4])
|
||||
alphas = val.astype(np.float)
|
||||
|
||||
# Line 10
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
if l_input[0]=='VALUE':
|
||||
val = np.array(l_input[1:3])
|
||||
bounds = val.astype(np.float)
|
||||
|
||||
else:
|
||||
bounds = l_input[0].rstrip()
|
||||
|
||||
# Line 11
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
if l_input[0]=='VALUE':
|
||||
val = np.array(l_input[1:6])
|
||||
lpnorms = val.astype(np.float)
|
||||
|
||||
else:
|
||||
lpnorms = l_input[0].rstrip()
|
||||
|
||||
# Line 12
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]', line)
|
||||
if l_input[0]=='VALUE':
|
||||
val = np.array(l_input[1:3])
|
||||
eps = val.astype(np.float)
|
||||
|
||||
else:
|
||||
eps = [None, None]
|
||||
|
||||
self.mshfile = mshfile
|
||||
self.obsfile = obsfile
|
||||
self.topofile = topofile
|
||||
self.mstart = mstart
|
||||
self._mrefInput = mref
|
||||
self._staticInput = staticInput
|
||||
self.wgtfile = wgtfile
|
||||
self.chi = chi
|
||||
self.alphas = alphas
|
||||
self.bounds = bounds
|
||||
self.lpnorms = lpnorms
|
||||
self.eps = eps
|
||||
|
||||
@property
|
||||
def mesh(self):
|
||||
if getattr(self, '_mesh', None) is None:
|
||||
self._mesh = Mesh.TensorMesh.readUBC(self.basePath + self.mshfile)
|
||||
return self._mesh
|
||||
|
||||
@property
|
||||
def survey(self):
|
||||
if getattr(self, '_survey', None) is None:
|
||||
self._survey = self.readGravityObservations(self.basePath + self.obsfile)
|
||||
return self._survey
|
||||
|
||||
@property
|
||||
def activeCells(self):
|
||||
if getattr(self, '_activeCells', None) is None:
|
||||
if self.topofile == 'null':
|
||||
self._activeCells = np.arange(mesh.nC)
|
||||
else:
|
||||
topo = np.genfromtxt(self.basePath + self.topofile, skip_header=1)
|
||||
# Find the active cells
|
||||
active = Utils.surface2ind_topo(self.mesh,topo,'N')
|
||||
inds = np.asarray([inds for inds, elem in enumerate(active, 1) if elem], dtype = int) - 1
|
||||
self._activeCells = inds
|
||||
|
||||
return self._activeCells
|
||||
|
||||
@property
|
||||
def staticCells(self):
|
||||
if getattr(self, '_staticCells', None) is None:
|
||||
|
||||
if getattr(self, '_staticInput', None) is None:
|
||||
# All cells are dynamic: 1's
|
||||
self._dynamicCells = np.arange(len(self.m0))
|
||||
self._staticCells = []
|
||||
|
||||
# Cells with specific value are static: 0's
|
||||
else:
|
||||
if isinstance(self._staticInput, float):
|
||||
staticCells = self.m0 == self._staticInput
|
||||
|
||||
else:
|
||||
# Read from file active cells with 0:air, 1:dynamic, -1 static
|
||||
staticCells = Mesh.TensorMesh.readModelUBC(self.mesh, self.basePath + self._staticInput)
|
||||
staticCells = staticCells[self.activeCells] == -1
|
||||
|
||||
inds = np.asarray([inds for inds, elem in enumerate(staticCells, 1) if elem], dtype = int) - 1
|
||||
self._staticCells = inds
|
||||
|
||||
return self._staticCells
|
||||
|
||||
@property
|
||||
def dynamicCells(self):
|
||||
if getattr(self, '_dynamicCells', None) is None:
|
||||
|
||||
if getattr(self, '_staticInput', None) is None:
|
||||
# All cells are dynamic: 1's
|
||||
self._dynamicCells = np.arange(len(self.m0))
|
||||
|
||||
# Cells with specific value are static: 0's
|
||||
else:
|
||||
if isinstance(self._staticInput, float):
|
||||
dynamicCells = self.m0 != self._staticInput
|
||||
|
||||
else:
|
||||
# Read from file active cells with 0:air, 1:dynamic, -1 static
|
||||
dynamicCells = Mesh.TensorMesh.readModelUBC(self.mesh, self.basePath + self._staticInput)
|
||||
dynamicCells = dynamicCells[self.activeCells] == 1
|
||||
|
||||
inds = np.asarray([inds for inds, elem in enumerate(dynamicCells, 1) if elem], dtype = int) - 1
|
||||
self._dynamicCells = inds
|
||||
|
||||
return self._dynamicCells
|
||||
|
||||
@property
|
||||
def nC(self):
|
||||
if getattr(self, '_nC', None) is None:
|
||||
self._nC = len(self.activeCells)
|
||||
return self._nC
|
||||
|
||||
@property
|
||||
def m0(self):
|
||||
if getattr(self, '_m0', None) is None:
|
||||
if isinstance(self.mstart, float):
|
||||
self._m0 = np.ones(self.nC) * self.mstart
|
||||
else:
|
||||
|
||||
self._m0 = Mesh.TensorMesh.readModelUBC(self.mesh, self.basePath + self.mstart)
|
||||
self._m0 = self._m0[self.activeCells]
|
||||
|
||||
return self._m0
|
||||
|
||||
@property
|
||||
def mref(self):
|
||||
if getattr(self, '_mref', None) is None:
|
||||
if isinstance(self._mrefInput, float):
|
||||
self._mref = np.ones(self.nC) * self._mrefInput
|
||||
else:
|
||||
self._mref = Mesh.TensorMesh.readModelUBC(self.mesh, self.basePath + self._mrefInput)
|
||||
self._mref = self._mref[self.activeCells]
|
||||
return self._mref
|
||||
|
||||
def readGravityObservations(self, obs_file):
|
||||
"""
|
||||
Read UBC grav file format
|
||||
|
||||
INPUT:
|
||||
:param fileName, path to the UBC obs grav file
|
||||
|
||||
OUTPUT:
|
||||
:param survey
|
||||
|
||||
"""
|
||||
|
||||
fid = open(obs_file,'r')
|
||||
|
||||
# First line has the number of rows
|
||||
line = fid.readline()
|
||||
ndat = np.array(line.split(),dtype=int)
|
||||
|
||||
# Pre-allocate space for obsx, obsy, obsz, data, uncert
|
||||
line = fid.readline()
|
||||
temp = np.array(line.split(),dtype=float)
|
||||
|
||||
d = np.zeros(ndat, dtype=float)
|
||||
wd = np.zeros(ndat, dtype=float)
|
||||
locXYZ = np.zeros( (ndat,3), dtype=float)
|
||||
|
||||
for ii in range(ndat):
|
||||
|
||||
temp = np.array(line.split(),dtype=float)
|
||||
locXYZ[ii,:] = temp[:3]
|
||||
d[ii] = temp[3]
|
||||
wd[ii] = temp[4]
|
||||
line = fid.readline()
|
||||
|
||||
rxLoc = BaseGrav.RxObs(locXYZ)
|
||||
srcField = BaseGrav.SrcField([rxLoc])
|
||||
survey = BaseGrav.LinearSurvey(srcField)
|
||||
survey.dobs = d
|
||||
survey.std = wd
|
||||
return survey
|
||||
@@ -1,278 +0,0 @@
|
||||
from scipy.constants import mu_0
|
||||
from SimPEG import *
|
||||
from SimPEG.Utils import kron3, speye, sdiag
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
def spheremodel(mesh, x0, y0, z0, r):
|
||||
"""
|
||||
Generate model indicies for sphere
|
||||
- (x0, y0, z0 ): is the center location of sphere
|
||||
- r: is the radius of the sphere
|
||||
- it returns logical indicies of cell-center model
|
||||
"""
|
||||
ind = np.sqrt( (mesh.gridCC[:,0]-x0)**2+(mesh.gridCC[:,1]-y0)**2+(mesh.gridCC[:,2]-z0)**2 ) < r
|
||||
return ind
|
||||
|
||||
|
||||
def MagSphereAnaFun(x, y, z, R, x0, y0, z0, mu1, mu2, H0, flag='total'):
|
||||
"""
|
||||
test
|
||||
Analytic function for Magnetics problem. The set up here is
|
||||
magnetic sphere in whole-space assuming that the inducing field is oriented in the x-direction.
|
||||
|
||||
* (x0,y0,z0)
|
||||
* (x0, y0, z0 ): is the center location of sphere
|
||||
* r: is the radius of the sphere
|
||||
|
||||
.. math::
|
||||
|
||||
\mathbf{H}_0 = H_0\hat{x}
|
||||
|
||||
|
||||
"""
|
||||
|
||||
if (~np.size(x)==np.size(y)==np.size(z)):
|
||||
print "Specify same size of x, y, z"
|
||||
return
|
||||
dim = x.shape
|
||||
x = Utils.mkvc(x)
|
||||
y = Utils.mkvc(y)
|
||||
z = Utils.mkvc(z)
|
||||
|
||||
ind = np.sqrt((x-x0)**2+(y-y0)**2+(z-z0)**2 ) < R
|
||||
r = Utils.mkvc(np.sqrt((x-x0)**2+(y-y0)**2+(z-z0)**2 ))
|
||||
Bx = np.zeros(x.size)
|
||||
By = np.zeros(x.size)
|
||||
Bz = np.zeros(x.size)
|
||||
|
||||
# Inside of the sphere
|
||||
rf2 = 3*mu1/(mu2+2*mu1)
|
||||
if flag is 'total' and any(ind):
|
||||
Bx[ind] = mu2*H0*(rf2)
|
||||
elif (flag == 'secondary'):
|
||||
Bx[ind] = mu2*H0*(rf2)-mu1*H0
|
||||
|
||||
By[ind] = 0.
|
||||
Bz[ind] = 0.
|
||||
# Outside of the sphere
|
||||
rf1 = (mu2-mu1)/(mu2+2*mu1)
|
||||
if (flag == 'total'):
|
||||
Bx[~ind] = mu1*(H0+H0/r[~ind]**5*(R**3)*rf1*(2*(x[~ind]-x0)**2-(y[~ind]-y0)**2-(z[~ind]-z0)**2))
|
||||
elif (flag == 'secondary'):
|
||||
Bx[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(2*(x[~ind]-x0)**2-(y[~ind]-y0)**2-(z[~ind]-z0)**2))
|
||||
|
||||
By[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(3*(x[~ind]-x0)*(y[~ind]-y0)))
|
||||
Bz[~ind] = mu1*(H0/r[~ind]**5*(R**3)*rf1*(3*(x[~ind]-x0)*(z[~ind]-z0)))
|
||||
return np.reshape(Bx, x.shape, order='F'), np.reshape(By, x.shape, order='F'), np.reshape(Bz, x.shape, order='F')
|
||||
|
||||
|
||||
def CongruousMagBC(mesh, Bo, chi):
|
||||
"""
|
||||
Computing boundary condition using Congrous sphere method.
|
||||
This is designed for secondary field formulation.
|
||||
|
||||
>> Input
|
||||
|
||||
* mesh: Mesh class
|
||||
* Bo: np.array([Box, Boy, Boz]): Primary magnetic flux
|
||||
* chi: susceptibility at cell volume
|
||||
|
||||
.. math::
|
||||
|
||||
\\vec{B}(r) = \\frac{\mu_0}{4\pi} \\frac{m}{ \| \\vec{r} - \\vec{r}_0\|^3}[3\hat{m}\cdot\hat{r}-\hat{m}]
|
||||
|
||||
"""
|
||||
|
||||
ind = chi > 0.
|
||||
V = mesh.vol[ind].sum()
|
||||
|
||||
gamma = 1/V*(chi*mesh.vol).sum() # like a mass!
|
||||
|
||||
Bot = np.sqrt(sum(Bo**2))
|
||||
mx = Bo[0]/Bot
|
||||
my = Bo[1]/Bot
|
||||
mz = Bo[2]/Bot
|
||||
|
||||
mom = 1/mu_0*Bot*gamma*V/(1+gamma/3)
|
||||
xc = sum(chi[ind]*mesh.gridCC[:,0][ind])/sum(chi[ind])
|
||||
yc = sum(chi[ind]*mesh.gridCC[:,1][ind])/sum(chi[ind])
|
||||
zc = sum(chi[ind]*mesh.gridCC[:,2][ind])/sum(chi[ind])
|
||||
|
||||
indxd, indxu, indyd, indyu, indzd, indzu = mesh.faceBoundaryInd
|
||||
|
||||
const = mu_0/(4*np.pi)*mom
|
||||
rfun = lambda x: np.sqrt((x[:,0]-xc)**2 + (x[:,1]-yc)**2 + (x[:,2]-zc)**2)
|
||||
|
||||
mdotrx = (mx*(mesh.gridFx[(indxd|indxu),0]-xc)/rfun(mesh.gridFx[(indxd|indxu),:]) +
|
||||
my*(mesh.gridFx[(indxd|indxu),1]-yc)/rfun(mesh.gridFx[(indxd|indxu),:]) +
|
||||
mz*(mesh.gridFx[(indxd|indxu),2]-zc)/rfun(mesh.gridFx[(indxd|indxu),:]))
|
||||
|
||||
Bbcx = const/(rfun(mesh.gridFx[(indxd|indxu),:])**3)*(3*mdotrx*(mesh.gridFx[(indxd|indxu),0]-xc)/rfun(mesh.gridFx[(indxd|indxu),:])-mx)
|
||||
|
||||
mdotry = (mx*(mesh.gridFy[(indyd|indyu),0]-xc)/rfun(mesh.gridFy[(indyd|indyu),:]) +
|
||||
my*(mesh.gridFy[(indyd|indyu),1]-yc)/rfun(mesh.gridFy[(indyd|indyu),:]) +
|
||||
mz*(mesh.gridFy[(indyd|indyu),2]-zc)/rfun(mesh.gridFy[(indyd|indyu),:]))
|
||||
|
||||
Bbcy = const/(rfun(mesh.gridFy[(indyd|indyu),:])**3)*(3*mdotry*(mesh.gridFy[(indyd|indyu),1]-yc)/rfun(mesh.gridFy[(indyd|indyu),:])-my)
|
||||
|
||||
mdotrz = (mx*(mesh.gridFz[(indzd|indzu),0]-xc)/rfun(mesh.gridFz[(indzd|indzu),:]) +
|
||||
my*(mesh.gridFz[(indzd|indzu),1]-yc)/rfun(mesh.gridFz[(indzd|indzu),:]) +
|
||||
mz*(mesh.gridFz[(indzd|indzu),2]-zc)/rfun(mesh.gridFz[(indzd|indzu),:]))
|
||||
|
||||
Bbcz = const/(rfun(mesh.gridFz[(indzd|indzu),:])**3)*(3*mdotrz*(mesh.gridFz[(indzd|indzu),2]-zc)/rfun(mesh.gridFz[(indzd|indzu),:])-mz)
|
||||
|
||||
return np.r_[Bbcx, Bbcy, Bbcz], (1/gamma-1/(3+gamma))*1/V
|
||||
|
||||
|
||||
def MagSphereAnaFunA(x, y, z, R, xc, yc, zc, chi, Bo, flag):
|
||||
"""
|
||||
Computing boundary condition using Congrous sphere method.
|
||||
This is designed for secondary field formulation.
|
||||
>> Input
|
||||
mesh: Mesh class
|
||||
Bo: np.array([Box, Boy, Boz]): Primary magnetic flux
|
||||
Chi: susceptibility at cell volume
|
||||
|
||||
.. math::
|
||||
|
||||
\\vec{B}(r) = \\frac{\mu_0}{4\pi}\\frac{m}{\| \\vec{r}-\\vec{r}_0\|^3}[3\hat{m}\cdot\hat{r}-\hat{m}]
|
||||
|
||||
"""
|
||||
if (~np.size(x)==np.size(y)==np.size(z)):
|
||||
print "Specify same size of x, y, z"
|
||||
return
|
||||
dim = x.shape
|
||||
x = Utils.mkvc(x)
|
||||
y = Utils.mkvc(y)
|
||||
z = Utils.mkvc(z)
|
||||
|
||||
Bot = np.sqrt(sum(Bo**2))
|
||||
mx = Bo[0]/Bot
|
||||
my = Bo[1]/Bot
|
||||
mz = Bo[2]/Bot
|
||||
|
||||
ind = np.sqrt((x-xc)**2+(y-yc)**2+(z-zc)**2 ) < R
|
||||
|
||||
Bx = np.zeros(x.size)
|
||||
By = np.zeros(x.size)
|
||||
Bz = np.zeros(x.size)
|
||||
|
||||
# Inside of the sphere
|
||||
rf2 = 3/(chi+3)*(1+chi)
|
||||
if (flag == 'total'):
|
||||
Bx[ind] = Bo[0]*(rf2)
|
||||
By[ind] = Bo[1]*(rf2)
|
||||
Bz[ind] = Bo[2]*(rf2)
|
||||
elif (flag == 'secondary'):
|
||||
Bx[ind] = Bo[0]*(rf2)-Bo[0]
|
||||
By[ind] = Bo[1]*(rf2)-Bo[1]
|
||||
Bz[ind] = Bo[2]*(rf2)-Bo[2]
|
||||
|
||||
r = Utils.mkvc(np.sqrt((x-xc)**2+(y-yc)**2+(z-zc)**2 ))
|
||||
V = 4*np.pi*R**3/3
|
||||
mom = Bot/mu_0*chi/(1+chi/3)*V
|
||||
const = mu_0/(4*np.pi)*mom
|
||||
mdotr = (mx*(x[~ind]-xc)/r[~ind] + my*(y[~ind]-yc)/r[~ind] + mz*(z[~ind]-zc)/r[~ind])
|
||||
Bx[~ind] = const/(r[~ind]**3)*(3*mdotr*(x[~ind]-xc)/r[~ind]-mx)
|
||||
By[~ind] = const/(r[~ind]**3)*(3*mdotr*(y[~ind]-yc)/r[~ind]-my)
|
||||
Bz[~ind] = const/(r[~ind]**3)*(3*mdotr*(z[~ind]-zc)/r[~ind]-mz)
|
||||
|
||||
|
||||
return Bx, By, Bz
|
||||
|
||||
|
||||
def IDTtoxyz(Inc, Dec, Btot):
|
||||
"""
|
||||
Convert from Inclination, Declination, Total intensity of earth field to x, y, z
|
||||
"""
|
||||
Bx = Btot*np.cos(Inc/180.*np.pi)*np.sin(Dec/180.*np.pi)
|
||||
By = Btot*np.cos(Inc/180.*np.pi)*np.cos(Dec/180.*np.pi)
|
||||
Bz = -Btot*np.sin(Inc/180.*np.pi)
|
||||
|
||||
return np.r_[Bx, By, Bz]
|
||||
|
||||
|
||||
def MagSphereFreeSpace(x, y, z, R, xc, yc, zc, chi, Bo):
|
||||
"""
|
||||
Computing boundary condition using Congrous sphere method.
|
||||
This is designed for secondary field formulation.
|
||||
>> Input
|
||||
mesh: Mesh class
|
||||
Bo: np.array([Box, Boy, Boz]): Primary magnetic flux
|
||||
Chi: susceptibility at cell volume
|
||||
|
||||
.. math::
|
||||
|
||||
\\vec{B}(r) = \\frac{\mu_0}{4\pi}\\frac{m}{\| \\vec{r}-\\vec{r}_0\|^3}[3\hat{m}\cdot\hat{r}-\hat{m}]
|
||||
|
||||
"""
|
||||
if (~np.size(x)==np.size(y)==np.size(z)):
|
||||
print "Specify same size of x, y, z"
|
||||
return
|
||||
|
||||
x = Utils.mkvc(x)
|
||||
y = Utils.mkvc(y)
|
||||
z = Utils.mkvc(z)
|
||||
|
||||
nobs = len(x)
|
||||
|
||||
Bot = np.sqrt(sum(Bo**2))
|
||||
|
||||
mx = np.ones([nobs]) * Bo[0,0] * R**3 / 3. * chi
|
||||
my = np.ones([nobs]) * Bo[0,1] * R**3 / 3. * chi
|
||||
mz = np.ones([nobs]) * Bo[0,2] * R**3 / 3. * chi
|
||||
|
||||
M = np.c_[mx, my, mz]
|
||||
|
||||
rx = (x - xc)
|
||||
ry = (y - yc)
|
||||
rz = (zc - z)
|
||||
|
||||
rvec = np.c_[rx, ry, rz]
|
||||
r = np.sqrt((rx)**2+(ry)**2+(rz)**2 )
|
||||
|
||||
B = -Utils.sdiag(1./r**3)*M + Utils.sdiag((3 * np.sum(M*rvec,axis=1))/r**5)*rvec
|
||||
|
||||
Bx = B[:,0]
|
||||
By = B[:,1]
|
||||
Bz = B[:,2]
|
||||
|
||||
return Bx, By, Bz
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
hxind = [(0,25,1.3),(21, 12.5),(0,25,1.3)]
|
||||
hyind = [(0,25,1.3),(21, 12.5),(0,25,1.3)]
|
||||
hzind = [(0,25,1.3),(20, 12.5),(0,25,1.3)]
|
||||
# hx, hy, hz = Utils.meshTensors(hxind, hyind, hzind)
|
||||
M3 = Mesh.TensorMesh([hxind, hyind, hzind], "CCC")
|
||||
indxd, indxu, indyd, indyu, indzd, indzu = M3.faceBoundaryInd
|
||||
mu0 = 4*np.pi*1e-7
|
||||
chibkg = 0.
|
||||
chiblk = 0.01
|
||||
chi = np.ones(M3.nC)*chibkg
|
||||
sph_ind = spheremodel(M3, 0, 0, 0, 100)
|
||||
chi[sph_ind] = chiblk
|
||||
mu = (1.+chi)*mu0
|
||||
Bbc, const = CongruousMagBC(M3, np.array([1., 0., 0.]), chi)
|
||||
|
||||
flag = 'secondary'
|
||||
Box = 1.
|
||||
H0 = Box/mu_0
|
||||
Bbcxx, Bbcxy, Bbcxz = MagSphereAnaFun(M3.gridFx[(indxd|indxu),0], M3.gridFx[(indxd|indxu),1], M3.gridFx[(indxd|indxu),2], 100, 0., 0., 0., mu_0, mu_0*(1+chiblk), H0, flag)
|
||||
Bbcyx, Bbcyy, Bbcyz = MagSphereAnaFun(M3.gridFy[(indyd|indyu),0], M3.gridFy[(indyd|indyu),1], M3.gridFy[(indyd|indyu),2], 100, 0., 0., 0., mu_0, mu_0*(1+chiblk), H0, flag)
|
||||
Bbczx, Bbczy, Bbczz = MagSphereAnaFun(M3.gridFz[(indzd|indzu),0], M3.gridFz[(indzd|indzu),1], M3.gridFz[(indzd|indzu),2], 100, 0., 0., 0., mu_0, mu_0*(1+chiblk), H0, flag)
|
||||
Bbc_ana = np.r_[Bbcxx, Bbcyy, Bbczz]
|
||||
|
||||
# fig, ax = plt.subplots(1,1, figsize = (10, 10))
|
||||
# ax.plot(Bbc_ana)
|
||||
# ax.plot(Bbc)
|
||||
# plt.show()
|
||||
err = np.linalg.norm(Bbc-Bbc_ana)/np.linalg.norm(Bbc_ana)
|
||||
|
||||
if err < 0.1:
|
||||
print 'Mag Boundary computation is valid, err = ', err
|
||||
else:
|
||||
print 'Mag Boundary computation is wrong!!, err = ', err
|
||||
pass
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,334 +0,0 @@
|
||||
import re, os
|
||||
from SimPEG import Mesh, np, Utils
|
||||
import BaseMag, Magnetics
|
||||
|
||||
class MagneticsDriver_Inv(object):
|
||||
"""docstring for MagneticsDriver_Inv"""
|
||||
|
||||
def __init__(self, input_file=None):
|
||||
if input_file is not None:
|
||||
self.basePath = os.path.sep.join(input_file.split(os.path.sep)[:-1])
|
||||
if len(self.basePath) > 0:
|
||||
self.basePath += os.path.sep
|
||||
self.readDriverFile(input_file.split(os.path.sep)[-1])
|
||||
|
||||
|
||||
def readDriverFile(self, input_file):
|
||||
"""
|
||||
Read input files for forward modeling MAG data with integral form
|
||||
INPUT:
|
||||
input_file: File name containing the forward parameter
|
||||
|
||||
OUTPUT:
|
||||
mshfile
|
||||
obsfile
|
||||
topofile
|
||||
start model
|
||||
ref model
|
||||
mag model
|
||||
weightfile
|
||||
chi_target
|
||||
as, ax ,ay, az
|
||||
upper, lower bounds
|
||||
lp, lqx, lqy, lqz
|
||||
|
||||
# All files should be in the working directory, otherwise the path must
|
||||
# be specified.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
fid = open(self.basePath + input_file,'r')
|
||||
|
||||
# Line 1
|
||||
line = fid.readline()
|
||||
l_input = line.split('!')
|
||||
mshfile = l_input[0].rstrip()
|
||||
|
||||
# Line 2
|
||||
line = fid.readline()
|
||||
l_input = line.split('!')
|
||||
obsfile = l_input[0].rstrip()
|
||||
|
||||
# Line 3
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input=='null':
|
||||
topofile = []
|
||||
|
||||
else:
|
||||
topofile = l_input[0].rstrip()
|
||||
|
||||
|
||||
# Line 4
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
mstart = float(l_input[1])
|
||||
|
||||
else:
|
||||
mstart = l_input[0].rstrip()
|
||||
|
||||
# Line 5
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
mref = float(l_input[1])
|
||||
|
||||
else:
|
||||
mref = l_input[0].rstrip()
|
||||
|
||||
# Line 6
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
staticInput = float(l_input[1])
|
||||
|
||||
elif l_input[0]=='DEFAULT':
|
||||
staticInput = None
|
||||
|
||||
else:
|
||||
staticInput = l_input[0].rstrip()
|
||||
|
||||
|
||||
# Line 7
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input=='DEFAULT':
|
||||
magfile = []
|
||||
|
||||
else:
|
||||
magfile = l_input[0].rstrip()
|
||||
|
||||
# Line 8
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input=='DEFAULT':
|
||||
wgtfile = []
|
||||
|
||||
else:
|
||||
wgtfile = l_input[0].rstrip()
|
||||
|
||||
# Line 9
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
chi = float(l_input[0])
|
||||
|
||||
# Line 10
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
val = np.array(l_input[0:4])
|
||||
alphas = val.astype(np.float)
|
||||
|
||||
# Line 11
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
val = np.array(l_input[1:3])
|
||||
bounds = val.astype(np.float)
|
||||
|
||||
else:
|
||||
bounds = l_input[0].rstrip()
|
||||
|
||||
# Line 12
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
val = np.array(l_input[1:6])
|
||||
lpnorms = val.astype(np.float)
|
||||
|
||||
else:
|
||||
lpnorms = l_input[0].rstrip()
|
||||
|
||||
# Line 13
|
||||
line = fid.readline()
|
||||
l_input = re.split('[!\s]',line)
|
||||
if l_input[0]=='VALUE':
|
||||
val = np.array(l_input[1:3])
|
||||
eps = val.astype(np.float)
|
||||
|
||||
else:
|
||||
eps = [None,None]
|
||||
|
||||
self.mshfile = mshfile
|
||||
self.obsfile = obsfile
|
||||
self.topofile = topofile
|
||||
self.mstart = mstart
|
||||
self._mrefInput = mref
|
||||
self._staticInput = staticInput
|
||||
self.magfile = magfile
|
||||
self.wgtfile = wgtfile
|
||||
self.chi = chi
|
||||
self.alphas = alphas
|
||||
self.bounds = bounds
|
||||
self.lpnorms = lpnorms
|
||||
self.eps = eps
|
||||
|
||||
@property
|
||||
def mesh(self):
|
||||
if getattr(self, '_mesh', None) is None:
|
||||
self._mesh = Mesh.TensorMesh.readUBC(self.basePath + self.mshfile)
|
||||
return self._mesh
|
||||
|
||||
@property
|
||||
def survey(self):
|
||||
if getattr(self, '_survey', None) is None:
|
||||
self._survey = self.readMagneticsObservations(self.obsfile)
|
||||
return self._survey
|
||||
|
||||
@property
|
||||
def activeCells(self):
|
||||
if getattr(self, '_activeCells', None) is None:
|
||||
if self.topofile == 'null':
|
||||
self._activeCells = np.arange(self.mesh.nC)
|
||||
else:
|
||||
topo = np.genfromtxt(self.basePath + self.topofile, skip_header=1)
|
||||
# Find the active cells
|
||||
active = Utils.surface2ind_topo(self.mesh,topo,'N')
|
||||
inds = np.asarray([inds for inds, elem in enumerate(active, 1) if elem], dtype = int) - 1
|
||||
self._activeCells = inds
|
||||
|
||||
return self._activeCells
|
||||
|
||||
@property
|
||||
def staticCells(self):
|
||||
if getattr(self, '_staticCells', None) is None:
|
||||
|
||||
if getattr(self, '_staticInput', None) is None:
|
||||
# All cells are dynamic: 1's
|
||||
self._dynamicCells = np.arange(len(self.m0))
|
||||
self._staticCells = []
|
||||
|
||||
# Cells with specific value are static: 0's
|
||||
else:
|
||||
if isinstance(self._staticInput, float):
|
||||
staticCells = self.m0 == self._staticInput
|
||||
|
||||
else:
|
||||
# Read from file active cells with 0:air, 1:dynamic, -1 static
|
||||
staticCells = Mesh.TensorMesh.readModelUBC(self.mesh, self.basePath + self._staticInput)
|
||||
staticCells = staticCells[self.activeCells] == -1
|
||||
|
||||
inds = np.asarray([inds for inds, elem in enumerate(staticCells, 1) if elem], dtype = int) - 1
|
||||
self._staticCells = inds
|
||||
|
||||
return self._staticCells
|
||||
|
||||
@property
|
||||
def dynamicCells(self):
|
||||
if getattr(self, '_dynamicCells', None) is None:
|
||||
|
||||
if getattr(self, '_staticInput', None) is None:
|
||||
# All cells are dynamic: 1's
|
||||
self._dynamicCells = np.arange(len(self.m0))
|
||||
|
||||
# Cells with specific value are static: 0's
|
||||
else:
|
||||
if isinstance(self._staticInput, float):
|
||||
dynamicCells = self.m0 != self._staticInput
|
||||
|
||||
else:
|
||||
# Read from file active cells with 0:air, 1:dynamic, -1 static
|
||||
dynamicCells = Mesh.TensorMesh.readModelUBC(self.mesh, self.basePath + self._staticInput)
|
||||
dynamicCells = dynamicCells[self.activeCells] == 1
|
||||
|
||||
inds = np.asarray([inds for inds, elem in enumerate(dynamicCells, 1) if elem], dtype = int) - 1
|
||||
self._dynamicCells = inds
|
||||
|
||||
return self._dynamicCells
|
||||
|
||||
@property
|
||||
def nC(self):
|
||||
if getattr(self, '_nC', None) is None:
|
||||
self._nC = len(self.activeCells)
|
||||
return self._nC
|
||||
|
||||
@property
|
||||
def m0(self):
|
||||
if getattr(self, '_m0', None) is None:
|
||||
if isinstance(self.mstart, float):
|
||||
self._m0 = np.ones(self.nC) * self.mstart
|
||||
else:
|
||||
self._m0 = Mesh.TensorMesh.readModelUBC(self.mesh,self.basePath + self.mstart)
|
||||
self._m0 = self._m0[self.activeCells]
|
||||
|
||||
return self._m0
|
||||
|
||||
@property
|
||||
def mref(self):
|
||||
if getattr(self, '_mref', None) is None:
|
||||
if isinstance(self._mrefInput, float):
|
||||
self._mref = np.ones(self.nC) * self._mrefInput
|
||||
else:
|
||||
self._mref = Mesh.TensorMesh.readModelUBC(self.mesh,self.basePath + self._mrefInput)
|
||||
self._mref = self._mref[self.activeCells]
|
||||
return self._mref
|
||||
|
||||
|
||||
@property
|
||||
def magnetizationModel(self):
|
||||
"""
|
||||
magnetization vector
|
||||
"""
|
||||
|
||||
if self.magfile == 'DEFAULT':
|
||||
return Magnetics.dipazm_2_xyz(np.ones(self.nC) * self.survey.srcField.param[1], np.ones(self.nC) * self.survey.srcField.param[2])
|
||||
|
||||
else:
|
||||
raise NotImplementedError("this will require you to read in a three column vector model")
|
||||
self._mref = Utils.meshutils.readUBCTensorModel(self.basePath + self._mrefInput, self.mesh)
|
||||
return np.genfromtxt(self.magfile,delimiter=' \n',dtype=np.str,comments='!')
|
||||
|
||||
def readMagneticsObservations(self, obs_file):
|
||||
"""
|
||||
Read and write UBC mag file format
|
||||
|
||||
INPUT:
|
||||
:param fileName, path to the UBC obs mag file
|
||||
|
||||
OUTPUT:
|
||||
:param survey
|
||||
:param M, magnetization orentiaton (MI, MD)
|
||||
"""
|
||||
|
||||
fid = open(self.basePath + obs_file,'r')
|
||||
|
||||
# First line has the inclination,declination and amplitude of B0
|
||||
line = fid.readline()
|
||||
B = np.array(line.split(),dtype=float)
|
||||
|
||||
# Second line has the magnetization orientation and a flag
|
||||
line = fid.readline()
|
||||
M = np.array(line.split(),dtype=float)
|
||||
|
||||
# Third line has the number of rows
|
||||
line = fid.readline()
|
||||
ndat = np.array(line.split(),dtype=int)
|
||||
|
||||
# Pre-allocate space for obsx, obsy, obsz, data, uncert
|
||||
line = fid.readline()
|
||||
temp = np.array(line.split(),dtype=float)
|
||||
|
||||
d = np.zeros(ndat, dtype=float)
|
||||
wd = np.zeros(ndat, dtype=float)
|
||||
locXYZ = np.zeros( (ndat,3), dtype=float)
|
||||
|
||||
for ii in range(ndat):
|
||||
|
||||
temp = np.array(line.split(),dtype=float)
|
||||
locXYZ[ii,:] = temp[:3]
|
||||
|
||||
if len(temp) > 3:
|
||||
d[ii] = temp[3]
|
||||
|
||||
if len(temp)==5:
|
||||
wd[ii] = temp[4]
|
||||
|
||||
line = fid.readline()
|
||||
|
||||
rxLoc = BaseMag.RxObs(locXYZ)
|
||||
srcField = BaseMag.SrcField([rxLoc],param=(B[2],B[0],B[1]))
|
||||
survey = BaseMag.LinearSurvey(srcField)
|
||||
survey.dobs = d
|
||||
survey.std = wd
|
||||
return survey
|
||||
@@ -1,7 +0,0 @@
|
||||
import MagAnalytics
|
||||
import BaseMag
|
||||
import Magnetics
|
||||
import BaseGrav
|
||||
import Gravity
|
||||
import MagneticsDriver
|
||||
import GravityDriver
|
||||
+1
-1
@@ -187,7 +187,7 @@ class _PropMapMetaClass(type):
|
||||
attrs[attr + 'Model'] = prop._getModelProperty()
|
||||
attrs[attr + 'Deriv'] = prop._getModelDerivProperty()
|
||||
|
||||
return type('PropModel', (PropModel, ), attrs)
|
||||
return type(name.replace('PropMap', 'PropModel'), (PropModel, ), attrs)
|
||||
|
||||
|
||||
class PropMap(object):
|
||||
|
||||
+200
-450
@@ -1,6 +1,4 @@
|
||||
import Utils, Maps, Mesh
|
||||
import numpy as np
|
||||
import scipy.sparse as sp
|
||||
import Utils, Maps, Mesh, numpy as np, scipy.sparse as sp
|
||||
|
||||
class RegularizationMesh(object):
|
||||
"""
|
||||
@@ -10,7 +8,7 @@ class RegularizationMesh(object):
|
||||
are not necessarily true differential operators, but are constructed from
|
||||
a SimPEG Mesh.
|
||||
|
||||
:param BaseMesh mesh: problem mesh
|
||||
:param Mesh mesh: problem mesh
|
||||
:param numpy.array indActive: bool array, size nC, that is True where we have active cells. Used to reduce the operators so we regularize only on active cells
|
||||
"""
|
||||
|
||||
@@ -41,7 +39,7 @@ class RegularizationMesh(object):
|
||||
if self.indActive is None:
|
||||
self._nC = self.mesh.nC
|
||||
else:
|
||||
self._nC = sum(self.indActive)
|
||||
self._nC = int(sum(self.indActive))
|
||||
return self._nC
|
||||
|
||||
@property
|
||||
@@ -306,7 +304,7 @@ class BaseRegularization(object):
|
||||
mesh = None #: A SimPEG.Mesh instance.
|
||||
mref = None #: Reference model.
|
||||
|
||||
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
|
||||
def __init__(self, mesh=None, nP=None, mapping=None, indActive=None, **kwargs):
|
||||
Utils.setKwargs(self, **kwargs)
|
||||
assert isinstance(mesh, Mesh.BaseMesh), "mesh must be a SimPEG.Mesh object."
|
||||
if indActive is not None and indActive.dtype != 'bool':
|
||||
@@ -316,11 +314,19 @@ class BaseRegularization(object):
|
||||
if indActive is not None and mapping is None:
|
||||
mapping = Maps.IdentityMap(nP=indActive.nonzero()[0].size)
|
||||
|
||||
if mesh is None and nP is None:
|
||||
raise Exception, 'either Mesh or number of parameters must be provided to the BaseRegularization'
|
||||
|
||||
self.regmesh = RegularizationMesh(mesh,indActive)
|
||||
self.mapping = mapping or self.mapPair(mesh)
|
||||
self.mapping._assertMatchesPair(self.mapPair)
|
||||
self.indActive = indActive
|
||||
|
||||
if mesh is not None and nP is None:
|
||||
nP = self.regmesh.nC
|
||||
self.nP = nP
|
||||
|
||||
self.mapping = mapping or self.mapPair(nP=self.nP)
|
||||
self.mapping._assertMatchesPair(self.mapPair)
|
||||
|
||||
@property
|
||||
def parent(self):
|
||||
"""This is the parent of the regularization."""
|
||||
@@ -348,7 +354,7 @@ class BaseRegularization(object):
|
||||
@property
|
||||
def W(self):
|
||||
"""Full regularization weighting matrix W."""
|
||||
return sp.identity(self.regmesh.nC)
|
||||
return sp.identity(self.nP)
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m):
|
||||
@@ -383,8 +389,8 @@ class BaseRegularization(object):
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array v: vector to multiply
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: WtW, or if v is supplied WtW*v (numpy.ndarray)
|
||||
:rtype: scipy.sparse.csr_matrix or numpy.ndarray
|
||||
:return: WtW or WtW*v
|
||||
|
||||
The regularization is:
|
||||
|
||||
@@ -405,238 +411,7 @@ class BaseRegularization(object):
|
||||
|
||||
return mD.T * ( self.W.T * ( self.W * ( mD * v) ) )
|
||||
|
||||
class Simple(BaseRegularization):
|
||||
"""
|
||||
Simple regularization that does not include length scales in the derivatives.
|
||||
"""
|
||||
|
||||
mrefInSmooth = False #: include mref in the smoothness?
|
||||
alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight")
|
||||
alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction")
|
||||
alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction")
|
||||
alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction")
|
||||
cell_weights = 1.
|
||||
|
||||
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
|
||||
BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
|
||||
|
||||
if isinstance(self.cell_weights,float):
|
||||
self.cell_weights = np.ones(self.regmesh.nC) * self.cell_weights
|
||||
|
||||
@property
|
||||
def Wsmall(self):
|
||||
"""Regularization matrix Wsmall"""
|
||||
if getattr(self,'_Wsmall', None) is None:
|
||||
self._Wsmall = Utils.sdiag((self.alpha_s*self.cell_weights)**0.5)
|
||||
return self._Wsmall
|
||||
|
||||
@property
|
||||
def Wx(self):
|
||||
"""Regularization matrix Wx"""
|
||||
if getattr(self, '_Wx', None) is None:
|
||||
self._Wx = Utils.sdiag((self.alpha_x * (self.regmesh.aveCC2Fx*self.cell_weights))**0.5)*self.regmesh.cellDiffxStencil
|
||||
return self._Wx
|
||||
|
||||
@property
|
||||
def Wy(self):
|
||||
"""Regularization matrix Wy"""
|
||||
if getattr(self, '_Wy', None) is None:
|
||||
self._Wy = Utils.sdiag((self.alpha_y * (self.regmesh.aveCC2Fy*self.cell_weights))**0.5)*self.regmesh.cellDiffyStencil
|
||||
return self._Wy
|
||||
|
||||
@property
|
||||
def Wz(self):
|
||||
"""Regularization matrix Wz"""
|
||||
if getattr(self, '_Wz', None) is None:
|
||||
self._Wz = Utils.sdiag((self.alpha_z * (self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.regmesh.cellDiffzStencil
|
||||
return self._Wz
|
||||
|
||||
# @property
|
||||
# def Wsmooth(self):
|
||||
# """Full smoothness regularization matrix W"""
|
||||
# print 'wtf why are we using Wsmooth'
|
||||
# raise NotImplementedError
|
||||
# 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"""
|
||||
# print 'wtf why are we using W'
|
||||
# if getattr(self, '_W', None) is None:
|
||||
# wlist = (self.Wsmall, self.Wx)
|
||||
# if self.regmesh.dim > 1:
|
||||
# wlist += (self.Wy,)
|
||||
# if self.regmesh.dim > 2:
|
||||
# wlist += (self.Wz,)
|
||||
# self._W = sp.vstack(wlist)
|
||||
# return self._W
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmall(self, m):
|
||||
r = self.Wsmall * ( self.mapping * (m - self.mref) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmallDeriv(self, m):
|
||||
r = self.Wsmall * ( self.mapping * (m - self.mref) )
|
||||
return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) )
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmall2Deriv(self, m, v = None):
|
||||
rDeriv = self.Wsmall * ( self.mapping.deriv(m - self.mref) )
|
||||
if v is not None:
|
||||
return rDeriv.T * (rDeriv * v)
|
||||
return rDeriv.T * rDeriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothx(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wx * ( self.mapping * (m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wx * ( self.mapping * (m) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothy(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wy * ( self.mapping * (m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wy * ( self.mapping * (m) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothz(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wz * ( self.mapping * (m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wz * ( self.mapping * (m) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmooth(self, m):
|
||||
phiSmooth = self._evalSmoothx(m)
|
||||
if self.regmesh.dim > 1:
|
||||
phiSmooth += self._evalSmoothy(m)
|
||||
if self.regmesh.dim > 2:
|
||||
phiSmooth += self._evalSmoothz(m)
|
||||
return phiSmooth
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothxDeriv(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wx * ( self.mapping * ( m - self.mref ) )
|
||||
return r.T * ( self.Wx * self.mapping.deriv(m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wx * ( self.mapping * m )
|
||||
return r.T * ( self.Wx * self.mapping.deriv(m) )
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothx2Deriv(self, m, v=None):
|
||||
if self.mrefInSmooth == True:
|
||||
rDeriv = self.Wx * ( self.mapping.deriv( m - self.mref ) )
|
||||
elif self.mrefInSmooth == False:
|
||||
rDeriv = self.Wx * ( self.mapping.deriv(m) )
|
||||
|
||||
if v is not None:
|
||||
return rDeriv.T * ( rDeriv * v )
|
||||
return rDeriv.T * rDeriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothyDeriv(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wy * ( self.mapping * ( m - self.mref ) )
|
||||
return r.T * ( self.Wy * self.mapping.deriv(m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wy * ( self.mapping * m )
|
||||
return r.T * ( self.Wy * self.mapping.deriv(m) )
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothy2Deriv(self, m, v=None):
|
||||
if self.mrefInSmooth == True:
|
||||
rDeriv = self.Wy * ( self.mapping.deriv( m - self.mref ) )
|
||||
elif self.mrefInSmooth == False:
|
||||
rDeriv = self.Wy * ( self.mapping.deriv(m) )
|
||||
|
||||
if v is not None:
|
||||
return rDeriv.T * ( rDeriv * v )
|
||||
return rDeriv.T * rDeriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothzDeriv(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wz * ( self.mapping * ( m - self.mref ) )
|
||||
return r.T * ( self.Wz * self.mapping.deriv(m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wz * ( self.mapping * m )
|
||||
return r.T * ( self.Wz * self.mapping.deriv(m) )
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothz2Deriv(self, m, v=None):
|
||||
if self.mrefInSmooth == True:
|
||||
rDeriv = self.Wz * ( self.mapping.deriv( m - self.mref ) )
|
||||
elif self.mrefInSmooth == False:
|
||||
rDeriv = self.Wz * ( self.mapping.deriv(m) )
|
||||
|
||||
if v is not None:
|
||||
return rDeriv.T * ( rDeriv * v )
|
||||
return rDeriv.T * rDeriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothDeriv(self, m):
|
||||
deriv = self._evalSmoothxDeriv(m)
|
||||
if self.regmesh.dim > 1:
|
||||
deriv += self._evalSmoothyDeriv(m)
|
||||
if self.regmesh.dim > 2:
|
||||
deriv += self._evalSmoothzDeriv(m)
|
||||
return deriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmooth2Deriv(self, m, v=None):
|
||||
deriv = self._evalSmoothx2Deriv(m, v)
|
||||
if self.regmesh.dim > 1:
|
||||
deriv += self._evalSmoothy2Deriv(m, v)
|
||||
if self.regmesh.dim > 2:
|
||||
deriv += self._evalSmoothz2Deriv(m, v)
|
||||
return deriv
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m):
|
||||
return self._evalSmall(m) + self._evalSmooth(m)
|
||||
|
||||
@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})}
|
||||
|
||||
"""
|
||||
return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m)
|
||||
|
||||
@Utils.timeIt
|
||||
def eval2Deriv(self, m, v=None):
|
||||
return self._evalSmall2Deriv(m, v) + self._evalSmooth2Deriv(m, v)
|
||||
|
||||
|
||||
|
||||
class Tikhonov(Simple):
|
||||
class Tikhonov(BaseRegularization):
|
||||
"""
|
||||
L2 Tikhonov regularization with both smallness and smoothness (first order
|
||||
derivative) contributions.
|
||||
@@ -650,8 +425,8 @@ class Tikhonov(Simple):
|
||||
Note if the key word argument `mrefInSmooth` is False, then mref is not
|
||||
included in the smoothness contribution.
|
||||
|
||||
:param BaseMesh mesh: SimPEG mesh
|
||||
:param IdentityMap mapping: regularization mapping, takes the model from model space to the thing you want to regularize
|
||||
:param Mesh mesh: SimPEG mesh
|
||||
:param Maps mapping: regularization mapping, takes the model from model space to the thing you want to regularize
|
||||
:param numpy.ndarray indActive: active cell indices for reducing the size of differential operators in the definition of a regularization mesh
|
||||
:param bool mrefInSmooth: (default = False) put mref in the smoothness component?
|
||||
:param float alpha_s: (default 1e-6) smallness weight
|
||||
@@ -671,7 +446,7 @@ class Tikhonov(Simple):
|
||||
alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction")
|
||||
alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction")
|
||||
|
||||
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
|
||||
def __init__(self, mesh, mapping=None, indActive = None, **kwargs):
|
||||
BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
|
||||
|
||||
@property
|
||||
@@ -726,131 +501,56 @@ class Tikhonov(Simple):
|
||||
self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDiffz*self.regmesh.cellDiffz
|
||||
return self._Wzz
|
||||
|
||||
|
||||
@property
|
||||
def Wsmooth2(self):
|
||||
def Wsmooth(self):
|
||||
"""Full smoothness regularization matrix W"""
|
||||
if getattr(self, '_Wsmooth', None) is None:
|
||||
wlist = (self.Wxx)
|
||||
wlist = (self.Wx, self.Wxx)
|
||||
if self.regmesh.dim > 1:
|
||||
wlist += (self.Wyy)
|
||||
wlist += (self.Wy, self.Wyy)
|
||||
if self.regmesh.dim > 2:
|
||||
wlist += (self.Wzz)
|
||||
wlist += (self.Wz, self.Wzz)
|
||||
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 _evalSmoothxx(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wxx * ( self.mapping * (m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wxx * ( self.mapping * (m) )
|
||||
def _evalSmall(self, m):
|
||||
r = self.Wsmall * ( self.mapping * (m - self.mref) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothyy(self, m):
|
||||
def _evalSmooth(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wyy * ( self.mapping * (m - self.mref) )
|
||||
r = self.Wsmooth * ( self.mapping * (m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wyy * ( self.mapping * (m) )
|
||||
r = self.Wsmooth * ( self.mapping * (m) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothzz(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wzz * ( self.mapping * (m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wzz * ( self.mapping * (m) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmooth2(self, m):
|
||||
phiSmooth2 = self._evalSmoothxx(m)
|
||||
if self.regmesh.dim > 1:
|
||||
phiSmooth2 += self._evalSmoothyy(m)
|
||||
if self.regmesh.dim > 2:
|
||||
phiSmooth2 += self._evalSmoothzz(m)
|
||||
return phiSmooth2
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothxxDeriv(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wxx * ( self.mapping * ( m - self.mref ) )
|
||||
return r.T * ( self.Wxx * self.mapping.deriv(m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wxx * ( self.mapping * m )
|
||||
return r.T * ( self.Wxx * self.mapping.deriv(m) )
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothyyDeriv(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wyy * ( self.mapping * ( m - self.mref ) )
|
||||
return r.T * ( self.Wyy * self.mapping.deriv(m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wyy * ( self.mapping * m )
|
||||
return r.T * ( self.Wyy * self.mapping.deriv(m) )
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothzzDeriv(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wzz * ( self.mapping * ( m - self.mref ) )
|
||||
return r.T * ( self.Wzz * self.mapping.deriv(m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wzz * ( self.mapping * m )
|
||||
return r.T * ( self.Wzz * self.mapping.deriv(m) )
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothxx2Deriv(self, m, v=None):
|
||||
if self.mrefInSmooth == True:
|
||||
rDeriv = self.Wxx * ( self.mapping.deriv( m - self.mref ) )
|
||||
elif self.mrefInSmooth == False:
|
||||
rDeriv = self.Wxx * self.mapping.deriv(m)
|
||||
if v is not None:
|
||||
return rDeriv.T * (rDeriv * v)
|
||||
return rDeriv.T * rDeriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothyy2Deriv(self, m, v=None):
|
||||
if self.mrefInSmooth == True:
|
||||
rDeriv = self.Wyy * ( self.mapping.deriv( m - self.mref ) )
|
||||
elif self.mrefInSmooth == False:
|
||||
rDeriv = self.Wyy * self.mapping.deriv(m)
|
||||
if v is not None:
|
||||
return rDeriv.T * (rDeriv * v)
|
||||
return rDeriv.T * rDeriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothzz2Deriv(self, m, v=None):
|
||||
if self.mrefInSmooth == True:
|
||||
rDeriv = self.Wzz * ( self.mapping.deriv( m - self.mref ) )
|
||||
elif self.mrefInSmooth == False:
|
||||
rDeriv = self.Wzz * self.mapping.deriv(m)
|
||||
if v is not None:
|
||||
return rDeriv.T * (rDeriv * v)
|
||||
return rDeriv.T * rDeriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothDeriv2(self, m):
|
||||
deriv = self._evalSmoothxxDeriv(m)
|
||||
if self.regmesh.dim > 1:
|
||||
deriv += self._evalSmoothyyDeriv(m)
|
||||
if self.regmesh.dim > 2:
|
||||
deriv += self._evalSmoothzzDeriv(m)
|
||||
return deriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmooth2Deriv2(self, m, v=None):
|
||||
deriv = self._evalSmoothxx2Deriv(m, v)
|
||||
if self.regmesh.dim > 1:
|
||||
deriv += self._evalSmoothyy2Deriv(m, v)
|
||||
if self.regmesh.dim > 2:
|
||||
deriv += self._evalSmoothzz2Deriv(m, v)
|
||||
return deriv
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m):
|
||||
return self._evalSmall(m) + self._evalSmooth(m) + self._evalSmooth2(m)
|
||||
return self._evalSmall(m) + self._evalSmooth(m)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmallDeriv(self,m):
|
||||
r = self.Wsmall * ( self.mapping * (m - self.mref) )
|
||||
return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) )
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmoothDeriv(self,m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wsmooth * ( self.mapping * ( m - self.mref ) )
|
||||
return r.T * ( self.Wsmooth * self.mapping.deriv(m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wsmooth * ( self.mapping * m )
|
||||
return r.T * ( self.Wsmooth * self.mapping.deriv(m) )
|
||||
|
||||
@Utils.timeIt
|
||||
def evalDeriv(self, m):
|
||||
@@ -868,134 +568,184 @@ class Tikhonov(Simple):
|
||||
R(m) = \mathbf{W^\\top W (m-m_\\text{ref})}
|
||||
|
||||
"""
|
||||
return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + self._evalSmoothDeriv2(m)
|
||||
|
||||
def eval2Deriv(self, m, v=None):
|
||||
"""
|
||||
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})}
|
||||
|
||||
"""
|
||||
return self._evalSmall2Deriv(m, v) + self._evalSmooth2Deriv(m, v) + self._evalSmooth2Deriv2(m, v)
|
||||
return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m)
|
||||
|
||||
|
||||
|
||||
class Sparse(Simple):
|
||||
class Simple(Tikhonov):
|
||||
"""
|
||||
The regularization is:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top R^\\top R W(m-m_\\text{ref})}
|
||||
|
||||
where the IRLS weight
|
||||
|
||||
.. math::
|
||||
|
||||
R = \eta TO FINISH LATER!!!
|
||||
|
||||
So the derivative is straight forward:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \mathbf{W^\\top R^\\top R W (m-m_\\text{ref})}
|
||||
|
||||
The IRLS weights are recomputed after each beta solves.
|
||||
It is strongly recommended to do a few Gauss-Newton iterations
|
||||
before updating.
|
||||
Simple regularization that does not include length scales in the derivatives.
|
||||
"""
|
||||
|
||||
# set default values
|
||||
eps_p = 1e-1 # Threshold value for the model norm
|
||||
eps_q = 1e-1 # Threshold value for the model gradient norm
|
||||
curModel = None # Requires model to compute the weights
|
||||
l2model = None
|
||||
gamma = 1. # Model norm scaling to smooth out convergence
|
||||
norms = [0., 2., 2., 2.] # Values for norm on (m, dmdx, dmdy, dmdz)
|
||||
cell_weights = 1. # Consider overwriting with sensitivity weights
|
||||
|
||||
mrefInSmooth = False #: SMOOTH and SMOOTH_MOD_DIF options
|
||||
alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight")
|
||||
alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction")
|
||||
alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction")
|
||||
alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction")
|
||||
wght = 1.
|
||||
|
||||
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
|
||||
Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
|
||||
BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
|
||||
|
||||
if isinstance(self.cell_weights,float):
|
||||
self.cell_weights = np.ones(self.regmesh.nC) * self.cell_weights
|
||||
if isinstance(self.wght,float):
|
||||
self.wght = np.ones(self.regmesh.nC) * self.wght
|
||||
|
||||
@property
|
||||
def Wsmall(self):
|
||||
"""Regularization matrix Wsmall"""
|
||||
if getattr(self,'_Wsmall', None) is None:
|
||||
if getattr(self, 'curModel', None) is None:
|
||||
self.Rs = Utils.speye(self.regmesh.nC)
|
||||
|
||||
else:
|
||||
f_m = self.mapping * (self.curModel - self.reg.mref)
|
||||
self.rs = self.R(f_m , self.eps_p, self.norms[0])
|
||||
self.Rs = Utils.sdiag( self.rs )
|
||||
|
||||
self._Wsmall = Utils.sdiag((self.alpha_s*self.gamma*self.cell_weights)**0.5)*self.Rs
|
||||
|
||||
self._Wsmall = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5)
|
||||
return self._Wsmall
|
||||
|
||||
@property
|
||||
def Wx(self):
|
||||
"""Regularization matrix Wx"""
|
||||
if getattr(self,'_Wx', None) is None:
|
||||
if getattr(self, 'curModel', None) is None:
|
||||
self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0])
|
||||
|
||||
else:
|
||||
f_m = self.regmesh.cellDiffxStencil * (self.mapping * self.curModel)
|
||||
self.rx = self.R( f_m , self.eps_q, self.norms[1])
|
||||
self.Rx = Utils.sdiag( self.rx )
|
||||
|
||||
self._Wx = Utils.sdiag(( self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.cell_weights))**0.5)*self.Rx*self.regmesh.cellDiffxStencil
|
||||
|
||||
if getattr(self, '_Wx', None) is None:
|
||||
self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.regmesh.cellDiffxStencil
|
||||
return self._Wx
|
||||
|
||||
@property
|
||||
def Wy(self):
|
||||
"""Regularization matrix Wy"""
|
||||
if getattr(self,'_Wy', None) is None:
|
||||
if getattr(self, 'curModel', None) is None:
|
||||
self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0])
|
||||
|
||||
else:
|
||||
f_m = self.regmesh.cellDiffyStencil * (self.mapping * self.curModel)
|
||||
self.ry = self.R( f_m , self.eps_q, self.norms[2])
|
||||
self.Ry = Utils.sdiag( self.ry )
|
||||
|
||||
self._Wy = Utils.sdiag((self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.cell_weights))**0.5)*self.Ry*self.regmesh.cellDiffyStencil
|
||||
|
||||
if getattr(self, '_Wy', None) is None:
|
||||
self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.regmesh.cellDiffyStencil
|
||||
return self._Wy
|
||||
|
||||
@property
|
||||
def Wz(self):
|
||||
"""Regularization matrix Wz"""
|
||||
if getattr(self,'_Wz', None) is None:
|
||||
if getattr(self, 'curModel', None) is None:
|
||||
self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0])
|
||||
|
||||
else:
|
||||
f_m = self.regmesh.cellDiffzStencil * (self.mapping * self.curModel)
|
||||
self.rz = self.R( f_m , self.eps_q, self.norms[3])
|
||||
self.Rz = Utils.sdiag( self.rz )
|
||||
|
||||
self._Wz = Utils.sdiag((self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.Rz*self.regmesh.cellDiffzStencil
|
||||
|
||||
if getattr(self, '_Wz', None) is None:
|
||||
self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil
|
||||
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 _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)
|
||||
|
||||
|
||||
class Sparse(Simple):
|
||||
|
||||
# set default values
|
||||
eps_p = 1e-1
|
||||
eps_q = 1e-1
|
||||
curModel = None # use a model to compute the weights
|
||||
gamma = 1.
|
||||
norms = [0., 2., 2., 2.]
|
||||
wght = 1.
|
||||
|
||||
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
|
||||
Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
|
||||
|
||||
if isinstance(self.wght,float):
|
||||
self.wght = np.ones(self.regmesh.nC) * self.wght
|
||||
|
||||
@property
|
||||
def Wsmall(self):
|
||||
"""Regularization matrix Wsmall"""
|
||||
if getattr(self, 'curModel', None) is None:
|
||||
self.Rs = Utils.speye(self.regmesh.nC)
|
||||
|
||||
else:
|
||||
f_m = self.curModel - self.reg.mref
|
||||
self.rs = self.R(f_m , self.eps_p, self.norms[0])
|
||||
#print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs))
|
||||
self.Rs = Utils.sdiag( self.rs )
|
||||
|
||||
return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.wght)**0.5)*self.Rs
|
||||
|
||||
|
||||
@property
|
||||
def Wx(self):
|
||||
"""Regularization matrix Wx"""
|
||||
|
||||
if getattr(self, 'curModel', None) is None:
|
||||
self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0])
|
||||
|
||||
else:
|
||||
f_m = self.regmesh.cellDiffxStencil * self.curModel
|
||||
self.rx = self.R( f_m , self.eps_q, self.norms[1])
|
||||
self.Rx = Utils.sdiag( self.rx )
|
||||
|
||||
return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.Rx*self.regmesh.cellDiffxStencil
|
||||
|
||||
@property
|
||||
def Wy(self):
|
||||
"""Regularization matrix Wy"""
|
||||
|
||||
if getattr(self, 'curModel', None) is None:
|
||||
self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0])
|
||||
|
||||
else:
|
||||
f_m = self.regmesh.cellDiffyStencil * self.curModel
|
||||
self.ry = self.R( f_m , self.eps_q, self.norms[2])
|
||||
self.Ry = Utils.sdiag( self.ry )
|
||||
|
||||
return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil
|
||||
|
||||
@property
|
||||
def Wz(self):
|
||||
"""Regularization matrix Wz"""
|
||||
|
||||
if getattr(self, 'curModel', None) is None:
|
||||
self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0])
|
||||
|
||||
else:
|
||||
f_m = self.regmesh.cellDiffzStencil * self.curModel
|
||||
self.rz = self.R( f_m , self.eps_q, self.norms[3])
|
||||
self.Rz = Utils.sdiag( self.rz )
|
||||
|
||||
return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.Rz*self.regmesh.cellDiffzStencil
|
||||
|
||||
@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 sp.vstack(wlist)
|
||||
|
||||
@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
|
||||
|
||||
def R(self, f_m , eps, exponent):
|
||||
|
||||
# Eta scaling is important for mix-norms...do not mess with it
|
||||
eta = (eps**(1.-exponent/2.))**0.5
|
||||
r = eta / (f_m**2.+ eps**2.)**((1.-exponent/2.)/2.)
|
||||
|
||||
|
||||
+3
-2
@@ -311,6 +311,7 @@ class BaseSurvey(object):
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(f))
|
||||
|
||||
|
||||
@Utils.count
|
||||
def eval(self, f):
|
||||
"""eval(f)
|
||||
@@ -321,7 +322,7 @@ class BaseSurvey(object):
|
||||
|
||||
d_\\text{pred} = \mathbf{P} f(m)
|
||||
"""
|
||||
raise NotImplementedError('eval is not yet implemented.')
|
||||
raise NotImplemented('eval is not yet implemented.')
|
||||
|
||||
@Utils.count
|
||||
def evalDeriv(self, f):
|
||||
@@ -333,7 +334,7 @@ class BaseSurvey(object):
|
||||
|
||||
\\frac{\partial d_\\text{pred}}{\partial u} = \mathbf{P}
|
||||
"""
|
||||
raise NotImplementedError('eval is not yet implemented.')
|
||||
raise NotImplemented('eval is not yet implemented.')
|
||||
|
||||
@Utils.count
|
||||
def residual(self, m, f=None):
|
||||
|
||||
+1
-1
@@ -237,7 +237,7 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole
|
||||
Compares error decay of 0th and 1st order Taylor approximation at point
|
||||
x0 for a randomized search direction.
|
||||
|
||||
:param callable fctn: function handle
|
||||
:param lambda fctn: function handle
|
||||
:param numpy.array x0: point at which to check derivative
|
||||
:param int num: number of times to reduce step length, h
|
||||
:param bool plotIt: if you would like to plot
|
||||
|
||||
@@ -7,11 +7,11 @@ def addBlock(gridCC, modelCC, p0, p1, blockProp):
|
||||
"""
|
||||
Add a block to an exsisting cell centered model, modelCC
|
||||
|
||||
:param numpy.array gridCC: mesh.gridCC is the cell centered grid
|
||||
:param numpy.array modelCC: cell centered model
|
||||
:param numpy.array p0: bottom, southwest corner of block
|
||||
:param numpy.array p1: top, northeast corner of block
|
||||
:blockProp float blockProp: property to assign to the model
|
||||
:param numpy.array, gridCC: mesh.gridCC is the cell centered grid
|
||||
:param numpy.array, modelCC: cell centered model
|
||||
:param numpy.array, p0: bottom, southwest corner of block
|
||||
:param numpy.array, p1: top, northeast corner of block
|
||||
:blockProp float, blockProp: property to assign to the model
|
||||
|
||||
:return numpy.array, modelBlock: model with block
|
||||
"""
|
||||
@@ -147,7 +147,7 @@ def getIndicesSphere(center,radius,ccMesh):
|
||||
|
||||
if dimMesh == 1:
|
||||
# Define the reference points
|
||||
|
||||
|
||||
ind = np.abs(center[0] - ccMesh[:,0]) < radius
|
||||
|
||||
elif dimMesh == 2:
|
||||
@@ -222,14 +222,14 @@ def layeredModel(ccMesh, layerTops, layerValues):
|
||||
|
||||
:param numpy.array ccMesh: cell-centered mesh
|
||||
:param numpy.array layerTops: z-locations of the tops of each layer
|
||||
:param numpy.array layerValue: values of the property to assign for each layer (starting at the top)
|
||||
:param numpy.array layerValue: values of the property to assign for each layer (starting at the top)
|
||||
:rtype: numpy.array
|
||||
:return: M, layered model on the mesh
|
||||
:return: M, layered model on the mesh
|
||||
"""
|
||||
|
||||
descending = np.linalg.norm(sorted(layerTops, reverse=True) - layerTops) < 1e-20
|
||||
|
||||
# TODO: put an error check to make sure that there is an ordering... needs to work with inf elts
|
||||
# TODO: put an error check to make sure that there is an ordering... needs to work with inf elts
|
||||
# assert ascending or descending, "Layers must be listed in either ascending or descending order"
|
||||
|
||||
# start from bottom up
|
||||
@@ -253,10 +253,10 @@ def layeredModel(ccMesh, layerTops, layerValues):
|
||||
model = np.zeros(ccMesh.shape[0])
|
||||
|
||||
for i, top in enumerate(layerTops):
|
||||
zind = z <= top
|
||||
zind = z <= top
|
||||
model[zind] = layerValues[i]
|
||||
|
||||
return model
|
||||
return model
|
||||
|
||||
|
||||
|
||||
@@ -265,9 +265,9 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=None):
|
||||
Create a random model by convolving a kernel with a
|
||||
uniformly distributed model.
|
||||
|
||||
:param tuple shape: shape of the model.
|
||||
:param int,tuple shape: shape of the model.
|
||||
:param int seed: pick which model to produce, prints the seed if you don't choose.
|
||||
:param numpy.ndarray anisotropy: this is the (3 x n) blurring kernel that is used.
|
||||
:param numpy.ndarray,list anisotropy: this is the (3 x n) blurring kernel that is used.
|
||||
:param int its: number of smoothing iterations
|
||||
:param list bounds: bounds on the model, len(list) == 2
|
||||
:rtype: numpy.ndarray
|
||||
|
||||
@@ -13,7 +13,7 @@ def _checkAccuracy(A, b, X, accuracyTol):
|
||||
warnings.warn(msg, RuntimeWarning)
|
||||
|
||||
|
||||
def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6, name=None):
|
||||
def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6):
|
||||
"""
|
||||
Wraps a direct Solver.
|
||||
|
||||
@@ -72,11 +72,11 @@ def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6, name=
|
||||
if factorize and hasattr(self.solver, 'clean'):
|
||||
return self.solver.clean()
|
||||
|
||||
return type(name if name is not None else fun.__name__, (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__})
|
||||
return type(fun.__name__+'_Wrapped', (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__})
|
||||
|
||||
|
||||
|
||||
def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5, name=None):
|
||||
def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5):
|
||||
"""
|
||||
Wraps an iterative Solver.
|
||||
|
||||
@@ -128,13 +128,13 @@ def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5, name=None):
|
||||
def clean(self):
|
||||
pass
|
||||
|
||||
return type(name if name is not None else fun.__name__, (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__})
|
||||
return type(fun.__name__+'_Wrapped', (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__})
|
||||
|
||||
|
||||
from scipy.sparse import linalg
|
||||
Solver = SolverWrapD(linalg.spsolve, factorize=False, name="Solver")
|
||||
SolverLU = SolverWrapD(linalg.splu, factorize=True, name="SolverLU")
|
||||
SolverCG = SolverWrapI(linalg.cg, name="SolverCG")
|
||||
Solver = SolverWrapD(linalg.spsolve, factorize=False)
|
||||
SolverLU = SolverWrapD(linalg.splu, factorize=True)
|
||||
SolverCG = SolverWrapI(linalg.cg)
|
||||
|
||||
|
||||
class SolverDiag(object):
|
||||
|
||||
@@ -25,7 +25,7 @@ def interpmat(locs, x, y=None, z=None):
|
||||
:param numpy.ndarray x: Tensor vector of 1st dimension of grid.
|
||||
:param numpy.ndarray y: Tensor vector of 2nd dimension of grid. None by default.
|
||||
:param numpy.ndarray z: Tensor vector of 3rd dimension of grid. None by default.
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:rtype: scipy.sparse.csr.csr_matrix
|
||||
:return: Interpolation matrix
|
||||
|
||||
.. plot::
|
||||
|
||||
@@ -27,7 +27,7 @@ def mkvc(x, numDims=1):
|
||||
|
||||
if isinstance(x, Zero):
|
||||
return x
|
||||
|
||||
|
||||
assert isinstance(x, np.ndarray), "Vector must be a numpy array"
|
||||
|
||||
if numDims == 1:
|
||||
@@ -355,9 +355,9 @@ def diagEst(matFun, n, k=None, approach='Probing'):
|
||||
2. Ones : random +/- 1 entries
|
||||
3. Random : random vectors
|
||||
|
||||
:param callable matFun: takes a (numpy.array) and multiplies it by a matrix to estimate the diagonal
|
||||
:param int n: size of the vector that should be used to compute matFun(v)
|
||||
:param int k: number of vectors to be used to estimate the diagonal
|
||||
:param lambda (numpy.array) matFun: matrix to estimate the diagonal of
|
||||
:param int64 n: size of the vector that should be used to compute matFun(v)
|
||||
:param int64 k: number of vectors to be used to estimate the diagonal
|
||||
:param str approach: approach to be used for getting vectors
|
||||
:rtype: numpy.array
|
||||
:return: est_diag(A)
|
||||
@@ -422,9 +422,9 @@ class Zero(object):
|
||||
def __ge__(self, v):return 0 >= v
|
||||
def __gt__(self, v):return 0 > v
|
||||
|
||||
@property
|
||||
@property
|
||||
def transpose(self): return Zero()
|
||||
|
||||
|
||||
@property
|
||||
def T(self): return Zero()
|
||||
|
||||
|
||||
+14
-18
@@ -83,7 +83,7 @@ def closestPoints(mesh, pts, gridLoc='CC'):
|
||||
"""
|
||||
Move a list of points to the closest points on a grid.
|
||||
|
||||
:param BaseMesh mesh: The mesh
|
||||
:param simpeg.Mesh.BaseMesh mesh: The mesh
|
||||
:param numpy.ndarray pts: Points to move
|
||||
:param string gridLoc: ['CC', 'N', 'Fx', 'Fy', 'Fz', 'Ex', 'Ex', 'Ey', 'Ez']
|
||||
:rtype: numpy.ndarray
|
||||
@@ -104,20 +104,16 @@ def closestPoints(mesh, pts, gridLoc='CC'):
|
||||
|
||||
def ExtractCoreMesh(xyzlim, mesh, meshType='tensor'):
|
||||
"""
|
||||
Extracts Core Mesh from Global mesh
|
||||
|
||||
:param numpy.ndarray xyzlim: 2D array [ndim x 2]
|
||||
:param BaseMesh mesh: The mesh
|
||||
|
||||
This function ouputs::
|
||||
|
||||
- actind: corresponding boolean index from global to core
|
||||
- meshcore: core SimPEG mesh
|
||||
|
||||
Warning: 1D and 2D has not been tested
|
||||
Extracts Core Mesh from Global mesh
|
||||
xyzlim: 2D array [ndim x 2]
|
||||
mesh: SimPEG mesh
|
||||
This function ouputs:
|
||||
- actind: corresponding boolean index from global to core
|
||||
- meshcore: core SimPEG mesh
|
||||
Warning: 1D and 2D has not been tested
|
||||
"""
|
||||
from SimPEG import Mesh
|
||||
if mesh.dim == 1:
|
||||
if mesh.dim ==1:
|
||||
xyzlim = xyzlim.flatten()
|
||||
xmin, xmax = xyzlim[0], xyzlim[1]
|
||||
|
||||
@@ -129,11 +125,11 @@ def ExtractCoreMesh(xyzlim, mesh, meshType='tensor'):
|
||||
|
||||
x0 = [xc[0]-hx[0]*0.5, yc[0]-hy[0]*0.5]
|
||||
|
||||
meshCore = Mesh.TensorMesh([hx, hy], x0=x0)
|
||||
meshCore = Mesh.TensorMesh([hx, hy] ,x0=x0)
|
||||
|
||||
actind = (mesh.gridCC[:,0]>xmin) & (mesh.gridCC[:,0]<xmax)
|
||||
|
||||
elif mesh.dim == 2:
|
||||
elif mesh.dim ==2:
|
||||
xmin, xmax = xyzlim[0,0], xyzlim[0,1]
|
||||
ymin, ymax = xyzlim[1,0], xyzlim[1,1]
|
||||
|
||||
@@ -148,12 +144,12 @@ def ExtractCoreMesh(xyzlim, mesh, meshType='tensor'):
|
||||
|
||||
x0 = [xc[0]-hx[0]*0.5, yc[0]-hy[0]*0.5]
|
||||
|
||||
meshCore = Mesh.TensorMesh([hx, hy], x0=x0)
|
||||
meshCore = Mesh.TensorMesh([hx, hy] ,x0=x0)
|
||||
|
||||
actind = (mesh.gridCC[:,0]>xmin) & (mesh.gridCC[:,0]<xmax) \
|
||||
& (mesh.gridCC[:,1]>ymin) & (mesh.gridCC[:,1]<ymax) \
|
||||
|
||||
elif mesh.dim == 3:
|
||||
elif mesh.dim==3:
|
||||
xmin, xmax = xyzlim[0,0], xyzlim[0,1]
|
||||
ymin, ymax = xyzlim[1,0], xyzlim[1,1]
|
||||
zmin, zmax = xyzlim[2,0], xyzlim[2,1]
|
||||
@@ -172,7 +168,7 @@ def ExtractCoreMesh(xyzlim, mesh, meshType='tensor'):
|
||||
|
||||
x0 = [xc[0]-hx[0]*0.5, yc[0]-hy[0]*0.5, zc[0]-hz[0]*0.5]
|
||||
|
||||
meshCore = Mesh.TensorMesh([hx, hy, hz], x0=x0)
|
||||
meshCore = Mesh.TensorMesh([hx, hy, hz] ,x0=x0)
|
||||
|
||||
actind = (mesh.gridCC[:,0]>xmin) & (mesh.gridCC[:,0]<xmax) \
|
||||
& (mesh.gridCC[:,1]>ymin) & (mesh.gridCC[:,1]<ymax) \
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import Directives
|
||||
import Inversion
|
||||
import Tests
|
||||
|
||||
__version__ = '0.1.12'
|
||||
__version__ = '0.1.10'
|
||||
__author__ = 'Rowan Cockett'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright 2014 Rowan Cockett'
|
||||
|
||||
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
+1
-1
@@ -2,7 +2,7 @@
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS = -n -w warnings.txt
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Vendored
-22
@@ -1,22 +0,0 @@
|
||||
{# Import the theme's layout. #}
|
||||
{% extends "!layout.html" %}
|
||||
|
||||
{% block extrahead %}
|
||||
{{ super() }}
|
||||
|
||||
<meta name="description" content="Simulation and Parameter Estimation in Geophysics">
|
||||
<meta name="author" content="SimPEG Developers">
|
||||
<meta name="keywords" content="python, geophysics, inversion, electromagnetics, magnetotellurics, magnetics, gravity, DC, flow inverse problems, open source, finite volume">
|
||||
|
||||
|
||||
<script>
|
||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
|
||||
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
|
||||
|
||||
ga('create', 'UA-45185336-1', 'auto');
|
||||
ga('send', 'pageview');
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,3 +1,5 @@
|
||||
.. _api_DC:
|
||||
|
||||
.. math::
|
||||
|
||||
\renewcommand{\div}{\nabla\cdot\,}
|
||||
@@ -36,16 +38,8 @@
|
||||
\renewcommand {\u} { {\vec u} }
|
||||
\newcommand{\I}{\vec{I}}
|
||||
|
||||
|
||||
Direct Current Resistivity
|
||||
**************************
|
||||
|
||||
`SimPEG.DCIP` uses SimPEG as the framework for the forward and inverse
|
||||
direct current (DC) resistivity and induced polarization (IP) geophysical problems.
|
||||
|
||||
|
||||
DC resistivity survey
|
||||
=====================
|
||||
*********************
|
||||
|
||||
Electrical resistivity of subsurface materials is measured by causing an electrical current to flow in the earth between one pair of electrodes while the voltage across a second pair of electrodes is measured. The result is an "apparent" resistivity which is a value representing the weighted average resistivity over a volume of the earth. Variations in this measurement are caused by variations in the soil, rock, and pore fluid electrical resistivity. Surveys require contact with the ground, so they can be labour intensive. Results are sometimes interpreted directly, but more commonly, 1D, 2D or 3D models are estimated using inversion procedures (`GPG <http://www.eos.ubc.ca/courses/eosc350/content/>`_).
|
||||
|
||||
@@ -61,7 +55,7 @@ As direct current (DC) implies, in DC resistivity survey, we assume steady-state
|
||||
|
||||
\curl \e = 0
|
||||
|
||||
Then by taking \\(\\div\\) of the first equation, we have
|
||||
Then by taking \\(\\curl\\) for the first equation, we have
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -143,14 +137,13 @@ Comparing to the analytic function:
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.DC_Analytic_Dipole.run(plotIt=True)
|
||||
import simpegDC as DC
|
||||
DC.Examples.Verification.run(plotIt=True)
|
||||
|
||||
API
|
||||
===
|
||||
|
||||
API for DC codes
|
||||
================
|
||||
|
||||
.. automodule:: SimPEG.DCIP.BaseDC
|
||||
.. automodule:: simpegDC.BaseDC
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -7,7 +7,7 @@ Examples
|
||||
:maxdepth: 1
|
||||
:glob:
|
||||
|
||||
../examples/*
|
||||
examples/*
|
||||
|
||||
|
||||
External Notebooks
|
||||
@@ -0,0 +1,19 @@
|
||||
.. _api_FiniteVolume:
|
||||
|
||||
Finite Volume
|
||||
*************
|
||||
|
||||
Any numerical implementation requires the discretization of continuous functions into discrete approximations. These approximations are typically organized in a mesh, which defines boundaries, locations, and connectivity. Of specific interest to geophysical simulations, we require that averaging, interpolation and differential operators be defined for any mesh. In SimPEG, we have implemented a staggered mimetic finite volume approach (`Hyman and Shashkov, 1999 <http://math.lanl.gov/~mac/papers/numerics/HS99B.pdf>`_). This approach requires the definitions of variables at either cell-centers, nodes, faces, or edges as seen in the figure below.
|
||||
|
||||
.. image:: images/finitevolrealestate.png
|
||||
:width: 400 px
|
||||
:alt: FiniteVolume
|
||||
:align: center
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
api_Mesh
|
||||
api_DiffOps
|
||||
api_InnerProducts
|
||||
@@ -52,15 +52,13 @@ We can take the derivative of the PDE:
|
||||
|
||||
\nabla_m c(m, u) \partial m + \nabla_u c(m, u) \partial u = 0
|
||||
|
||||
If the forward problem is invertible, then we can rearrange for
|
||||
\\(\\frac{\\partial u}{\\partial m}\\):
|
||||
If the forward problem is invertible, then we can rearrange for \\(\\frac{\\partial u}{\\partial m}\\):
|
||||
|
||||
.. math::
|
||||
|
||||
J = - P \left( \nabla_u c(m, u) \right)^{-1} \nabla_m c(m, u)
|
||||
|
||||
This can often be computed given a vector (i.e. \\(J(v)\\)) rather than
|
||||
stored, as \\(J\\) is a large dense matrix.
|
||||
This can often be computed given a vector (i.e. \\(J(v)\\)) rather than stored, as \\(J\\) is a large dense matrix.
|
||||
|
||||
|
||||
|
||||
@@ -69,45 +67,13 @@ The API
|
||||
|
||||
Problem
|
||||
-------
|
||||
|
||||
.. autoclass:: SimPEG.Problem.BaseProblem
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Problem.BaseTimeProblem
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
Fields
|
||||
------
|
||||
|
||||
.. autoclass:: SimPEG.Fields.Fields
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Fields.TimeFields
|
||||
.. automodule:: SimPEG.Problem
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
Survey
|
||||
------
|
||||
|
||||
.. autoclass:: SimPEG.Survey.BaseSurvey
|
||||
.. automodule:: SimPEG.Survey
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Survey.BaseSrc
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Survey.BaseRx
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Survey.BaseTimeRx
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Survey.Data
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -4,10 +4,7 @@
|
||||
Inner Products
|
||||
**************
|
||||
|
||||
By using the weak formulation of many of the PDEs in geophysical applications,
|
||||
we can rapidly develop discretizations. Much of this work, however, needs a
|
||||
good understanding of how to approximate inner products on our discretized
|
||||
meshes. We will define the inner product as:
|
||||
By using the weak formulation of many of the PDEs in geophysical applications, we can rapidly develop discretizations. Much of this work, however, needs a good understanding of how to approximate inner products on our discretized meshes. We will define the inner product as:
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -17,15 +14,12 @@ where a and b are either scalars or vectors.
|
||||
|
||||
.. note::
|
||||
|
||||
The InnerProducts class is a base class providing inner product matrices
|
||||
for meshes and cannot run on its own.
|
||||
The InnerProducts class is a base class providing inner product matrices for meshes and cannot run on its own.
|
||||
|
||||
|
||||
Example problem for DC resistivity
|
||||
----------------------------------
|
||||
|
||||
We will start with the formulation of the Direct Current (DC) resistivity
|
||||
problem in geophysics.
|
||||
We will start with the formulation of the Direct Current (DC) resistivity problem in geophysics.
|
||||
|
||||
|
||||
.. math::
|
||||
@@ -34,13 +28,12 @@ problem in geophysics.
|
||||
|
||||
\nabla\cdot \vec{j} = q
|
||||
|
||||
In the following discretization, :math:`\sigma` and :math:`\phi`
|
||||
will be discretized on the cell-centers and the flux, :math:`\vec{j}`,
|
||||
In the following discretization, \\\( \\sigma \\\) and \\\( \\phi \\\)
|
||||
will be discretized on the cell-centers and the flux, \\\(\\vec{j}\\\),
|
||||
will be on the faces. We will use the weak formulation to discretize
|
||||
the DC resistivity equation.
|
||||
|
||||
We can define in weak form by integrating with a general face function
|
||||
:math:`\vec{f}`:
|
||||
We can define in weak form by integrating with a general face function \\\(\\vec{f}\\\):
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -68,16 +61,9 @@ We can then discretize for every cell:
|
||||
|
||||
.. note::
|
||||
|
||||
We have discretized the dot product above, but remember that we do not
|
||||
really have a single vector :math:`\mathbf{J}`, but approximations of
|
||||
:math:`\vec{j}` on each face of our cell. In 2D that means 2
|
||||
approximations of :math:`\mathbf{J}_x` and 2 approximations of
|
||||
:math:`\mathbf{J}_y`. In 3D we also have 2 approximations of
|
||||
:math:`\mathbf{J}_z`.
|
||||
We have discretized the dot product above, but remember that we do not really have a single vector \\\(\\mathbf{J}\\\), but approximations of \\\(\\vec{j}\\\) on each face of our cell. In 2D that means 2 approximations of \\\(\\mathbf{J}_x\\\) and 2 approximations of \\\(\\mathbf{J}_y\\\). In 3D we also have 2 approximations of \\\(\\mathbf{J}_z\\\).
|
||||
|
||||
Regardless of how we choose to approximate this dot product, we can represent
|
||||
this in vector form (again this is for every cell), and will generalize for
|
||||
the case of anisotropic (tensor) sigma.
|
||||
Regardless of how we choose to approximate this dot product, we can represent this in vector form (again this is for every cell), and will generalize for the case of anisotropic (tensor) sigma.
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -85,17 +71,14 @@ the case of anisotropic (tensor) sigma.
|
||||
-\phi^{\top} v_{\text{cell}} \mathbf{D}_{\text{cell}} \mathbf{F})
|
||||
+ \text{BC}
|
||||
|
||||
We multiply by square-root of volume on each side of the tensor conductivity
|
||||
to keep symmetry in the system. Here :math:`\mathbf{J}_c` is the Cartesian
|
||||
:math:`\mathbf{J}` (on the faces that we choose to use in our approximation)
|
||||
and must be calculated differently depending on the mesh:
|
||||
We multiply by square-root of volume on each side of the tensor conductivity to keep symmetry in the system. Here \\\(\\mathbf{J}_c\\\) is the Cartesian \\\(\\mathbf{J}\\\) (on the faces that we choose to use in our approximation) and must be calculated differently depending on the mesh:
|
||||
|
||||
.. math::
|
||||
\mathbf{J}_c = \mathbf{Q}_{(i)}\mathbf{J}_\text{TENSOR} \\
|
||||
\mathbf{J}_c = \mathbf{N}_{(i)}^{-1}\mathbf{Q}_{(i)}\mathbf{J}_\text{Curv}
|
||||
|
||||
Here the :math:`i` index refers to where we choose to approximate this integral, as discussed in the note above.
|
||||
We will approximate this integral by taking the fluxes clustered around every node of the cell, there are 8 combinations in 3D, and 4 in 2D. We will use a projection matrix :math:`\mathbf{Q}_{(i)}` to pick the appropriate fluxes. So, now that we have 8 approximations of this integral, we will just take the average. For the TensorMesh, this looks like:
|
||||
Here the \\\(i\\\) index refers to where we choose to approximate this integral, as discussed in the note above.
|
||||
We will approximate this integral by taking the fluxes clustered around every node of the cell, there are 8 combinations in 3D, and 4 in 2D. We will use a projection matrix \\\( \\mathbf{Q}_{(i)} \\\) to pick the appropriate fluxes. So, now that we have 8 approximations of this integral, we will just take the average. For the TensorMesh, this looks like:
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -124,12 +107,10 @@ By defining the faceInnerProduct (8 combinations of fluxes in 3D, 4 in 2D, 2 in
|
||||
\sum_{i=1}^{2^d}
|
||||
\mathbf{P}_{(i)}^{\top} \Sigma^{-1} \mathbf{P}_{(i)}
|
||||
|
||||
Where :math:`d` is the dimension of the mesh.
|
||||
The :math:`\mathbf{M}^f` is returned when given the input of :math:`\Sigma^{-1}`.
|
||||
Where \\\(d\\\) is the dimension of the mesh.
|
||||
The \\\( \\mathbf{M}^f \\\) is returned when given the input of \\\( \\Sigma^{-1} \\\).
|
||||
|
||||
Here each :math:`\mathbf{P} ~ \in ~ \mathbb{R}^{(d*nC, nF)}` is a combination
|
||||
of the projection, volume, and any normalization to Cartesian coordinates
|
||||
(where the dot product is well defined):
|
||||
Here each \\( \\mathbf{P} \\in \\mathbb{R}^{(d*nC, nF)} \\\) is a combination of the projection, volume, and any normalization to Cartesian coordinates (where the dot product is well defined):
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -148,10 +129,7 @@ If ``returnP=True`` is requested in any of these methods the projection matrices
|
||||
# In 1D
|
||||
P = [P0, P1]
|
||||
|
||||
The derivation for ``edgeInnerProducts`` is exactly the same, however, when we
|
||||
approximate the integral using the fields around each node, the projection
|
||||
matrices look a bit different because we have 12 edges in 3D instead of just 6
|
||||
faces. The interface to the code is exactly the same.
|
||||
The derivation for ``edgeInnerProducts`` is exactly the same, however, when we approximate the integral using the fields around each node, the projection matrices look a bit different because we have 12 edges in 3D instead of just 6 faces. The interface to the code is exactly the same.
|
||||
|
||||
|
||||
Defining Tensor Properties
|
||||
@@ -159,8 +137,7 @@ Defining Tensor Properties
|
||||
|
||||
**For 3D:**
|
||||
|
||||
Depending on the number of columns (either 1, 3, or 6) of mu, the material
|
||||
property is interpreted as follows:
|
||||
Depending on the number of columns (either 1, 3, or 6) of mu, the material property is interpreted as follows:
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -211,16 +188,13 @@ Which is nice and easy to invert if necessary, however, in the fully anisotropic
|
||||
Taking Derivatives
|
||||
------------------
|
||||
|
||||
We will take the derivative of the fully anisotropic tensor for a 3D mesh, the
|
||||
other cases are easier and will not be discussed here. Let us start with one
|
||||
part of the sum which makes up :math:`\mathbf{M}^f_\Sigma` and take the
|
||||
derivative when this is multiplied by some vector :math:`\mathbf{v}`:
|
||||
We will take the derivative of the fully anisotropic tensor for a 3D mesh, the other cases are easier and will not be discussed here. Let us start with one part of the sum which makes up \\\(\\mathbf{M}^f_\\Sigma\\\) and take the derivative when this is multiplied by some vector \\\(\\mathbf{v}\\\):
|
||||
|
||||
.. math::
|
||||
|
||||
\mathbf{P}^\top \boldsymbol{\Sigma} \mathbf{Pv}
|
||||
|
||||
Here we will let :math:`\mathbf{Pv} = \mathbf{y}` and :math:`\mathbf{y}` will have the form:
|
||||
Here we will let \\\( \\mathbf{Pv} = \\mathbf{y} \\\) and \\\(\\mathbf{y}\\\) will have the form:
|
||||
|
||||
.. math::
|
||||
|
||||
@@ -259,9 +233,7 @@ Here we will let :math:`\mathbf{Pv} = \mathbf{y}` and :math:`\mathbf{y}` will ha
|
||||
\end{matrix}
|
||||
\right]
|
||||
|
||||
Now it is easy to take the derivative with respect to any one of the
|
||||
parameters, for example,
|
||||
:math:`\frac{\partial}{\partial\boldsymbol{\sigma}_1}`
|
||||
Now it is easy to take the derivative with respect to any one of the parameters, for example, \\\(\\frac{\\partial}{\\partial\\boldsymbol{\\sigma}_1}\\\)
|
||||
|
||||
.. math::
|
||||
\frac{\partial}{\partial \boldsymbol{\sigma}_1}\left(\mathbf{P}^\top\Sigma\mathbf{y}\right)
|
||||
@@ -275,8 +247,7 @@ parameters, for example,
|
||||
\end{matrix}
|
||||
\right]
|
||||
|
||||
Whereas :math:`\frac{\partial}{\partial\boldsymbol{\sigma}_4}`, for
|
||||
example, is:
|
||||
Whereas \\\(\\frac{\\partial}{\\partial\\boldsymbol{\\sigma}_4}\\\), for example, is:
|
||||
|
||||
.. math::
|
||||
\frac{\partial}{\partial \boldsymbol{\sigma}_4}\left(\mathbf{P}^\top\Sigma\mathbf{y}\right)
|
||||
@@ -290,12 +261,11 @@ example, is:
|
||||
\end{matrix}
|
||||
\right]
|
||||
|
||||
These are computed for each of the 8 projections, horizontally concatenated,
|
||||
and returned.
|
||||
These are computed for each of the 8 projections, horizontally concatenated, and returned.
|
||||
|
||||
The API
|
||||
-------
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.InnerProducts.InnerProducts
|
||||
.. automodule:: SimPEG.Mesh.InnerProducts
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -3,7 +3,7 @@
|
||||
InvProblem
|
||||
**********
|
||||
|
||||
.. autoclass:: SimPEG.InvProblem.BaseInvProblem
|
||||
.. automodule:: SimPEG.InvProblem
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -12,7 +12,7 @@ InvProblem
|
||||
Inversion
|
||||
*********
|
||||
|
||||
.. autoclass:: SimPEG.Inversion.BaseInversion
|
||||
.. automodule:: SimPEG.Inversion
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -27,8 +27,7 @@ back to conductivity. This is a relatively trivial example (we are just taking
|
||||
the exponential!) but by defining maps we can start to combine and manipulate
|
||||
exactly what we think about as our model, \\\(m\\\). In code, this looks like
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
::
|
||||
|
||||
M = Mesh.TensorMesh([100]) # Create a mesh
|
||||
expMap = Maps.ExpMap(M) # Create a mapping
|
||||
@@ -47,15 +46,14 @@ We will use an example where we want a 1D layered earth as
|
||||
our model, but we want to map this to a 2D discretization to do our forward
|
||||
modeling. We will also assume that we are working in log conductivity still,
|
||||
so after the transformation we want to map to conductivity space.
|
||||
To do this we will introduce the vertical 1D map (:class:`SimPEG.Maps.SurjectVertical1D`),
|
||||
To do this we will introduce the vertical 1D map (:class:`SimPEG.Maps.Vertical1DMap`),
|
||||
which does the first part of what we just described. The second part will be
|
||||
done by the :class:`SimPEG.Maps.ExpMap` described above.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
::
|
||||
|
||||
M = Mesh.TensorMesh([7,5])
|
||||
v1dMap = Maps.SurjectVertical1D(M)
|
||||
v1dMap = Maps.Vertical1DMap(M)
|
||||
expMap = Maps.ExpMap(M)
|
||||
myMap = expMap * v1dMap
|
||||
m = np.r_[0.2,1,0.1,2,2.9] # only 5 model parameters!
|
||||
@@ -63,8 +61,26 @@ done by the :class:`SimPEG.Maps.ExpMap` described above.
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.Maps_ComboMaps.run()
|
||||
from SimPEG import *
|
||||
import matplotlib.pyplot as plt
|
||||
M = Mesh.TensorMesh([7,5])
|
||||
v1dMap = Maps.Vertical1DMap(M)
|
||||
expMap = Maps.ExpMap(M)
|
||||
myMap = expMap * v1dMap
|
||||
m = np.r_[0.2,1,0.1,2,2.9] # only 5 model parameters!
|
||||
sig = myMap * m
|
||||
figs, axs = plt.subplots(1,2)
|
||||
axs[0].plot(m, M.vectorCCy, 'b-o')
|
||||
axs[0].set_title('Model')
|
||||
axs[0].set_ylabel('Depth, y')
|
||||
axs[0].set_xlabel('Value, $m_i$')
|
||||
axs[0].set_xlim(0,3)
|
||||
axs[0].set_ylim(0,1)
|
||||
clbar = plt.colorbar(M.plotImage(sig,ax=axs[1],grid=True,gridOpts=dict(color='grey'))[0])
|
||||
axs[1].set_title('Physical Property')
|
||||
axs[1].set_ylabel('Depth, y')
|
||||
clbar.set_label('$\sigma = \exp(\mathbf{P}m)$')
|
||||
plt.tight_layout()
|
||||
|
||||
If you noticed, it was pretty easy to combine maps. What is even cooler is
|
||||
that the derivatives also are made for you (if everything goes right).
|
||||
@@ -106,72 +122,10 @@ When these are used in the inverse problem, this is extremely important!!
|
||||
The API
|
||||
=======
|
||||
|
||||
The :code:`IdentityMap` is the base class for all mappings, and it does absolutely nothing.
|
||||
|
||||
.. autoclass:: SimPEG.Maps.IdentityMap
|
||||
.. automodule:: SimPEG.Maps
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Common Maps
|
||||
===========
|
||||
|
||||
Exponential Map
|
||||
---------------
|
||||
|
||||
Electrical conductivity varies over many orders of magnitude, so it is a common
|
||||
technique when solving the inverse problem to parameterize and optimize in terms
|
||||
of log conductivity. This makes sense not only because it ensures all conductivities
|
||||
will be positive, but because this is fundamentally the space where conductivity
|
||||
lives (i.e. it varies logarithmically).
|
||||
|
||||
.. autoclass:: SimPEG.Maps.ExpMap
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Vertical 1D Map
|
||||
---------------
|
||||
|
||||
.. autoclass:: SimPEG.Maps.SurjectVertical1D
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Map 2D Cross-Section to 3D Model
|
||||
--------------------------------
|
||||
|
||||
.. autoclass:: SimPEG.Maps.Map2Dto3D
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Mesh to Mesh Map
|
||||
----------------
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.Maps_Mesh2Mesh.run()
|
||||
|
||||
|
||||
.. autoclass:: SimPEG.Maps.Mesh2Mesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Under the Hood
|
||||
==============
|
||||
|
||||
Combo Map
|
||||
---------
|
||||
|
||||
The ComboMap holds the information for multiplying and combining
|
||||
maps. It also uses the chain rule to create the derivative.
|
||||
Remember, any time that you make your own combination of mappings
|
||||
be sure to test that the derivative is correct.
|
||||
|
||||
.. autoclass:: SimPEG.Maps.ComboMap
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
@@ -188,6 +188,6 @@ other types of meshes in this SimPEG framework.
|
||||
The API
|
||||
=======
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.BaseMesh.BaseMesh
|
||||
.. automodule:: SimPEG.Mesh.BaseMesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -0,0 +1,36 @@
|
||||
.. _api_MeshCode:
|
||||
|
||||
Tensor Mesh
|
||||
===========
|
||||
|
||||
.. automodule:: SimPEG.Mesh.TensorMesh
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Cylindrical Mesh
|
||||
================
|
||||
|
||||
.. automodule:: SimPEG.Mesh.CylMesh
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Tree Mesh
|
||||
=========
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.TreeMesh.TreeMesh
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Curvilinear Mesh
|
||||
================
|
||||
|
||||
.. automodule:: SimPEG.Mesh.CurvilinearMesh
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -91,21 +91,10 @@ The API
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. autoclass:: SimPEG.Regularization.Simple
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
.. autoclass:: SimPEG.Regularization.Tikhonov
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
.. autoclass:: SimPEG.Regularization.Sparse
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
.. autoclass:: SimPEG.Regularization.RegularizationMesh
|
||||
:show-inheritance:
|
||||
:members:
|
||||
|
||||
|
||||
|
||||
@@ -46,8 +46,6 @@ The API
|
||||
=======
|
||||
|
||||
.. autofunction:: SimPEG.Utils.SolverUtils.SolverWrapD
|
||||
:noindex:
|
||||
|
||||
.. autofunction:: SimPEG.Utils.SolverUtils.SolverWrapI
|
||||
:noindex:
|
||||
|
||||
@@ -6,6 +6,5 @@ Utilities
|
||||
|
||||
api_Solver
|
||||
api_Maps
|
||||
api_PropMaps
|
||||
api_Utils
|
||||
api_Tests
|
||||
@@ -21,7 +21,7 @@ Solver Utilities
|
||||
:undoc-members:
|
||||
|
||||
Curv Utilities
|
||||
==============
|
||||
=============
|
||||
|
||||
.. automodule:: SimPEG.Utils.curvutils
|
||||
:members:
|
||||
@@ -51,9 +51,7 @@ Interpolation Utilities
|
||||
Counter Utilities
|
||||
=================
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
::
|
||||
class MyClass(object):
|
||||
def __init__(self, url):
|
||||
self.counter = Counter()
|
||||
@@ -71,9 +69,7 @@ Counter Utilities
|
||||
for i in range(300): c.MySecondMethod()
|
||||
c.counter.summary()
|
||||
|
||||
|
||||
.. code-block:: text
|
||||
:linenos:
|
||||
::
|
||||
|
||||
Counters:
|
||||
MyClass.MyMethod : 100
|
||||
@@ -81,8 +77,6 @@ Counter Utilities
|
||||
Times: mean sum
|
||||
MyClass.MySecondMethod : 1.70e-06, 5.10e-04, 300x
|
||||
|
||||
|
||||
|
||||
The API
|
||||
-------
|
||||
|
||||
@@ -35,7 +35,7 @@ The Big Picture
|
||||
Defining a well-posed inverse problem and solving it is a complex task that requires many components that must interact. It is helpful
|
||||
to view this task as a workflow in which various elements are explicitly identified and integrated. The figure below outlines the inversion components that consists of inputs, implementation, and evaluation. The inputs are composed of the geophysical data, the equations which are a mathematical description of the governing physics, and prior knowledge or assumptions about the setting. The implementation consists of two broad categories: the forward simulation and the inversion. The **forward simulation** is the means by which we solve the governing equations given a model and the **inversion components** evaluate and update this model. We are considering a gradient based approach, which updates the model through an optimization routine. The output of this implementation is a model, which, prior to interpretation, must be evaluated. This requires considering, and often re-assessing, the choices and assumptions made in both the input and implementation stages.
|
||||
|
||||
.. image:: ../../images/InversionWorkflow-PreSimPEG.png
|
||||
.. image:: InversionWorkflow-PreSimPEG.png
|
||||
:width: 400 px
|
||||
:alt: Components
|
||||
:align: center
|
||||
@@ -46,24 +46,24 @@ A Comprehensive Framework
|
||||
|
||||
There are an overwhelming amount of choices to be made as one works through the forward modeling and inversion process (see figure above). As a result, software implementations of this workflow often become complex and highly interdependent, making it difficult to interact with and to ask other scientists to pick up and change. Our approach to handling this complexity is to propose a framework, (see below), that compartmentalizes the implementation of inversions into various units. We present it in this specific modular style, as each unit contains a targeted subset of choices crucial to the inversion process.
|
||||
|
||||
.. image:: ../../images/InversionWorkflow.png
|
||||
.. image:: InversionWorkflow.png
|
||||
:width: 400 px
|
||||
:alt: Framework
|
||||
:align: center
|
||||
|
||||
The process of obtaining an acceptable model from an inversion generally requires the geophysicist to perform several iterations of the inversion workflow, rethinking and redesigning each piece of the framework to ensure it is appropriate in the current context. Inversions are experimental and empirical by nature and our software package is designed to facilitate this iterative process. To accomplish this, we have divided the inversion methodology into eight major components (See figure above). The :class:`SimPEG.Mesh.BaseMesh.BaseMesh` class handles the discretization of the earth and also provides numerical operators. The forward simulation is split into two classes, the :class:`SimPEG.Survey.BaseSurvey` and the :class:`SimPEG.Problem.BaseProblem`. The :class:`SimPEG.Survey.BaseSurvey` class handles the geometry of a geophysical problem as well as sources. The :class:`SimPEG.Problem.BaseProblem` class handles the simulation of the physics for the geophysical problem of interest. Although created independently, these two classes must be paired to form all of the components necessary for a geophysical forward simulation and calculation of the sensitivity. The :class:`SimPEG.Problem.BaseProblem` creates geophysical fields given a source from the :class:`SimPEG.Survey.BaseSurvey`. The :class:`SimPEG.Survey.BaseSurvey` interpolates these fields to the receiver locations and converts them to the appropriate data type, for example, by selecting only the measured components of the field. Each of these operations may have associated derivatives with respect to the model and the computed field; these are included in the calculation of the sensitivity. For the inversion, a :class:`SimPEG.DataMisfit.BaseDataMisfit` is chosen to capture the goodness of fit of the predicted data and a :class:`SimPEG.Regularization.BaseRegularization` is chosen to handle the non-uniqueness. These inversion elements and an Optimization routine are combined into an inverse problem class :class:`SimPEG.InvProblem.BaseInvProblem`. :class:`SimPEG.InvProblem.BaseInvProblem` is the mathematical statement that will be numerically solved by running an Inversion. The :class:`SimPEG.Inversion.BaseInversion` class handles organization and dispatch of directives between all of the various pieces of the framework.
|
||||
The process of obtaining an acceptable model from an inversion generally requires the geophysicist to perform several iterations of the inversion workflow, rethinking and redesigning each piece of the framework to ensure it is appropriate in the current context. Inversions are experimental and empirical by nature and our software package is designed to facilitate this iterative process. To accomplish this, we have divided the inversion methodology into eight major components (See figure above). The (:class:`SimPEG.Mesh.BaseMesh`) class handles the discretization of the earth and also provides numerical operators. The forward simulation is split into two classes, the (:class:`SimPEG.Survey.BaseSurvey`) and the (:class:`SimPEG.Problem.BaseProblem`). The (:class:`SimPEG.Survey.BaseSurvey`) class handles the geometry of a geophysical problem as well as sources. The (:class:`SimPEG.Problem.BaseProblem`) class handles the simulation of the physics for the geophysical problem of interest. Although created independently, these two classes must be paired to form all of the components necessary for a geophysical forward simulation and calculation of the sensitivity. The (:class:`SimPEG.Problem.BaseProblem`) creates geophysical fields given a source from the (:class:`SimPEG.Survey.BaseSurvey`). The (:class:`SimPEG.Survey.BaseSurvey`) interpolates these fields to the receiver locations and converts them to the appropriate data type, for example, by selecting only the measured components of the field. Each of these operations may have associated derivatives with respect to the model and the computed field; these are included in the calculation of the sensitivity. For the inversion, a (:class:`SimPEG.DataMisfit.BaseDataMisfit`) is chosen to capture the goodness of fit of the predicted data and a (:class:`SimPEG.Regularization.BaseRegularization`) is chosen to handle the non-uniqueness. These inversion elements and an Optimization routine are combined into an inverse problem class (:class:`SimPEG.InvProblem.BaseInvProblem`). (:class:`SimPEG.InvProblem.BaseInvProblem`) is the mathematical statement that will be numerically solved by running an Inversion. The (:class:`SimPEG.Inversion.BaseInversion`) class handles organization and dispatch of directives between all of the various pieces of the framework.
|
||||
|
||||
The arrows in the figure above indicate what each class takes as a primary argument. For example, both the :class:`SimPEG.Problem.BaseProblem` and :class:`SimPEG.Regularization.BaseRegularization` classes take a :class:`SimPEG.Mesh.BaseMesh.BaseMesh` class as an argument. The diagram does not show class inheritance, as each of the base classes outlined have many subtypes that can be interchanged. The :class:`SimPEG.Mesh.BaseMesh.BaseMesh` class, for example, could be a regular Cartesian mesh :class:`SimPEG.Mesh.TensorMesh` or a cylindrical coordinate mesh :class:`SimPEG.Mesh.CylMesh`, which have many properties in common. These common features, such as both meshes being created from tensor products, can be exploited through inheritance of base classes, and differences can be expressed through subtype polymorphism. Please look at the documentation here for more in-depth information.
|
||||
The arrows in the figure above indicate what each class takes as a primary argument. For example, both the (:class:`SimPEG.Problem.BaseProblem`) and (:class:`SimPEG.Regularization.BaseRegularization`) classes take a (:class:`SimPEG.Mesh.BaseMesh`) class as an argument. The diagram does not show class inheritance, as each of the base classes outlined have many subtypes that can be interchanged. The (:class:`SimPEG.Mesh.BaseMesh`) class, for example, could be a regular Cartesian mesh (:class:`SimPEG.Mesh.TensorMesh`) or a cylindrical coordinate mesh (:class:`SimPEG.Mesh.CylMesh`), which have many properties in common. These common features, such as both meshes being created from tensor products, can be exploited through inheritance of base classes, and differences can be expressed through subtype polymorphism. Please look at the documentation here for more in-depth information.
|
||||
|
||||
|
||||
.. include:: ../../../CITATION.rst
|
||||
.. include:: ../CITATION.rst
|
||||
|
||||
Authors
|
||||
-------
|
||||
|
||||
.. include:: ../../../AUTHORS.rst
|
||||
.. include:: ../AUTHORS.rst
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
.. include:: ../../../LICENSE
|
||||
.. include:: ../LICENSE
|
||||
@@ -1,95 +0,0 @@
|
||||
# application: simpegdocs
|
||||
# version: 1
|
||||
runtime: python27
|
||||
api_version: 1
|
||||
threadsafe: yes
|
||||
|
||||
handlers:
|
||||
|
||||
# favicon
|
||||
- url: /images/logo-block\.ico
|
||||
static_files: /images/logo-block.ico
|
||||
upload: /images/logo-block\.ico
|
||||
|
||||
# all css
|
||||
- url: /(.*\.css)
|
||||
mime_type: text/css
|
||||
static_files: _build/html/\1
|
||||
upload: _build/html/(.*\.css)
|
||||
|
||||
# webfonts
|
||||
- url: /(.*\.(eot|svg|ttf|woff|woff2|otf))
|
||||
static_files: _build/html/\1
|
||||
upload: _build/html/(.*\.(eot|svg|ttf|woff|woff2|otf))
|
||||
|
||||
# javascript
|
||||
- url: /(.*\.js)
|
||||
mime_type: text/javascript
|
||||
static_files: _build/html/\1
|
||||
upload: _build/html/(.*\.js)
|
||||
|
||||
# plain text source
|
||||
- url: /(.*\.txt)
|
||||
mime_type: text/plain
|
||||
static_files: _build/html/\1
|
||||
upload: _build/html/(.*\.txt)
|
||||
|
||||
# images
|
||||
- url: /_images/(.*\.(gif|png|jpg|ico))
|
||||
static_files: _build/html/_images/\1
|
||||
upload: _build/html/_images/(.*\.(gif|png|jpg|ico))
|
||||
|
||||
# redirect en/latest traffic
|
||||
- url: /en/latest/(.*\.html)
|
||||
script: simpegdocs.app
|
||||
|
||||
# raw html
|
||||
- url: /(.*\.html)
|
||||
mime_type: text/html
|
||||
static_files: _build/html/\1
|
||||
upload: _build/html/(.*\.html)
|
||||
|
||||
# serve index files
|
||||
- url: /(.+)/
|
||||
static_files: _build/html/\1/index.html
|
||||
upload: _build/html/(.+)/index.html
|
||||
|
||||
- url: /(.+)
|
||||
static_files: _build/html/\1/index.html
|
||||
upload: _build/html/(.+)/index.html
|
||||
|
||||
- url: /
|
||||
static_files: _build/html/index.html
|
||||
upload: _build/html/index.html
|
||||
|
||||
- url: .*
|
||||
script: simpegdocs.app
|
||||
|
||||
# Recommended file skipping declaration from the GAE tutorials
|
||||
skip_files:
|
||||
- ^(.*/)?app\.yaml
|
||||
- ^(.*/)?app\.yml
|
||||
- ^(.*/)?#.*#
|
||||
- ^(.*/)?.*~
|
||||
- ^(.*/)?.*\.py[co]
|
||||
- ^(.*/)?.*/RCS/.*
|
||||
- ^(.*/)?\..*
|
||||
- ^(.*/)?tests$
|
||||
- ^(.*/)?test$
|
||||
- ^test/(.*/)?
|
||||
- ^COPYING.LESSER
|
||||
- ^README\..*
|
||||
- \.gitignore
|
||||
- ^\.git/.*
|
||||
- \.*\.lint$
|
||||
- ^(.*/)?.*\.doctree$
|
||||
|
||||
libraries:
|
||||
- name: webapp2
|
||||
version: "2.5.2"
|
||||
- name: PIL
|
||||
version: "1.1.7"
|
||||
- name: numpy
|
||||
version: "latest"
|
||||
- name: jinja2
|
||||
version: "latest"
|
||||
+6
-47
@@ -28,7 +28,7 @@ sys.path.append('../')
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', 'matplotlib.sphinxext.plot_directive']
|
||||
extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc', 'matplotlib.sphinxext.plot_directive']
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -44,16 +44,16 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'SimPEG'
|
||||
copyright = u'2013 - 2016, SimPEG Developers'
|
||||
copyright = u'2013, SimPEG Developers'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1.12'
|
||||
version = '0.1.10'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1.12'
|
||||
release = '0.1.10'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -124,12 +124,12 @@ except Exception, e:
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
html_favicon = './images/logo-block.ico'
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = []
|
||||
html_static_path = ['_static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
@@ -229,12 +229,6 @@ man_pages = [
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
# Intersphinx
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/2', None),
|
||||
'numpy': ('http://docs.scipy.org/doc/numpy/', None),
|
||||
'scipy': ('http://docs.scipy.org/doc/scipy/reference/', None),
|
||||
'matplotlib': ('http://matplotlib.sourceforge.net/', None)}
|
||||
|
||||
|
||||
# -- Options for Texinfo output ------------------------------------------------
|
||||
|
||||
@@ -257,38 +251,3 @@ texinfo_documents = [
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
autodoc_member_order = 'bysource'
|
||||
|
||||
def supress_nonlocal_image_warn():
|
||||
import sphinx.environment
|
||||
sphinx.environment.BuildEnvironment.warn_node = _supress_nonlocal_image_warn
|
||||
|
||||
def _supress_nonlocal_image_warn(self, msg, node):
|
||||
from docutils.utils import get_source_line
|
||||
|
||||
if not msg.startswith('nonlocal image URI found:'):
|
||||
self._warnfunc(msg, '%s:%s' % get_source_line(node))
|
||||
|
||||
supress_nonlocal_image_warn()
|
||||
|
||||
|
||||
nitpick_ignore = [
|
||||
('py:class', 'IdentityMap'),
|
||||
('py:class', 'BaseSurvey'),
|
||||
('py:class', 'BaseSrc'),
|
||||
('py:class', 'BaseRx'),
|
||||
('py:class', 'Survey'),
|
||||
('py:class', 'FieldsFDEM'),
|
||||
('py:class', 'Fields3D_e'),
|
||||
('py:class', 'Fields3D_b'),
|
||||
('py:class', 'Fields3D_j'),
|
||||
('py:class', 'Fields3D_h'),
|
||||
('py:class', 'SurveyTDEM'),
|
||||
('py:class', 'SrcTDEM'),
|
||||
('py:class', 'EMPropMap'),
|
||||
('py:class', 'Data'),
|
||||
('py:class', 'SurveyDC'),
|
||||
('py:class', 'BaseMTFields'),
|
||||
('py:class', 'SolverLU'),
|
||||
('py:class', 'BaseMagSurvey'),
|
||||
('py:class', 'BaseMagMap'),
|
||||
]
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
.. _api_FiniteVolume:
|
||||
|
||||
Finite Volume
|
||||
*************
|
||||
|
||||
Any numerical implementation requires the discretization of continuous
|
||||
functions into discrete approximations. These approximations are typically
|
||||
organized in a mesh, which defines boundaries, locations, and connectivity. Of
|
||||
specific interest to geophysical simulations, we require that averaging,
|
||||
interpolation and differential operators be defined for any mesh. In SimPEG,
|
||||
we have implemented a staggered mimetic finite volume approach (`Hyman and
|
||||
Shashkov, 1999 <http://math.lanl.gov/~mac/papers/numerics/HS99B.pdf>`_). This
|
||||
approach requires the definitions of variables at either cell-centers, nodes,
|
||||
faces, or edges as seen in the figure below.
|
||||
|
||||
.. image:: ../../images/finitevolrealestate.png
|
||||
:width: 400 px
|
||||
:alt: FiniteVolume
|
||||
:align: center
|
||||
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
api_Mesh
|
||||
api_DiffOps
|
||||
api_InnerProducts
|
||||
@@ -1,68 +0,0 @@
|
||||
.. _api_MeshCode:
|
||||
|
||||
Tensor Mesh
|
||||
===========
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.TensorMesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Cylindrical Mesh
|
||||
================
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.CylMesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Tree Mesh
|
||||
=========
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.TreeMesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Curvilinear Mesh
|
||||
================
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.CurvilinearMesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Base Rectangular Mesh
|
||||
=====================
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.BaseMesh.BaseRectangularMesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
Base Tensor Mesh
|
||||
================
|
||||
|
||||
.. autoclass:: SimPEG.Mesh.TensorMesh.BaseTensorMesh
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Mesh IO
|
||||
=======
|
||||
|
||||
.. automodule:: SimPEG.Mesh.MeshIO
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Mesh Viewing
|
||||
============
|
||||
|
||||
.. automodule:: SimPEG.Mesh.View
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -1,29 +0,0 @@
|
||||
SimPEG PropMaps
|
||||
***************
|
||||
|
||||
The API
|
||||
=======
|
||||
|
||||
Property
|
||||
--------
|
||||
|
||||
.. autoclass:: SimPEG.PropMaps.Property
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
PropMap
|
||||
-------
|
||||
|
||||
.. autoclass:: SimPEG.PropMaps.PropMap
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
PropModel
|
||||
---------
|
||||
|
||||
.. autoclass:: SimPEG.PropMaps.PropModel
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
Overview of Electromagnetics in SimPEG
|
||||
**************************************
|
||||
|
||||
|
||||
The API
|
||||
=======
|
||||
|
||||
Physical Properties
|
||||
-------------------
|
||||
|
||||
.. autoclass:: SimPEG.EM.Base.EMPropMap
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
Problem
|
||||
-------
|
||||
|
||||
.. autoclass:: SimPEG.EM.Base.BaseEMProblem
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
Survey
|
||||
------
|
||||
|
||||
.. autoclass:: SimPEG.EM.Base.BaseEMSurvey
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
.. _examples_Maps_ComboMaps:
|
||||
|
||||
.. --------------------------------- ..
|
||||
.. ..
|
||||
.. THIS FILE IS AUTO GENEREATED ..
|
||||
.. ..
|
||||
.. SimPEG/Examples/__init__.py ..
|
||||
.. ..
|
||||
.. --------------------------------- ..
|
||||
|
||||
|
||||
|
||||
Maps: ComboMaps
|
||||
===============
|
||||
|
||||
We will use an example where we want a 1D layered earth as
|
||||
our model, but we want to map this to a 2D discretization to do our forward
|
||||
modeling. We will also assume that we are working in log conductivity still,
|
||||
so after the transformation we want to map to conductivity space.
|
||||
To do this we will introduce the vertical 1D map (:class:`SimPEG.Maps.SurjectVertical1D`),
|
||||
which does the first part of what we just described. The second part will be
|
||||
done by the :class:`SimPEG.Maps.ExpMap` described above.
|
||||
|
||||
.. code-block:: python
|
||||
:linenos:
|
||||
|
||||
M = Mesh.TensorMesh([7,5])
|
||||
v1dMap = Maps.SurjectVertical1D(M)
|
||||
expMap = Maps.ExpMap(M)
|
||||
myMap = expMap * v1dMap
|
||||
m = np.r_[0.2,1,0.1,2,2.9] # only 5 model parameters!
|
||||
sig = myMap * m
|
||||
|
||||
If you noticed, it was pretty easy to combine maps. What is even cooler is
|
||||
that the derivatives also are made for you (if everything goes right).
|
||||
Just to be sure that the derivative is correct, you should always run the test
|
||||
on the mapping that you create.
|
||||
|
||||
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.Maps_ComboMaps.run()
|
||||
|
||||
.. literalinclude:: ../../../SimPEG/Examples/Maps_ComboMaps.py
|
||||
:language: python
|
||||
:linenos:
|
||||
@@ -1,25 +0,0 @@
|
||||
.. _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:
|
||||
@@ -1,26 +0,0 @@
|
||||
.. _examples_PF_Magnetics_Analytics:
|
||||
|
||||
.. --------------------------------- ..
|
||||
.. ..
|
||||
.. THIS FILE IS AUTO GENEREATED ..
|
||||
.. ..
|
||||
.. SimPEG/Examples/__init__.py ..
|
||||
.. ..
|
||||
.. --------------------------------- ..
|
||||
|
||||
|
||||
PF: Magnetics: Analytics
|
||||
========================
|
||||
|
||||
Comparing the magnetics field in Vancouver to Seoul
|
||||
|
||||
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.PF_Magnetics_Analytics.run()
|
||||
|
||||
.. literalinclude:: ../../../SimPEG/Examples/PF_Magnetics_Analytics.py
|
||||
:language: python
|
||||
:linenos:
|
||||
@@ -1,14 +0,0 @@
|
||||
Induced Polarization
|
||||
********************
|
||||
|
||||
Todo: docs for IP!
|
||||
|
||||
|
||||
API for IP codes
|
||||
================
|
||||
|
||||
.. automodule:: SimPEG.DCIP.BaseIP
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
@@ -1,170 +0,0 @@
|
||||
.. math::
|
||||
|
||||
\renewcommand{\div}{\nabla\cdot\,}
|
||||
\newcommand{\grad}{\vec \nabla}
|
||||
\newcommand{\curl}{{\vec \nabla}\times\,}
|
||||
\newcommand {\J}{{\vec J}}
|
||||
\renewcommand{\H}{{\vec H}}
|
||||
\newcommand {\E}{{\vec E}}
|
||||
\newcommand{\dcurl}{{\mathbf C}}
|
||||
\newcommand{\dgrad}{{\mathbf G}}
|
||||
\newcommand{\Acf}{{\mathbf A_c^f}}
|
||||
\newcommand{\Ace}{{\mathbf A_c^e}}
|
||||
\renewcommand{\S}{{\mathbf \Sigma}}
|
||||
\renewcommand{\Div}{{\mathbf {Div}}}
|
||||
\newcommand{\St}{{\mathbf \Sigma_\tau}}
|
||||
\newcommand{\T}{{\mathbf T}}
|
||||
\newcommand{\Tt}{{\mathbf T_\tau}}
|
||||
\newcommand{\diag}{\mathbf{diag}}
|
||||
\newcommand{\M}{{\mathbf M}}
|
||||
\newcommand{\MfMui}{{\M^f_{\mu^{-1}}}}
|
||||
\newcommand{\dMfMuI}{{d_m (\M^f_{\mu^{-1}})^{-1}}}
|
||||
\newcommand{\MeSig}{{\M^e_\sigma}}
|
||||
\newcommand{\MeSigInf}{{\M^e_{\sigma_\infty}}}
|
||||
\newcommand{\MeSigO}{{\M^e_{\sigma_0}}}
|
||||
\newcommand{\Me}{{\M^e}}
|
||||
\newcommand{\Mes}[1]{{\M^e_{#1}}}
|
||||
\newcommand{\Mee}{{\M^e_e}}
|
||||
\newcommand{\Mej}{{\M^e_j}}
|
||||
\newcommand{\BigO}[1]{\mathcal{O}\bigl(#1\bigr)}
|
||||
\newcommand{\bE}{\mathbf{E}}
|
||||
\newcommand{\bH}{\mathbf{H}}
|
||||
\newcommand{\B}{\vec{B}}
|
||||
\newcommand{\D}{\vec{D}}
|
||||
\renewcommand{\H}{\vec{H}}
|
||||
\newcommand{\s}{\vec{s}}
|
||||
\newcommand{\bfJ}{\bf{J}}
|
||||
\newcommand{\vecm}{\vec m}
|
||||
\renewcommand{\Re}{\mathsf{Re}}
|
||||
\renewcommand{\Im}{\mathsf{Im}}
|
||||
\renewcommand {\j} { {\vec j} }
|
||||
\newcommand {\h} { {\vec h} }
|
||||
\renewcommand {\b} { {\vec b} }
|
||||
\newcommand {\e} { {\vec e} }
|
||||
\newcommand {\c} { {\vec c} }
|
||||
\renewcommand {\d} { {\vec d} }
|
||||
\renewcommand {\u} { {\vec u} }
|
||||
\newcommand{\I}{\vec{I}}
|
||||
|
||||
Magnetics
|
||||
*********
|
||||
|
||||
|
||||
The geomagnetic field can be ranked as the longest studied of all the geophysical properties of the earth. In addition, magnetic survey, has been used broadly in diverse realm e.g., mining, oil and gas industry and environmental engineering. Although, this geophysical application is quite common in geoscience; however, we do not have modular, well-documented and well-tested open-source codes, which perform forward and inverse problems of magnetic survey. Therefore, here we are going to build up magnetic forward and inverse modeling code based on two common methodologies for forward problem - differential equation and integral equation approaches. \
|
||||
|
||||
First, we start with some backgrounds of magnetics, e.g., Maxwell's equations. Based on that secondly, we use differential equation approach to solve forward problem with secondary field formulation. In order to discretzie our system here, we use finite volume approach with weak formulation. Third, we solve inverse problem through Gauss-Newton method.
|
||||
|
||||
Backgrounds
|
||||
===========
|
||||
Maxwell's equations for static case with out current source can be written as
|
||||
|
||||
.. math::
|
||||
|
||||
\nabla U = \frac{1}{\mu}\vec{B} \\
|
||||
|
||||
\nabla \cdot \vec{B} = 0
|
||||
|
||||
where \\(\\vec{B}\\) is magnetic flux (\\(\T\\)) and \\(\U\\) is magnetic potential and \\(\\mu\\) is permeability. Since we do not have any source term in above equations, boundary condition is going to be the driving force of our system as given below
|
||||
|
||||
.. math::
|
||||
|
||||
(\vec{B}\cdot{\vec{n}})_{\partial\Omega} = B_{BC}
|
||||
|
||||
where \\(\\vec{n}\\) means the unit normal vector on the boundary surface (\\(\\partial \\Omega\\)). By using seocondary field formulation we can rewrite above equations as
|
||||
|
||||
.. math::
|
||||
|
||||
\frac{1}{\mu}\vec{B}_s = (\frac{1}{\mu}_0-\frac{1}{\mu})\vec{B}_0+\nabla\phi_s
|
||||
|
||||
\nabla \cdot \vec{B}_s = 0
|
||||
|
||||
(\vec{B}_s\cdot{\vec{n}})_{\partial\Omega} = B_{sBC}
|
||||
|
||||
where \\(\\vec{B}_s\\) is the secondary magnetic flux and \\(\\vec{B}_0\\) is the background or primary magnetic flux. In practice, we consider our earth field, which we can get from International Geomagnetic Reference Field (IGRF) by specifying the time and location, as \\(\\vec{B}_0\\). And based on this background fields, we compute secondary fields (\\(\\vec{B}_s\\)). Now we introduce the susceptibility as
|
||||
|
||||
.. math::
|
||||
|
||||
\chi = \frac{\mu}{\mu_0} - 1 \\
|
||||
|
||||
\mu = \mu_0(1+\chi)
|
||||
|
||||
Since most materials in the earth have lower permeability than \\(\\mu_0\\), usually \\(\\chi\\) is greater than 0.
|
||||
|
||||
.. note::
|
||||
|
||||
Actually, this is an assumption, which means we are not sure exactly this is true, although we are sure, it is very rare that we can encounter those materials. Anyway, practical range of the susceptibility is \\(0 < \\chi < 1 \\).
|
||||
|
||||
Since we compute secondary field based on the earth field, which can be different from different locations in the world, we can expect different anomalous responses in different locations in the earth. For instance, assume we have two susceptible spheres, which are exactly same. However, anomalous responses in Seoul and Vancouver are going to be different.
|
||||
|
||||
.. plot::
|
||||
|
||||
from SimPEG import Examples
|
||||
Examples.PF_Magnetics_Analytics.run()
|
||||
|
||||
Since we can measure total fields ( \\(\\vec{B}\\)), and usually have reasonably accurate earth field (\\(\\vec{B}_0\\)), we can compute anomalous fields, \\(\\vec{B}_s\\) from our observed data. If you want to download earth magnetic fields at specific location see this website (`noaa <http://www.ngdc.noaa.gov/geomag-web/>`_).
|
||||
|
||||
What is our data?
|
||||
-----------------
|
||||
|
||||
In applied geophysics, which means in practice, it is common to refer to measurements as "the magnetic anomaly" and we can consider this as our observed data. For further descriptions in `GPG <http://www.eos.ubc.ca/courses/eosc350/content/>`_ materials for magnetic survey. Now we have the simple relation ship between "the magnetic anomaly" and the total field as
|
||||
|
||||
.. math::
|
||||
|
||||
\triangle\vec{B} = |\hat{B}_o-\vec{B}_s|-|\hat{B}_o| \approx |\vec{B}_s|cos \theta
|
||||
|
||||
where \\(\\theta\\) is the angle between total and anomalous fields, \\(\\hat{B}_o\\) is the unit vector for \\(\\vec{B}_o\\). Equivalently, we can use the vector dot product to show that the anomalous field is approximately equal to the projection of that field onto the direction of the inducing field. Using this approach we would write
|
||||
|
||||
.. math::
|
||||
|
||||
\triangle\vec{B} = |\vec{B}_s|cos \theta = |\hat{B}_o||\vec{B}_s|cos \theta = \hat{B}_o \cdot \vec{B}_s
|
||||
|
||||
This is important because, in practice we usually use a total field magnetometer (like a proton precession or optically pumped sensor), which can measure only that part of the anomalous field which is in the direction of the earth's main field.
|
||||
|
||||
Sphere in a whole space
|
||||
-----------------------
|
||||
|
||||
|
||||
Forward problem
|
||||
===============
|
||||
|
||||
Differential equation approach
|
||||
------------------------------
|
||||
|
||||
.. math::
|
||||
|
||||
\mathbf{A}\mathbf{u} = \mathbf{rhs}
|
||||
|
||||
\mathbf{A} = \Div(\MfMui)^{-1}\Div^{T}
|
||||
|
||||
\mathbf{rhs} = \Div(\MfMui)^{-1}\mathbf{M}^f_{\mu_0^{-1}}\mathbf{B}_0 - \Div\mathbf{B}_0+\diag(v)\mathbf{D} \mathbf{P}_{out}^T \mathbf{B}_{sBC}
|
||||
|
||||
\mathbf{B}_s = (\MfMui)^{-1}\mathbf{M}^f_{\mu_0^{-1}}\mathbf{B}_0-\mathbf{B}_0 -(\MfMui)^{-1}\Div^T \mathbf{u}
|
||||
|
||||
|
||||
Mag Differential eq. approach
|
||||
=============================
|
||||
|
||||
.. autoclass:: SimPEG.PF.Magnetics.Problem3D_DiffSecondary
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
.. autoclass:: SimPEG.PF.BaseMag.BaseMagSurvey
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
|
||||
|
||||
Mag Integral eq. approach
|
||||
=========================
|
||||
|
||||
Mag analytic solutions
|
||||
----------------------
|
||||
|
||||
.. automodule:: SimPEG.PF.MagAnalytics
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
:inherited-members:
|
||||
Binary file not shown.
@@ -9,28 +9,17 @@
|
||||
Frequency Domain Electromagnetics
|
||||
*********************************
|
||||
|
||||
Electromagnetic (EM) geophysical methods are used in a variety of applications
|
||||
from resource exploration, including for hydrocarbons and minerals, to
|
||||
environmental applications, such as groundwater monitoring. The primary
|
||||
physical property of interest in EM is electrical conductivity, which
|
||||
describes the ease with which electric current flows through a material.
|
||||
Electromagnetic (EM) geophysical methods are used in a variety of applications from resource exploration, including for hydrocarbons and minerals, to environmental applications, such as groundwater monitoring. The primary physical property of interest in EM is electrical conductivity, which describes the ease with which electric current flows through a material.
|
||||
|
||||
|
||||
Background
|
||||
==========
|
||||
|
||||
Electromagnetic phenomena are governed by Maxwell's equations. They describe
|
||||
the behavior of EM fields and fluxes. Electromagnetic theory for geophysical
|
||||
applications by Ward and Hohmann (1988) is a highly recommended resource on
|
||||
this topic.
|
||||
Electromagnetic phenomena are governed by Maxwell's equations. They describe the behavior of EM fields and fluxes. Electromagnetic theory for geophysical applications by Ward and Hohmann (1988) is a highly recommended resource on this topic.
|
||||
|
||||
Fourier Transform Convention
|
||||
----------------------------
|
||||
|
||||
In order to examine Maxwell's equations in the frequency domain, we must first
|
||||
define our choice of harmonic time-dependence by choosing a Fourier transform
|
||||
convention. We use the :math:`e^{i \omega t}` convention, so we define our
|
||||
Fourier Transform pair as
|
||||
In order to examine Maxwell's equations in the frequency domain, we must first define our choice of harmonic time-dependence by choosing a Fourier transform convention. We use the :math:`e^{i \omega t}` convention, so we define our Fourier Transform pair as
|
||||
|
||||
.. math ::
|
||||
F(\omega) = \int_{-\infty}^{\infty} f(t) e^{- i \omega t} dt \\
|
||||
@@ -42,7 +31,6 @@ where :math:`\omega` is angular frequency, :math:`t` is time, :math:`F(\omega)`
|
||||
|
||||
Maxwell's Equations
|
||||
===================
|
||||
|
||||
In the frequency domain, Maxwell's equations are given by
|
||||
|
||||
.. math ::
|
||||
@@ -116,20 +104,19 @@ The H-J formulation is in terms of the current density and the magnetic field:
|
||||
|
||||
Discretizing
|
||||
------------
|
||||
|
||||
For both formulations, we use a finite volume discretization
|
||||
and discretize fields on cell edges, fluxes on cell faces and
|
||||
physical properties in cell centers. This is particularly
|
||||
important when using symmetry to reduce the dimensionality of a problem
|
||||
(for instance on a 2D CylMesh, there are :math:`r`, :math:`z` faces and :math:`\theta` edges)
|
||||
|
||||
.. figure:: ../../images/finitevolrealestate.png
|
||||
.. figure:: ../images/finitevolrealestate.png
|
||||
:align: center
|
||||
:scale: 60 %
|
||||
|
||||
For the two formulations, the discretization of the physical properties, fields and fluxes are summarized below.
|
||||
|
||||
.. figure:: ../../images/ebjhdiscretizations.png
|
||||
.. figure:: ../images/ebjhdiscretizations.png
|
||||
:align: center
|
||||
:scale: 60 %
|
||||
|
||||
@@ -163,7 +150,7 @@ API
|
||||
FDEM Problem
|
||||
------------
|
||||
|
||||
.. automodule:: SimPEG.EM.FDEM.ProblemFDEM
|
||||
.. automodule:: SimPEG.EM.FDEM.FDEM
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
@@ -182,11 +169,6 @@ FDEM Survey
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
.. automodule:: SimPEG.EM.FDEM.RxFDEM
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
FDEM Fields
|
||||
-----------
|
||||
|
||||
@@ -359,7 +359,7 @@ TDEM - B formulation
|
||||
Field Storage
|
||||
=============
|
||||
|
||||
.. autoclass:: SimPEG.EM.TDEM.BaseTDEM.FieldsTDEM
|
||||
.. autoclass:: SimPEG.EM.TDEM.SurveyTDEM.FieldsTDEM
|
||||
:show-inheritance:
|
||||
:members:
|
||||
:undoc-members:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user