mirror of
https://github.com/wassname/simpeg.git
synced 2026-09-13 13:03:14 +08:00
Compare commits
338
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3c0c10e48 | ||
|
|
2c429f9dc2 | ||
|
|
62b3a3a218 | ||
|
|
6826df8989 | ||
|
|
78fce342cf | ||
|
|
94f799e7c4 | ||
|
|
947c671c8c | ||
|
|
0367a172a2 | ||
|
|
4796b0f91f | ||
|
|
52b25e2dc5 | ||
|
|
a289b656cd | ||
|
|
334cd8e454 | ||
|
|
ecbdd90f63 | ||
|
|
dcdcbd212a | ||
|
|
17b1459b57 | ||
|
|
394dc9106a | ||
|
|
eda2394411 | ||
|
|
3deca9ed77 | ||
|
|
ba173674ec | ||
|
|
303da372aa | ||
|
|
6d6e7fc8bd | ||
|
|
8ed3ec18fa | ||
|
|
3960cfc313 | ||
|
|
f4a8efab78 | ||
|
|
2eba0b841f | ||
|
|
c79bb998cb | ||
|
|
0763925743 | ||
|
|
1a0b81a206 | ||
|
|
8b44f8d96b | ||
|
|
2bfd01ed7c | ||
|
|
e1ba80883d | ||
|
|
a54713f546 | ||
|
|
2f4c9a2a7a | ||
|
|
b64d967e73 | ||
|
|
ef382aed85 | ||
|
|
1b33804e5a | ||
|
|
c161c5eab2 | ||
|
|
f0944362c8 | ||
|
|
e815ddaec7 | ||
|
|
64b0b4561f | ||
|
|
b9d30af4a8 | ||
|
|
093f441331 | ||
|
|
5e3c1da8e2 | ||
|
|
a3a5c86008 | ||
|
|
7a82f57367 | ||
|
|
845c3c10ab | ||
|
|
c4d86b4a29 | ||
|
|
3fc855f3c9 | ||
|
|
fea508a507 | ||
|
|
5ca52cf49f | ||
|
|
7a06453c42 | ||
|
|
291da78b97 | ||
|
|
ef12a3674a | ||
|
|
504592c8de | ||
|
|
75647f8fc3 | ||
|
|
e3462666bd | ||
|
|
fb37bf0fe2 | ||
|
|
b023adbb33 | ||
|
|
279bd49b4c | ||
|
|
3398d5ab4d | ||
|
|
3e26bb7de9 | ||
|
|
382b31bd12 | ||
|
|
01e19e4227 | ||
|
|
9fbdaaf0a5 | ||
|
|
2a159e20b9 | ||
|
|
5e8d3fbc78 | ||
|
|
414418a996 | ||
|
|
6cc509020a | ||
|
|
40f0874dfb | ||
|
|
231e6dbc93 | ||
|
|
18f98b2ecd | ||
|
|
bc073e49b5 | ||
|
|
a131383dae | ||
|
|
ad4a0240d1 | ||
|
|
74f5395573 | ||
|
|
6f7a0b1279 | ||
|
|
e2bb9c8d8e | ||
|
|
de693adaa7 | ||
|
|
fc07993006 | ||
|
|
12a12c7b5a | ||
|
|
0b4215f33e | ||
|
|
5e2a8232a3 | ||
|
|
feba384911 | ||
|
|
4844b7230a | ||
|
|
f2e13182bf | ||
|
|
09cd9c7fa3 | ||
|
|
62eb4541cb | ||
|
|
09eb2106ec | ||
|
|
f8b86abd5a | ||
|
|
e476bf0059 | ||
|
|
825511e9d3 | ||
|
|
3b4bec9c0b | ||
|
|
1960b52dfd | ||
|
|
022e1f7660 | ||
|
|
28d67e3112 | ||
|
|
406703f1c6 | ||
|
|
7b72d3a92d | ||
|
|
cf89f5f6a2 | ||
|
|
aa1086eba3 | ||
|
|
1c53129da6 | ||
|
|
6fd3be77de | ||
|
|
51d82eee26 | ||
|
|
f6b49c680a | ||
|
|
339543b893 | ||
|
|
44ad57e90d | ||
|
|
d98eef2560 | ||
|
|
21d817d9a2 | ||
|
|
f20fcb4504 | ||
|
|
2c87a50d29 | ||
|
|
beca0203df | ||
|
|
e25b496ab0 | ||
|
|
e5ec512517 | ||
|
|
342414bd25 | ||
|
|
8936fa4021 | ||
|
|
0179631fe3 | ||
|
|
c4c97ae054 | ||
|
|
e8bd78f63d | ||
|
|
d0a65dda1b | ||
|
|
a506d5c6be | ||
|
|
10c8791514 | ||
|
|
c88263234b | ||
|
|
d5219be3d8 | ||
|
|
fd3bde787f | ||
|
|
3cc46131a3 | ||
|
|
cd2360b815 | ||
|
|
029171fb1d | ||
|
|
a690cab131 | ||
|
|
e10d6878fb | ||
|
|
3dd9ecc9cd | ||
|
|
90a3030796 | ||
|
|
c1b1c2467f | ||
|
|
11e6b452c9 | ||
|
|
7964ebce50 | ||
|
|
955bd54019 | ||
|
|
2a802c1aa3 | ||
|
|
3f0c89f10b | ||
|
|
eaa37f42e4 | ||
|
|
fb5434695f | ||
|
|
e037597ecd | ||
|
|
73c219ff5c | ||
|
|
abd919e862 | ||
|
|
6e00b4c2fe | ||
|
|
906cca30f3 | ||
|
|
8803956d83 | ||
|
|
0a714663d3 | ||
|
|
cb042ac938 | ||
|
|
f7c46ed83b | ||
|
|
52747c0926 | ||
|
|
d8eeb7cd05 | ||
|
|
8278230476 | ||
|
|
069127333d | ||
|
|
b4ab60c260 | ||
|
|
fbb8cf2731 | ||
|
|
79e1378009 | ||
|
|
0379df2bf2 | ||
|
|
66440b0478 | ||
|
|
dbdcc3cefb | ||
|
|
4e296c4cd5 | ||
|
|
c488dabf9a | ||
|
|
5e1de61a71 | ||
|
|
69ec374415 | ||
|
|
224105364d | ||
|
|
00bbe0f35e | ||
|
|
a7f89131b4 | ||
|
|
6e12bdc57a | ||
|
|
354e57f24e | ||
|
|
ddb11096c8 | ||
|
|
fa6033c438 | ||
|
|
dd45a6a085 | ||
|
|
bd63e67161 | ||
|
|
d350dc258d | ||
|
|
350818d802 | ||
|
|
ba8f270b3a | ||
|
|
4df6f340d3 | ||
|
|
9b2eec0ea3 | ||
|
|
3d1dfc13d7 | ||
|
|
a6e995e9fb | ||
|
|
056dc09fa6 | ||
|
|
4257ea77b3 | ||
|
|
a0174e4f30 | ||
|
|
00db6746d4 | ||
|
|
028a16a45a | ||
|
|
c83b460672 | ||
|
|
225394f74e | ||
|
|
ace9cad016 | ||
|
|
38aef03f9d | ||
|
|
ef602eaab1 | ||
|
|
0610289fdf | ||
|
|
d14cd444ac | ||
|
|
92e2fd67de | ||
|
|
6a064c5f96 | ||
|
|
f944f9b76b | ||
|
|
dcd4fbf973 | ||
|
|
edc2c5feb6 | ||
|
|
1936a04683 | ||
|
|
fcc2b8b22a | ||
|
|
eeee594f09 | ||
|
|
a48224ed8b | ||
|
|
0bb001973c | ||
|
|
f55d9573a6 | ||
|
|
d8bfb27415 | ||
|
|
0e16645b67 | ||
|
|
8cac166fba | ||
|
|
73001abfc5 | ||
|
|
a9362bd38e | ||
|
|
64b94861a0 | ||
|
|
8775364d8f | ||
|
|
5ec6e79a39 | ||
|
|
79183ae9fb | ||
|
|
606488d152 | ||
|
|
2c09be9fc1 | ||
|
|
cd5339322e | ||
|
|
28005dde45 | ||
|
|
8739ba0f20 | ||
|
|
119bc801c7 | ||
|
|
23d2783bc1 | ||
|
|
b58ba55ffd | ||
|
|
0d6fe5f7a1 | ||
|
|
35bac38c8b | ||
|
|
05e3b02b3a | ||
|
|
bd318f0092 | ||
|
|
90b0301408 | ||
|
|
083742cb40 | ||
|
|
2a351be971 | ||
|
|
3e4f47711c | ||
|
|
e305600de5 | ||
|
|
8a18e479ab | ||
|
|
d13c540be0 | ||
|
|
f15a628136 | ||
|
|
fb60f45a3c | ||
|
|
822f6d333d | ||
|
|
6000034826 | ||
|
|
16c6cc8d74 | ||
|
|
636d178fbf | ||
|
|
0575490f56 | ||
|
|
ae9ca6cec9 | ||
|
|
f799733a9d | ||
|
|
2bd5829b42 | ||
|
|
8b94cd4dfe | ||
|
|
09f3f7b55b | ||
|
|
15d59a5b50 | ||
|
|
e646211e7d | ||
|
|
ba977206ea | ||
|
|
fb1ff4e867 | ||
|
|
a31319b46e | ||
|
|
d8aec96080 | ||
|
|
756b738ef2 | ||
|
|
aad596a8cc | ||
|
|
8d6bd65923 | ||
|
|
df620b42bd | ||
|
|
31d418bed8 | ||
|
|
7a6f4e0780 | ||
|
|
2ee158e5d7 | ||
|
|
8f73b2e7be | ||
|
|
16d62a6d0a | ||
|
|
5d9d746932 | ||
|
|
df3d32cb35 | ||
|
|
f59cfa9481 | ||
|
|
99ed4ad50e | ||
|
|
b531c162a2 | ||
|
|
a220c75d78 | ||
|
|
c7883673bf | ||
|
|
d8d8915f94 | ||
|
|
35c6d50db1 | ||
|
|
9c220ef37c | ||
|
|
021e7c794c | ||
|
|
0a0caceaca | ||
|
|
936a7aaadc | ||
|
|
44049bb48c | ||
|
|
1d208a8747 | ||
|
|
b6438688d8 | ||
|
|
824ce64c7e | ||
|
|
7aa5599211 | ||
|
|
fbec011983 | ||
|
|
5fb8cdb88c | ||
|
|
b765699d2f | ||
|
|
fdc081970e | ||
|
|
c66db805af | ||
|
|
579f1d7a65 | ||
|
|
c51afa4aad | ||
|
|
cc9d2e5ac7 | ||
|
|
055061ac3b | ||
|
|
d5f73d0fd3 | ||
|
|
3d11431f2f | ||
|
|
f92ff1301d | ||
|
|
d302a59b2c | ||
|
|
ef467efce0 | ||
|
|
d226186c8e | ||
|
|
38b4079f0b | ||
|
|
9d4e2488f3 | ||
|
|
838035adae | ||
|
|
ef4513bcd4 | ||
|
|
4fefccc97d | ||
|
|
1946e1f69e | ||
|
|
33c9059e4e | ||
|
|
d9b3c038c4 | ||
|
|
b5b70390cb | ||
|
|
2f8b8a36bf | ||
|
|
5e5c7ba0fb | ||
|
|
6c33455d15 | ||
|
|
7000699e38 | ||
|
|
63bf8b9e4d | ||
|
|
e3af1fd94e | ||
|
|
4e871a43a9 | ||
|
|
b5f4d8e999 | ||
|
|
e4a3e0a16d | ||
|
|
1c2fecf3a2 | ||
|
|
c10777a245 | ||
|
|
05a85018de | ||
|
|
8aa23c31de | ||
|
|
a9c9ce6bc8 | ||
|
|
6286e48830 | ||
|
|
4cf5d49524 | ||
|
|
88ef74ac38 | ||
|
|
3a506b9051 | ||
|
|
fa6bcd3ffa | ||
|
|
47895ef270 | ||
|
|
429d8b1191 | ||
|
|
774d612c18 | ||
|
|
6acaa81faf | ||
|
|
312b5d79c5 | ||
|
|
999a37547e | ||
|
|
433457f649 | ||
|
|
3eeb5dbd3c | ||
|
|
df78f7b33a | ||
|
|
cbe8758465 | ||
|
|
6b359f49b5 | ||
|
|
2254eedbac | ||
|
|
012d2cadf1 | ||
|
|
841ba61006 | ||
|
|
2874e204ee | ||
|
|
adca273565 | ||
|
|
d9d6f70958 | ||
|
|
f4ef767764 | ||
|
|
e314bdb740 | ||
|
|
e005ed8f5f | ||
|
|
ac2e38e89d | ||
|
|
ade37fb493 |
+1
-1
@@ -1,4 +1,4 @@
|
||||
[bumpversion]
|
||||
current_version = 0.1.10
|
||||
current_version = 0.1.12
|
||||
files = setup.py SimPEG/__init__.py docs/conf.py
|
||||
|
||||
|
||||
@@ -39,3 +39,5 @@ nosetests.xml
|
||||
*.sublime-workspace
|
||||
docs/_build/
|
||||
Makefile
|
||||
docs/warnings.txt
|
||||
.DS_Store
|
||||
|
||||
+26
-3
@@ -24,18 +24,25 @@ env:
|
||||
- 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:
|
||||
- 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
|
||||
# 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
|
||||
- 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
|
||||
- conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython nose vtk sphinx
|
||||
- pip install nose-cov python-coveralls
|
||||
|
||||
- git clone https://github.com/rowanc1/pymatsolver.git
|
||||
@@ -46,12 +53,28 @@ 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
|
||||
|
||||
+5
-1
@@ -1,4 +1,4 @@
|
||||
.. image:: https://raw.github.com/simpeg/simpeg/master/docs/simpeg-logo.png
|
||||
.. image:: https://raw.github.com/simpeg/simpeg/master/docs/images/simpeg-logo.png
|
||||
:alt: SimPEG Logo
|
||||
|
||||
======
|
||||
@@ -25,6 +25,10 @@ SimPEG
|
||||
:target: https://coveralls.io/r/simpeg/simpeg?branch=master
|
||||
:alt: Coverage status
|
||||
|
||||
.. image:: http://img.shields.io/badge/GITTER-JOIN_CHAT-brightgreen.svg?style=flat-square
|
||||
:alt: gitter chat room at https://gitter.im/simpeg/simpeg
|
||||
:target: https://gitter.im/simpeg/simpeg
|
||||
|
||||
Simulation and Parameter Estimation in Geophysics - A python package for simulation and gradient based parameter estimation in the context of geophysical applications.
|
||||
|
||||
The vision is to create a package for finite volume simulation with applications to geophysical imaging and subsurface flow. To enable the understanding of the many different components, this package has the following features:
|
||||
|
||||
+13
-15
@@ -162,8 +162,8 @@ class ProblemDC_CC(Problem.BaseProblem):
|
||||
"""
|
||||
Makes the matrix A(m) for the DC resistivity problem.
|
||||
|
||||
:param numpy.array m: model
|
||||
:rtype: scipy.csc_matrix
|
||||
:param numpy.ndarray m: model
|
||||
:rtype: scipy.sparse.csc_matrix
|
||||
:return: A(m)
|
||||
|
||||
.. math::
|
||||
@@ -200,11 +200,11 @@ class ProblemDC_CC(Problem.BaseProblem):
|
||||
|
||||
return F
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: Jv
|
||||
|
||||
@@ -225,11 +225,10 @@ class ProblemDC_CC(Problem.BaseProblem):
|
||||
# Set current model; clear dependent property $\mathbf{A(m)}$
|
||||
self.curModel = m
|
||||
sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
|
||||
if u is None:
|
||||
if f is None:
|
||||
# Run forward simulation if $u$ not provided
|
||||
u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol']
|
||||
else:
|
||||
u = u[self.survey.srcList, 'phi_sol']
|
||||
f = self.fields(self.curModel)
|
||||
u = f[self.survey.srcList, 'phi_sol']
|
||||
|
||||
D = self.mesh.faceDiv
|
||||
G = self.mesh.cellGrad
|
||||
@@ -251,19 +250,18 @@ class ProblemDC_CC(Problem.BaseProblem):
|
||||
if self.Ainv is None:
|
||||
self.Ainv = self.Solver(dA_du, **self.solverOpts)
|
||||
|
||||
P = self.survey.getP(self.mesh)
|
||||
P = self.survey.getP(self.mesh)
|
||||
Jv = - P * mkvc( self.Ainv * dCdm_x_v )
|
||||
return Jv
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
|
||||
self.curModel = m
|
||||
sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
|
||||
if u is None:
|
||||
# Run forward simulation if $u$ not provided
|
||||
u = self.fields(self.curModel)[self.survey.srcList, 'phi_sol']
|
||||
else:
|
||||
u = u[self.survey.srcList, 'phi_sol']
|
||||
if f is None:
|
||||
# Run forward simulation if $f$ not provided
|
||||
f = self.fields(self.curModel)
|
||||
u = f[self.survey.srcList, 'phi_sol']
|
||||
|
||||
shp = u.shape
|
||||
P = self.survey.getP(self.mesh)
|
||||
|
||||
@@ -14,12 +14,12 @@ class SurveyIP(SurveyDC):
|
||||
Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
self._Ps = {}
|
||||
|
||||
def dpred(self, m, u=None):
|
||||
def dpred(self, m, f=None):
|
||||
"""
|
||||
Predicted data.
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = Pu(m)
|
||||
d_\\text{pred} = Pf(m)
|
||||
"""
|
||||
|
||||
return self.prob.forward(m)
|
||||
@@ -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.csc_matrix
|
||||
:rtype: scipy.sparse.csc_matrix
|
||||
:return: A(m)
|
||||
|
||||
.. math::
|
||||
@@ -143,10 +143,10 @@ class ProblemIP(Problem.BaseProblem):
|
||||
J_x_v = - P * mkvc( self.Ainv * dCdm_x_v )
|
||||
return -J_x_v
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
return self.forward(v)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
|
||||
self.curModel = m
|
||||
# sigma = self.curModel.transform # $\sigma = \mathcal{M}(\m)$
|
||||
|
||||
+324
-215
@@ -1,12 +1,16 @@
|
||||
from SimPEG import np
|
||||
from SimPEG import np, Utils
|
||||
import BaseDC as DC
|
||||
import BaseDC as IP
|
||||
import warnings
|
||||
|
||||
def getActiveindfromTopo(mesh, topo):
|
||||
# def genActiveindfromTopo(mesh, topo):
|
||||
"""
|
||||
Get active indices from topography
|
||||
"""
|
||||
warnings.warn(
|
||||
"`getActiveindfromTopo` is deprecated and will be removed in future versions. Use `SimPEG.Utils.surface2ind_topo` instead",
|
||||
FutureWarning)
|
||||
from scipy.interpolate import NearestNDInterpolator
|
||||
if mesh.dim==3:
|
||||
nCxy = mesh.nCx*mesh.nCy
|
||||
@@ -28,6 +32,9 @@ def gettopoCC(mesh, airind):
|
||||
"""
|
||||
Get topography from active indices of mesh.
|
||||
"""
|
||||
warnings.warn(
|
||||
"`gettopoCC` is deprecated and will be removed in future versions. Use `SimPEG.Utils.surface2ind_topo` instead",
|
||||
FutureWarning)
|
||||
mesh2D = Mesh.TensorMesh([mesh.hx, mesh.hy], mesh.x0[:2])
|
||||
zc = mesh.gridCC[:,2]
|
||||
AIRIND = airind.reshape((mesh.vnC[0]*mesh.vnC[1],mesh.vnC[2]), order='F')
|
||||
@@ -118,34 +125,27 @@ def readUBC_DC3Dobstopo(filename,mesh,topo,probType="CC"):
|
||||
|
||||
def readUBC_DC2DModel(fileName):
|
||||
"""
|
||||
Read UBC GIF 2DTensor model and generate 2D Tensor model in simpeg
|
||||
Read UBC GIF 2DTensor model and generate 2D Tensor model in simpeg
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF 2D model file
|
||||
|
||||
Output:
|
||||
:param SimPEG TensorMesh 2D object
|
||||
:return
|
||||
|
||||
Created on Thu Nov 12 13:14:10 2015
|
||||
|
||||
@author: dominiquef
|
||||
:param string fileName: path to the UBC GIF 2D model file
|
||||
:rtype: TensorMesh
|
||||
:return: SimPEG TensorMesh 2D object
|
||||
|
||||
"""
|
||||
from SimPEG import np, mkvc
|
||||
|
||||
# Open fileand skip header... assume that we know the mesh already
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
|
||||
obsfile = np.genfromtxt(fileName, delimiter=' \n', dtype=np.str, comments='!')
|
||||
|
||||
dim = np.array(obsfile[0].split(),dtype=float)
|
||||
dim = np.array(obsfile[0].split(), dtype=float)
|
||||
|
||||
temp = np.array(obsfile[1].split(),dtype=float)
|
||||
temp = np.array(obsfile[1].split(), dtype=float)
|
||||
|
||||
if len(temp) > 1:
|
||||
model = np.zeros(dim)
|
||||
|
||||
for ii in range(len(obsfile)-1):
|
||||
mm = np.array(obsfile[ii+1].split(),dtype=float)
|
||||
mm = np.array(obsfile[ii+1].split(), dtype=float)
|
||||
model[:,ii] = mm
|
||||
|
||||
model = model[:,::-1]
|
||||
@@ -153,10 +153,10 @@ def readUBC_DC2DModel(fileName):
|
||||
else:
|
||||
|
||||
if len(obsfile[1:])==1:
|
||||
mm = np.array(obsfile[1:].split(),dtype=float)
|
||||
mm = np.array(obsfile[1:].split(), dtype=float)
|
||||
|
||||
else:
|
||||
mm = np.array(obsfile[1:],dtype=float)
|
||||
mm = np.array(obsfile[1:], dtype=float)
|
||||
|
||||
# Permute the second dimension to flip the order
|
||||
model = mm.reshape(dim[1],dim[0])
|
||||
@@ -169,32 +169,25 @@ def readUBC_DC2DModel(fileName):
|
||||
|
||||
return model
|
||||
|
||||
def plot_pseudoSection(DCsurvey, axs, stype):
|
||||
|
||||
def plot_pseudoSection(DCsurvey, axs, surveyType='dipole-dipole', unitType='volt', clim=None, cblabel=True, axlabel = True, colorbar = True, contour = None):
|
||||
"""
|
||||
Read list of 2D tx-rx location and plot a speudo-section of apparent
|
||||
resistivity.
|
||||
Read list of 2D tx-rx location and plot a speudo-section of apparent
|
||||
resistivity.
|
||||
|
||||
Assumes flat topo for now...
|
||||
Assumes flat topo for now...
|
||||
|
||||
Input:
|
||||
:param d2D, z0
|
||||
:switch stype -> Either 'pdp' (pole-dipole) | 'dpdp' (dipole-dipole)
|
||||
|
||||
Output:
|
||||
:figure scatter plot overlayed on image
|
||||
|
||||
Edited Feb 17th, 2016
|
||||
|
||||
@author: dominiquef
|
||||
:param SurveyDC DCsurvey:
|
||||
:param string surveyType: Either 'pole-dipole' | 'dipole-dipole'
|
||||
:param string unitType: Either 'appResistivity' | 'appConductivity' | 'volt'
|
||||
:rtype: matplotlib.plt
|
||||
:return: figure scatter plot overlayed on image
|
||||
|
||||
"""
|
||||
from SimPEG import np
|
||||
from scipy.interpolate import griddata
|
||||
import pylab as plt
|
||||
|
||||
# Set depth to 0 for now
|
||||
z0 = 0.
|
||||
|
||||
# Pre-allocate
|
||||
midx = []
|
||||
midz = []
|
||||
@@ -221,69 +214,117 @@ def plot_pseudoSection(DCsurvey, axs, stype):
|
||||
Cmid = (Tx[0][0] + Tx[1][0])/2
|
||||
Pmid = (Rx[0][:,0] + Rx[1][:,0])/2
|
||||
|
||||
# Compute pant leg of apparent rho
|
||||
if stype == 'pdp':
|
||||
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
|
||||
# Change output for unitType
|
||||
if unitType == 'volt':
|
||||
|
||||
leg = np.log10(abs(1/leg))
|
||||
rho = np.hstack([rho,data])
|
||||
|
||||
elif stype == 'dpdp':
|
||||
leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA )
|
||||
else:
|
||||
|
||||
# Compute pant leg of apparent rho
|
||||
if surveyType == 'pole-dipole':
|
||||
|
||||
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
|
||||
|
||||
elif surveyType == 'dipole-dipole':
|
||||
|
||||
leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA )
|
||||
|
||||
else:
|
||||
print """unitType must be 'pole-dipole' | 'dipole-dipole' """
|
||||
break
|
||||
|
||||
|
||||
if unitType == 'appConductivity':
|
||||
|
||||
leg = np.log10(abs(1./leg))
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
elif unitType == 'appResistivity':
|
||||
|
||||
leg = np.log10(abs(leg))
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
else:
|
||||
print """unitType must be 'appResistivity' | 'appConductivity' | 'volt' """
|
||||
break
|
||||
|
||||
midx = np.hstack([midx, ( Cmid + Pmid )/2 ])
|
||||
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ])
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
|
||||
ax = axs
|
||||
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + (Tx[0][2] + Tx[1][2])/2 ])
|
||||
|
||||
# Grid points
|
||||
grid_x, grid_z = np.mgrid[np.min(midx):np.max(midx), np.min(midz):np.max(midz)]
|
||||
grid_rho = griddata(np.c_[midx,midz], rho.T, (grid_x, grid_z), method='linear')
|
||||
|
||||
# Scale the color scheme
|
||||
if clim == None:
|
||||
vmin, vmax = rho.min(), rho.max()
|
||||
else:
|
||||
vmin, vmax = clim[0], clim[1]
|
||||
|
||||
plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin = np.min(rho), vmax = np.max(rho))
|
||||
cbar = plt.colorbar(format = '%.2f',fraction=0.04,orientation="horizontal")
|
||||
# Plot data
|
||||
grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho)
|
||||
|
||||
cmin,cmax = cbar.get_clim()
|
||||
ticks = np.linspace(cmin,cmax,3)
|
||||
cbar.set_ticks(ticks)
|
||||
|
||||
# Plot apparent resistivity
|
||||
plt.scatter(midx,midz,s=50,c=rho.T)
|
||||
|
||||
ax.set_xticklabels([])
|
||||
ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, vmin = vmin, vmax = vmax)
|
||||
plt.gca().tick_params(axis='both', which='major', labelsize=8)
|
||||
|
||||
if contour is not None:
|
||||
plt.contour(grid_x,grid_z,grid_rho,levels = contour,colors = 'r', vmin = vmin, vmax = vmax)
|
||||
|
||||
# Add scatter points
|
||||
axs.scatter(midx,midz,s=10,c=rho.T, vmin = vmin, vmax = vmax)
|
||||
|
||||
if colorbar:
|
||||
|
||||
if unitType == 'volt':
|
||||
cbar = plt.colorbar(ph, ax = axs, format="%4.1f",fraction=0.04,orientation="horizontal")
|
||||
|
||||
else:
|
||||
cbar = plt.colorbar(ph, ax = axs, format="$10^{%.1f}$",fraction=0.04,orientation="horizontal")
|
||||
|
||||
cmin,cmax = cbar.get_clim()
|
||||
ticks = np.linspace(cmin,cmax,3)
|
||||
cbar.set_ticks(ticks)
|
||||
cbar.ax.tick_params(labelsize=10)
|
||||
|
||||
if unitType == 'appConductivity':
|
||||
cbar.set_label("App.Cond",size=12)
|
||||
elif unitType == 'appResistivity':
|
||||
cbar.set_label("App.Res.",size=12)
|
||||
elif unitType == 'volt':
|
||||
cbar.set_label("Potential (V)",size=12)
|
||||
|
||||
|
||||
if not axlabel:
|
||||
axs.set_xticklabels([])
|
||||
axs.set_yticklabels([])
|
||||
|
||||
ax.set_ylabel('Z')
|
||||
ax.yaxis.tick_right()
|
||||
ax.yaxis.set_label_position('right')
|
||||
plt.gca().set_aspect('equal', adjustable='box')
|
||||
|
||||
|
||||
return ax
|
||||
|
||||
def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
return ph
|
||||
|
||||
def gen_DCIPsurvey(endl, mesh, surveyType, AM_sep, MN_sep, nrx):
|
||||
"""
|
||||
Load in endpoints and survey specifications to generate Tx, Rx location
|
||||
stations.
|
||||
Load in endpoints and survey specifications to generate Tx, Rx location
|
||||
stations.
|
||||
|
||||
Assumes flat topo for now...
|
||||
Assumes flat topo for now...
|
||||
|
||||
Input:
|
||||
:param endl -> input endpoints [x1, y1, z1, x2, y2, z2]
|
||||
:object mesh -> SimPEG mesh object
|
||||
:switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient'
|
||||
: param a, n -> pole seperation, number of rx dipoles per tx
|
||||
:param numpy.array endl: input endpoints [[x1, y1] , [x2, y2]]
|
||||
:param Mesh mesh: SimPEG mesh object
|
||||
:param string surveyType: 'dipole-dipole' | 'pole-dipole' | 'gradient'
|
||||
:param float AM_sep: transmitter (A) - receiver (M) seperation
|
||||
:param float b: receiver dipole seperation
|
||||
:param float nrx: pole seperation, number of rx dipoles per tx
|
||||
|
||||
Output:
|
||||
:param Tx, Rx -> List objects for each tx location
|
||||
Lines: P1x, P1y, P1z, P2x, P2y, P2z
|
||||
:rtype: DC.Survey, Src, Rx
|
||||
:returns: DC survey, Source
|
||||
|
||||
Created on Wed December 9th, 2015
|
||||
|
||||
@author: dominiquef
|
||||
!! Require clean up to deal with DCsurvey
|
||||
!! Require clean up to deal with DCsurvey
|
||||
"""
|
||||
|
||||
from SimPEG import np
|
||||
@@ -299,17 +340,17 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
dl_x = ( endl[1,0] - endl[0,0] ) / dl_len
|
||||
dl_y = ( endl[1,1] - endl[0,1] ) / dl_len
|
||||
|
||||
nstn = np.floor( dl_len / a )
|
||||
nstn = np.floor( dl_len / AM_sep )
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a
|
||||
stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*AM_sep
|
||||
stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*AM_sep
|
||||
|
||||
# Create line of P1 locations
|
||||
M = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
# Create line of P2 locations
|
||||
N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
N = np.c_[stn_x+AM_sep*dl_x, stn_y+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
## Build list of Tx-Rx locations depending on survey type
|
||||
# Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn]
|
||||
@@ -319,14 +360,14 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
SrcList = []
|
||||
|
||||
|
||||
if stype != 'gradient':
|
||||
if surveyType != 'gradient':
|
||||
|
||||
for ii in range(0, int(nstn)-1):
|
||||
|
||||
|
||||
if stype == 'dpdp':
|
||||
if surveyType == 'dipole-dipole':
|
||||
tx = np.c_[M[ii,:],N[ii,:]]
|
||||
elif stype == 'pdp':
|
||||
elif surveyType == 'pole-dipole':
|
||||
tx = np.c_[M[ii,:],M[ii,:]]
|
||||
|
||||
# Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]])
|
||||
@@ -335,43 +376,33 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1])
|
||||
|
||||
# Number of receivers to fit
|
||||
nstn = np.min([np.floor( (AB - b) / a ) , n])
|
||||
nstn = np.min([np.floor( (AB - MN_sep) / AM_sep ) , nrx])
|
||||
|
||||
# Check if there is enough space, else break the loop
|
||||
if nstn <= 0:
|
||||
continue
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a
|
||||
stn_x = N[ii,0] + dl_x*MN_sep + np.array(range(int(nstn)))*dl_x*AM_sep
|
||||
stn_y = N[ii,1] + dl_y*MN_sep + np.array(range(int(nstn)))*dl_y*AM_sep
|
||||
|
||||
# Create receiver poles
|
||||
# Create line of P1 locations
|
||||
P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
# Create line of P2 locations
|
||||
P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
P2 = np.c_[stn_x+AM_sep*dl_x, stn_y+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
Rx.append(np.c_[P1,P2])
|
||||
rxClass = DC.RxDipole(P1, P2)
|
||||
Tx.append(tx)
|
||||
if stype == 'dpdp':
|
||||
if surveyType == 'dipole-dipole':
|
||||
srcClass = DC.SrcDipole([rxClass], M[ii,:],N[ii,:])
|
||||
elif stype == 'pdp':
|
||||
elif surveyType == 'pole-dipole':
|
||||
srcClass = DC.SrcDipole([rxClass], M[ii,:],M[ii,:])
|
||||
SrcList.append(srcClass)
|
||||
|
||||
#==============================================================================
|
||||
# elif re.match(stype,'dpdp'):
|
||||
#
|
||||
# for ii in range(0, int(nstn)-2):
|
||||
#
|
||||
# indx = np.min([ii+n+1,nstn])
|
||||
# Tx.append(np.c_[M[ii,:],N[ii,:]])
|
||||
# Rx.append(np.c_[M[ii+2:indx,:],N[ii+2:indx,:]])
|
||||
#==============================================================================
|
||||
|
||||
elif stype == 'gradient':
|
||||
elif surveyType == 'gradient':
|
||||
|
||||
# Gradient survey only requires Tx at end of line and creates a square
|
||||
# grid of receivers at in the middle at a pre-set minimum distance
|
||||
@@ -379,23 +410,23 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
Tx.append(np.c_[M[0,:],N[-1,:]])
|
||||
|
||||
# Get the edge limit of survey area
|
||||
min_x = endl[0,0] + dl_x * b
|
||||
min_y = endl[0,1] + dl_y * b
|
||||
min_x = endl[0,0] + dl_x * MN_sep
|
||||
min_y = endl[0,1] + dl_y * MN_sep
|
||||
|
||||
max_x = endl[1,0] - dl_x * b
|
||||
max_y = endl[1,1] - dl_y * b
|
||||
max_x = endl[1,0] - dl_x * MN_sep
|
||||
max_y = endl[1,1] - dl_y * MN_sep
|
||||
|
||||
box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 )
|
||||
box_w = box_l/2.
|
||||
|
||||
nstn = np.floor( box_l / a )
|
||||
nstn = np.floor( box_l / AM_sep )
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = min_x + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = min_y + np.array(range(int(nstn)))*dl_y*a
|
||||
stn_x = min_x + np.array(range(int(nstn)))*dl_x*AM_sep
|
||||
stn_y = min_y + np.array(range(int(nstn)))*dl_y*AM_sep
|
||||
|
||||
# Define number of cross lines
|
||||
nlin = int(np.floor( box_w / a ))
|
||||
nlin = int(np.floor( box_w / AM_sep ))
|
||||
lind = range(-nlin,nlin+1)
|
||||
|
||||
ngrad = nstn * len(lind)
|
||||
@@ -404,12 +435,12 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
for ii in range( len(lind) ):
|
||||
|
||||
# Move line in perpendicular direction by dipole spacing
|
||||
lxx = stn_x - lind[ii]*a*dl_y
|
||||
lyy = stn_y + lind[ii]*a*dl_x
|
||||
lxx = stn_x - lind[ii]*AM_sep*dl_y
|
||||
lyy = stn_y + lind[ii]*AM_sep*dl_x
|
||||
|
||||
|
||||
M = np.c_[ lxx, lyy , np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
N = np.c_[ lxx+AM_sep*dl_x, lyy+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
|
||||
|
||||
rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N]
|
||||
|
||||
@@ -418,37 +449,37 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
srcClass = DC.SrcDipole([rxClass], M[0,:], N[-1,:])
|
||||
SrcList.append(srcClass)
|
||||
else:
|
||||
print """stype must be either 'pdp', 'dpdp' or 'gradient'. """
|
||||
print """surveyType must be either 'pole-dipole', 'dipole-dipole' or 'gradient'. """
|
||||
|
||||
survey = DC.SurveyDC(SrcList)
|
||||
return survey, Tx, Rx
|
||||
|
||||
def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
|
||||
|
||||
def writeUBC_DCobs(fileName, DCsurvey, dim, surveyType, iptype = 0):
|
||||
"""
|
||||
Write UBC GIF DCIP 2D or 3D observation file
|
||||
|
||||
Input:
|
||||
:string fileName -> including path where the file is written out
|
||||
:DCsurvey -> DC survey class object
|
||||
:string dtype -> either '2D' | '3D'
|
||||
:string stype -> either 'SURFACE' | 'GENERAL'
|
||||
|
||||
Output:
|
||||
:param UBC2D-Data file
|
||||
:return
|
||||
|
||||
Last edit: February 16th, 2016
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
:param string fileName: including path where the file is written out
|
||||
:param Survey DCsurvey: DC survey class object
|
||||
:param string dim: either '2D' | '3D'
|
||||
:param string surveyType: either 'SURFACE' | 'GENERAL'
|
||||
:rtype: file
|
||||
:return: UBC2D-Data file
|
||||
"""
|
||||
|
||||
from SimPEG import mkvc
|
||||
|
||||
assert (dtype=='2D') | (dtype=='3D'), "Data must be either '2D' | '3D'"
|
||||
assert (stype=='SURFACE') | (stype=='GENERAL') | (stype=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'"
|
||||
assert (dim=='2D') | (dim=='3D'), "Data must be either '2D' | '3D'"
|
||||
assert (surveyType=='SURFACE') | (surveyType=='GENERAL') | (surveyType=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'"
|
||||
|
||||
fid = open(fileName,'w')
|
||||
fid.write('! ' + stype + ' FORMAT\n')
|
||||
fid.write('! ' + surveyType + ' FORMAT\n')
|
||||
|
||||
if iptype!=0:
|
||||
fid.write('IPTYPE=%i\n'%iptype)
|
||||
|
||||
else:
|
||||
fid.write('! ' + stype + ' FORMAT\n')
|
||||
|
||||
count = 0
|
||||
|
||||
@@ -463,10 +494,10 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
|
||||
M = rx[0]
|
||||
N = rx[1]
|
||||
|
||||
# Adapt source-receiver location for dtype and stype
|
||||
if dtype=='2D':
|
||||
# Adapt source-receiver location for dim and surveyType
|
||||
if dim=='2D':
|
||||
|
||||
if stype == 'SIMPLE':
|
||||
if surveyType == 'SIMPLE':
|
||||
|
||||
#fid.writelines("%e " % ii for ii in mkvc(tx[0,:]))
|
||||
A = np.repeat(tx[0,0],M.shape[0],axis=0)
|
||||
@@ -479,58 +510,60 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
|
||||
|
||||
else:
|
||||
|
||||
if stype == 'SURFACE':
|
||||
if surveyType == 'SURFACE':
|
||||
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx[0,:]))
|
||||
fid.writelines("%f " % ii for ii in mkvc(tx[0,:]))
|
||||
M = M[:,0]
|
||||
N = N[:,0]
|
||||
|
||||
if stype == 'GENERAL':
|
||||
if surveyType == 'GENERAL':
|
||||
|
||||
# Flip sign for z-elevation to depth
|
||||
tx[2::2,:] = -tx[2::2,:]
|
||||
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx[::2,:]))
|
||||
M = M[:,0::2]
|
||||
N = N[:,0::2]
|
||||
|
||||
# Flip sign for z-elevation to depth
|
||||
M[:,1::2] = -M[:,1::2]
|
||||
N[:,1::2] = -N[:,1::2]
|
||||
|
||||
fid.write('%i\n'% nD)
|
||||
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n')
|
||||
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%f',delimiter=' ',newline='\n')
|
||||
|
||||
if dtype=='3D':
|
||||
if dim=='3D':
|
||||
|
||||
if stype == 'SURFACE':
|
||||
if surveyType == 'SURFACE':
|
||||
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx[0:2,:]))
|
||||
M = M[:,0:2]
|
||||
N = N[:,0:2]
|
||||
|
||||
if stype == 'GENERAL':
|
||||
if surveyType == 'GENERAL':
|
||||
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx))
|
||||
fid.writelines("%e " % ii for ii in mkvc(tx[0:3,:]))
|
||||
|
||||
fid.write('%i\n'% nD)
|
||||
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n')
|
||||
fid.write('\n')
|
||||
|
||||
count += nD
|
||||
|
||||
fid.close()
|
||||
|
||||
def convertObs_DC3D_to_2D(DCsurvey,lineID):
|
||||
def convertObs_DC3D_to_2D(DCsurvey, lineID, flag='local'):
|
||||
"""
|
||||
Read DC survey and data and change
|
||||
coordinate system to distance along line assuming
|
||||
all data is acquired along line.
|
||||
First transmitter pole is assumed to be at the origin
|
||||
Read DC survey and projects the coordinate system
|
||||
according to the flag = 'Xloc' | 'Yloc' | 'local' (default)
|
||||
In the 'local' system, station coordinates are referenced
|
||||
to distance from the first srcLoc[0].loc[0]
|
||||
|
||||
Assumes flat topo for now...
|
||||
The Z value is preserved, but Y coordinates zeroed.
|
||||
|
||||
Input:
|
||||
:param Tx, Rx
|
||||
|
||||
Output:
|
||||
:figure Tx2d, Rx2d
|
||||
|
||||
Edited Feb 17th, 2016
|
||||
|
||||
@author: dominiquef
|
||||
:param DC.Survey survey3D: 3D simpeg DC survey
|
||||
:rtype: DC.Survey
|
||||
:return: survey2D
|
||||
|
||||
"""
|
||||
from SimPEG import np
|
||||
@@ -570,25 +603,39 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID):
|
||||
Rx = DCsurvey.srcList[indx[ii]].rxList[0].locs
|
||||
nrx = Rx[0].shape[0]
|
||||
|
||||
# Find A electrode along line
|
||||
vec, r = r_unit(x0,Tx[ii][0,0:2])
|
||||
A = stn_id(vecTx,vec,r)
|
||||
if flag == 'local':
|
||||
# Find A electrode along line
|
||||
vec, r = r_unit(x0,Tx[ii][0,0:2])
|
||||
A = stn_id(vecTx,vec,r)
|
||||
|
||||
# Find B electrode along line
|
||||
vec, r = r_unit(x0,Tx[ii][1,0:2])
|
||||
B = stn_id(vecTx,vec,r)
|
||||
# Find B electrode along line
|
||||
vec, r = r_unit(x0,Tx[ii][1,0:2])
|
||||
B = stn_id(vecTx,vec,r)
|
||||
|
||||
M = np.zeros(nrx)
|
||||
N = np.zeros(nrx)
|
||||
for kk in range(nrx):
|
||||
M = np.zeros(nrx)
|
||||
N = np.zeros(nrx)
|
||||
for kk in range(nrx):
|
||||
|
||||
# Find all M electrodes along line
|
||||
vec, r = r_unit(x0,Rx[0][kk,0:2])
|
||||
M[kk] = stn_id(vecTx,vec,r)
|
||||
# Find all M electrodes along line
|
||||
vec, r = r_unit(x0,Rx[0][kk,0:2])
|
||||
M[kk] = stn_id(vecTx,vec,r)
|
||||
|
||||
# Find all N electrodes along line
|
||||
vec, r = r_unit(x0,Rx[1][kk,0:2])
|
||||
N[kk] = stn_id(vecTx,vec,r)
|
||||
# Find all N electrodes along line
|
||||
vec, r = r_unit(x0,Rx[1][kk,0:2])
|
||||
N[kk] = stn_id(vecTx,vec,r)
|
||||
elif flag == 'Yloc':
|
||||
""" Flip the XY axis locs"""
|
||||
A = Tx[ii][0,1]
|
||||
B = Tx[ii][1,1]
|
||||
M = Rx[0][:,1]
|
||||
N = Rx[1][:,1]
|
||||
|
||||
elif flag == 'Xloc':
|
||||
""" Copy the rx-tx locs"""
|
||||
A = Tx[ii][0,0]
|
||||
B = Tx[ii][1,0]
|
||||
M = Rx[0][:,0]
|
||||
N = Rx[1][:,0]
|
||||
|
||||
Rx = DC.RxDipole(np.c_[M,np.zeros(nrx),Rx[0][:,2]],np.c_[N,np.zeros(nrx),Rx[1][:,2]])
|
||||
|
||||
@@ -602,50 +649,53 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID):
|
||||
|
||||
return DCsurvey2D
|
||||
|
||||
def readUBC_DC3Dobs(fileName):
|
||||
def readUBC_DC3Dobs(fileName, rtype = 'DC'):
|
||||
"""
|
||||
Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location
|
||||
Read UBC GIF IP 3D observation file and generate survey
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF 3D obs file
|
||||
|
||||
Output:
|
||||
:param rx, tx, d, wd
|
||||
:return
|
||||
|
||||
Created on Mon December 7th, 2015
|
||||
|
||||
@author: dominiquef
|
||||
:param string fileName:, path to the UBC GIF 3D obs file
|
||||
:rtype: Survey
|
||||
:return: DCIPsurvey
|
||||
|
||||
"""
|
||||
zflag = True # Flag for z value provided
|
||||
|
||||
# Load file
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
|
||||
if rtype == 'IP':
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='IPTYPE')
|
||||
|
||||
elif rtype == 'DC':
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
|
||||
|
||||
else:
|
||||
print "rtype must be 'DC'(default) | 'IP'"
|
||||
|
||||
# Pre-allocate
|
||||
srcLists = []
|
||||
Rx = []
|
||||
d = []
|
||||
wd = []
|
||||
zflag = True # Flag for z value provided
|
||||
|
||||
|
||||
# Countdown for number of obs/tx
|
||||
count = 0
|
||||
for ii in range(obsfile.shape[0]):
|
||||
|
||||
# Skip if blank line
|
||||
if not obsfile[ii]:
|
||||
continue
|
||||
|
||||
# First line is transmitter with number of receivers
|
||||
# First line or end of a transmitter block, read transmitter info
|
||||
if count==0:
|
||||
|
||||
temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T)
|
||||
# Read the line
|
||||
temp = (np.fromstring(obsfile[ii], dtype=float, sep=' ').T)
|
||||
count = int(temp[-1])
|
||||
|
||||
# Check if z value is provided, if False -> nan
|
||||
if len(temp)==5:
|
||||
tx = np.r_[temp[0:2],np.nan,temp[0:2],np.nan]
|
||||
zflag = False
|
||||
tx = np.r_[temp[0:2],np.nan,temp[2:4],np.nan]
|
||||
|
||||
zflag = False # Pass on the flag to the receiver loc
|
||||
|
||||
else:
|
||||
tx = temp[:-1]
|
||||
@@ -653,8 +703,16 @@ def readUBC_DC3Dobs(fileName):
|
||||
rx = []
|
||||
continue
|
||||
|
||||
temp = np.fromstring(obsfile[ii], dtype=float,sep=' ')
|
||||
temp = np.fromstring(obsfile[ii], dtype=float,sep=' ') # Get the string
|
||||
|
||||
# Filter out negative IP
|
||||
# if temp[-2] < 0:
|
||||
# count = count -1
|
||||
# print "Negative!"
|
||||
#
|
||||
# else:
|
||||
|
||||
# If the Z-location is provided, otherwise put nan
|
||||
if zflag:
|
||||
|
||||
rx.append(temp[:-2])
|
||||
@@ -664,7 +722,7 @@ def readUBC_DC3Dobs(fileName):
|
||||
wd.append(temp[-1])
|
||||
|
||||
else:
|
||||
rx.append(np.r_[temp[0:2],np.nan,temp[0:2],np.nan] )
|
||||
rx.append(np.r_[temp[0:2],np.nan,temp[2:4],np.nan] )
|
||||
# Check if there is data with the location
|
||||
if len(temp)==6:
|
||||
d.append(temp[-2])
|
||||
@@ -672,7 +730,7 @@ def readUBC_DC3Dobs(fileName):
|
||||
|
||||
count = count -1
|
||||
|
||||
# Reach the end of transmitter block
|
||||
# Reach the end of transmitter block, append the src, rx and continue
|
||||
if count == 0:
|
||||
rx = np.asarray(rx)
|
||||
Rx = DC.RxDipole(rx[:,:3],rx[:,3:])
|
||||
@@ -688,19 +746,12 @@ def readUBC_DC3Dobs(fileName):
|
||||
|
||||
def readUBC_DC2Dobs(fileName):
|
||||
"""
|
||||
------- NEEDS TO BE UPDATED ------
|
||||
Read UBC GIF 2D observation file and generate arrays for tx-rx location
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF 2D model file
|
||||
|
||||
Output:
|
||||
:param rx, tx
|
||||
:return
|
||||
|
||||
Created on Thu Nov 12 13:14:10 2015
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
:param string fileName: path to the UBC GIF 2D model file
|
||||
:rtype: (DC.Src, DC.Rx, ??, ??)
|
||||
:return: source_locs, rx_locs, ??, ??
|
||||
"""
|
||||
|
||||
from SimPEG import np
|
||||
@@ -735,16 +786,78 @@ def readUBC_DC2Dobs(fileName):
|
||||
|
||||
return tx, rx, d, wd
|
||||
|
||||
def readUBC_DC2Dpre(fileName):
|
||||
"""
|
||||
Read UBC GIF DCIP 2D observation file and generate arrays for tx-rx location
|
||||
|
||||
Input:
|
||||
:param string fileName: path to the UBC GIF 3D obs file
|
||||
:rtype: DC.Survey
|
||||
:return: DCsurvey
|
||||
|
||||
Created on Mon March 9th, 2016 << Doug's 70th Birthday !! >>
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
"""
|
||||
|
||||
# Load file
|
||||
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
|
||||
|
||||
# Pre-allocate
|
||||
srcLists = []
|
||||
Rx = []
|
||||
d = []
|
||||
zflag = True # Flag for z value provided
|
||||
|
||||
for ii in range(obsfile.shape[0]):
|
||||
|
||||
if not obsfile[ii]:
|
||||
continue
|
||||
|
||||
# First line is transmitter with number of receivers
|
||||
|
||||
|
||||
temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T)
|
||||
|
||||
|
||||
# Check if z value is provided, if False -> nan
|
||||
if len(temp)==5:
|
||||
tx = np.r_[temp[0],np.nan,np.nan,temp[1],np.nan,np.nan]
|
||||
zflag = False
|
||||
|
||||
else:
|
||||
tx = np.r_[temp[0],np.nan,temp[1],temp[2],np.nan,temp[3]]
|
||||
|
||||
|
||||
if zflag:
|
||||
rx = np.c_[temp[4],np.nan,temp[5],temp[6],np.nan,temp[7]]
|
||||
|
||||
|
||||
else:
|
||||
rx = np.c_[temp[2],np.nan,np.nan,temp[3],np.nan,np.nan]
|
||||
# Check if there is data with the location
|
||||
|
||||
d.append(temp[-1])
|
||||
|
||||
|
||||
Rx = DC.RxDipole(rx[:,:3],rx[:,3:])
|
||||
srcLists.append( DC.SrcDipole( [Rx], tx[:3],tx[3:]) )
|
||||
|
||||
# Create survey class
|
||||
survey = DC.SurveyDC(srcLists)
|
||||
|
||||
survey.dobs = np.asarray(d)
|
||||
|
||||
return {'DCsurvey':survey}
|
||||
|
||||
def readUBC_DC2DMesh(fileName):
|
||||
"""
|
||||
Read UBC GIF 2DTensor mesh and generate 2D Tensor mesh in simpeg
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF mesh file
|
||||
|
||||
Output:
|
||||
:param SimPEG TensorMesh 2D object
|
||||
:return
|
||||
:param string fileName: path to the UBC GIF mesh file
|
||||
:rtype: Mesh.TensorMesh
|
||||
:return: SimPEG TensorMesh 2D object
|
||||
|
||||
Created on Thu Nov 12 13:14:10 2015
|
||||
|
||||
@@ -810,12 +923,9 @@ def xy_2_lineID(DCsurvey):
|
||||
they were collected. May need to generalize for random
|
||||
point locations, but will be more expensive
|
||||
|
||||
Input:
|
||||
:param DCdict Vectors of station location
|
||||
|
||||
Output:
|
||||
:param LineID Vector of integers
|
||||
:return
|
||||
:param numpy.array DCdict: Vectors of station location
|
||||
:rtype: numpy.array
|
||||
:return: LineID Vector of integers
|
||||
|
||||
Created on Thu Feb 11, 2015
|
||||
|
||||
@@ -928,7 +1038,6 @@ def getSrc_locs(DCsurvey):
|
||||
|
||||
srcMat = np.zeros((DCsurvey.nSrc,2,3))
|
||||
for ii in range(DCsurvey.nSrc):
|
||||
print np.asarray(DCsurvey.srcList[ii].loc).shape
|
||||
srcMat[ii,:,:] = np.asarray(DCsurvey.srcList[ii].loc)
|
||||
|
||||
return srcMat
|
||||
|
||||
+22
-26
@@ -22,11 +22,11 @@ class BaseDataMisfit(object):
|
||||
Utils.setKwargs(self,**kwargs)
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m, u=None):
|
||||
"""eval(m, u=None)
|
||||
def eval(self, m, f=None):
|
||||
"""eval(m, f=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: float
|
||||
:return: data misfit
|
||||
|
||||
@@ -34,11 +34,11 @@ class BaseDataMisfit(object):
|
||||
raise NotImplementedError('This method should be overwritten.')
|
||||
|
||||
@Utils.timeIt
|
||||
def evalDeriv(self, m, u=None):
|
||||
"""evalDeriv(m, u=None)
|
||||
def evalDeriv(self, m, f=None):
|
||||
"""evalDeriv(m, f=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: data misfit derivative
|
||||
|
||||
@@ -47,12 +47,12 @@ class BaseDataMisfit(object):
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def eval2Deriv(self, m, v, u=None):
|
||||
"""eval2Deriv(m, v, u=None)
|
||||
def eval2Deriv(self, m, v, f=None):
|
||||
"""eval2Deriv(m, v, f=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: data misfit derivative
|
||||
|
||||
@@ -89,7 +89,7 @@ class l2_DataMisfit(BaseDataMisfit):
|
||||
"""
|
||||
|
||||
if getattr(self, '_Wd', None) is None:
|
||||
|
||||
|
||||
survey = self.survey
|
||||
|
||||
if getattr(survey,'std', None) is None:
|
||||
@@ -108,24 +108,20 @@ class l2_DataMisfit(BaseDataMisfit):
|
||||
self._Wd = value
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m, u=None):
|
||||
"eval(m, u=None)"
|
||||
prob = self.prob
|
||||
survey = self.survey
|
||||
R = self.Wd * survey.residual(m, u=u)
|
||||
def eval(self, m, f=None):
|
||||
"eval(m, f=None)"
|
||||
if f is None: f = self.prob.fields(m)
|
||||
R = self.Wd * self.survey.residual(m, f)
|
||||
return 0.5*np.vdot(R, R)
|
||||
|
||||
@Utils.timeIt
|
||||
def evalDeriv(self, m, u=None):
|
||||
"evalDeriv(m, u=None)"
|
||||
prob = self.prob
|
||||
survey = self.survey
|
||||
if u is None: u = prob.fields(m)
|
||||
return prob.Jtvec(m, self.Wd * (self.Wd * survey.residual(m, u=u)), u=u)
|
||||
def evalDeriv(self, m, f=None):
|
||||
"evalDeriv(m, f=None)"
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return self.prob.Jtvec(m, self.Wd * (self.Wd * self.survey.residual(m, f=f)), f=f)
|
||||
|
||||
@Utils.timeIt
|
||||
def eval2Deriv(self, m, v, u=None):
|
||||
"eval2Deriv(m, v, u=None)"
|
||||
prob = self.prob
|
||||
if u is None: u = prob.fields(m)
|
||||
return prob.Jtvec_approx(m, self.Wd * (self.Wd * prob.Jvec_approx(m, v, u=u)), u=u)
|
||||
def eval2Deriv(self, m, v, f=None):
|
||||
"eval2Deriv(m, v, f=None)"
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return self.prob.Jtvec_approx(m, self.Wd * (self.Wd * self.prob.Jvec_approx(m, v, f=f)), f=f)
|
||||
|
||||
+216
-49
@@ -123,10 +123,10 @@ class BetaEstimate_ByEig(InversionDirective):
|
||||
if self.debug: print 'Calculating the beta0 parameter.'
|
||||
|
||||
m = self.invProb.curModel
|
||||
u = self.invProb.getFields(m, store=True, deleteWarmstart=False)
|
||||
f = self.invProb.getFields(m, store=True, deleteWarmstart=False)
|
||||
|
||||
x0 = np.random.rand(*m.shape)
|
||||
t = x0.dot(self.dmisfit.eval2Deriv(m,x0,u=u))
|
||||
t = x0.dot(self.dmisfit.eval2Deriv(m,x0,f=f))
|
||||
b = x0.dot(self.reg.eval2Deriv(m, v=x0))
|
||||
self.beta0 = self.beta0_ratio*(t/b)
|
||||
|
||||
@@ -144,12 +144,18 @@ class BetaSchedule(InversionDirective):
|
||||
if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter
|
||||
self.invProb.beta /= self.coolingFactor
|
||||
|
||||
|
||||
class TargetMisfit(InversionDirective):
|
||||
|
||||
chifact = 1.
|
||||
phi_d_star = None
|
||||
|
||||
@property
|
||||
def target(self):
|
||||
if getattr(self, '_target', None) is None:
|
||||
self._target = self.survey.nD*0.5
|
||||
if self.phi_d_star is None:
|
||||
self.phi_d_star = 0.5 * self.survey.nD
|
||||
self._target = self.chifact * self.phi_d_star # the factor of 0.5 is because we do phid = 0.5*|| dpred - dobs||^2
|
||||
return self._target
|
||||
@target.setter
|
||||
def target(self, val):
|
||||
@@ -161,7 +167,7 @@ class TargetMisfit(InversionDirective):
|
||||
|
||||
|
||||
|
||||
class _SaveEveryIteration(InversionDirective):
|
||||
class SaveEveryIteration(InversionDirective):
|
||||
@property
|
||||
def name(self):
|
||||
if getattr(self, '_name', None) is None:
|
||||
@@ -182,7 +188,7 @@ class _SaveEveryIteration(InversionDirective):
|
||||
self._fileName = value
|
||||
|
||||
|
||||
class SaveModelEveryIteration(_SaveEveryIteration):
|
||||
class SaveModelEveryIteration(SaveEveryIteration):
|
||||
"""SaveModelEveryIteration"""
|
||||
|
||||
def initialize(self):
|
||||
@@ -192,7 +198,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):
|
||||
@@ -206,7 +212,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):
|
||||
@@ -216,13 +222,13 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration):
|
||||
# Save the data.
|
||||
ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) )
|
||||
phi_ms = 0.5*ms.dot(ms)
|
||||
if self.reg.smoothModel == True:
|
||||
if self.reg.mrefInSmooth == True:
|
||||
mref = self.reg.mref
|
||||
else:
|
||||
mref = 0
|
||||
mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_mx = 0.5 * mx.dot(mx)
|
||||
if self.prob.mesh.dim==2:
|
||||
if self.prob.mesh.dim >= 2:
|
||||
my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_my = 0.5 * my.dot(my)
|
||||
else:
|
||||
@@ -237,49 +243,210 @@ 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 SaveOutputDictEveryIteration(_SaveEveryIteration):
|
||||
"""SaveOutputDictEveryIteration
|
||||
A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info).
|
||||
"""
|
||||
|
||||
def initialize(self):
|
||||
print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName
|
||||
|
||||
def endIter(self):
|
||||
# Save the data.
|
||||
ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) )
|
||||
phi_ms = 0.5*ms.dot(ms)
|
||||
if self.reg.smoothModel == True:
|
||||
mref = self.reg.mref
|
||||
else:
|
||||
mref = 0
|
||||
mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_mx = 0.5 * mx.dot(mx)
|
||||
if self.prob.mesh.dim==2:
|
||||
my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_my = 0.5 * my.dot(my)
|
||||
else:
|
||||
phi_my = 'NaN'
|
||||
if self.prob.mesh.dim==3 and 'CYL' not in self.prob.mesh._meshType:
|
||||
mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) )
|
||||
phi_mz = 0.5 * mz.dot(mz)
|
||||
else:
|
||||
phi_mz = 'NaN'
|
||||
|
||||
|
||||
# Save the file as a npz
|
||||
np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred)
|
||||
|
||||
|
||||
|
||||
# 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'
|
||||
# mref = self.mref0
|
||||
# self.m_prev = self.invProb.m_current
|
||||
# return mref
|
||||
|
||||
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.]
|
||||
|
||||
def endIter(self):
|
||||
|
||||
# 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, 'reg.eps', None) is None:
|
||||
self.reg.eps_p = np.percentile(np.abs(self.invProb.curModel),self.prctile)
|
||||
else:
|
||||
self.reg.eps_p = self.eps[0]
|
||||
|
||||
if getattr(self, 'reg.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]
|
||||
|
||||
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)
|
||||
|
||||
self.reg.norms = self.norms
|
||||
self.coolingFactor = 1.
|
||||
self.coolingRate = 1
|
||||
self.iterStart = self.opt.iter
|
||||
self.phi_d_last = self.invProb.phi_d
|
||||
self.phi_m_last = self.invProb.phi_m_last
|
||||
|
||||
self.reg.l2model = self.invProb.curModel
|
||||
self.reg.curModel = self.invProb.curModel
|
||||
|
||||
if getattr(self, 'f_old', None) is None:
|
||||
self.f_old = self.reg.eval(self.invProb.curModel)#self.invProb.evalFunction(self.invProb.curModel, return_g=False, return_H=False)
|
||||
|
||||
# Beta Schedule
|
||||
if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0:
|
||||
if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter
|
||||
self.invProb.beta /= self.coolingFactor
|
||||
|
||||
|
||||
# Only update after GN iterations
|
||||
if (self.opt.iter-self.iterStart) % self.minGNiter == 0 and self.mode==2:
|
||||
|
||||
self.IRLSiter += 1
|
||||
|
||||
phim_new = self.reg.eval(self.invProb.curModel)
|
||||
self.f_change = np.abs(self.f_old - phim_new) / self.f_old
|
||||
|
||||
print "Regularization decrease: %6.3e" % (self.f_change)
|
||||
|
||||
# Check for maximum number of IRLS cycles
|
||||
if self.IRLSiter == self.maxIRLSiter:
|
||||
print "Reach maximum number of IRLS cycles: %i" % self.maxIRLSiter
|
||||
self.opt.stopNextIteration = True
|
||||
return
|
||||
|
||||
# Check if the function has changed enough
|
||||
if self.f_change < self.f_min_change and self.IRLSiter > 1:
|
||||
print "Minimum decrease in regularization. End of IRLS"
|
||||
self.opt.stopNextIteration = True
|
||||
return
|
||||
else:
|
||||
self.f_old = phim_new
|
||||
|
||||
# # Cool the threshold parameter if required
|
||||
# if getattr(self, 'factor', None) is not None:
|
||||
# eps = self.reg.eps / self.factor
|
||||
#
|
||||
# if getattr(self, 'eps_min', None) is not None:
|
||||
# self.reg.eps = np.max([self.eps_min,eps])
|
||||
# else:
|
||||
# self.reg.eps = eps
|
||||
|
||||
# Get phi_m at the end of current iteration
|
||||
self.phi_m_last = self.invProb.phi_m_last
|
||||
|
||||
# Reset the regularization matrices so that it is
|
||||
# recalculated for current model
|
||||
self.reg._Wsmall = None
|
||||
self.reg._Wx = None
|
||||
self.reg._Wy = None
|
||||
self.reg._Wz = None
|
||||
|
||||
# Update the model used for the IRLS weights
|
||||
self.reg.curModel = self.invProb.curModel
|
||||
|
||||
# Temporarely set gamma to 1. to get raw phi_m
|
||||
self.reg.gamma = 1.
|
||||
|
||||
# Compute new model objective function value
|
||||
phim_new = self.reg.eval(self.invProb.curModel)
|
||||
|
||||
# Update gamma to scale the regularization between IRLS iterations
|
||||
self.reg.gamma = self.phi_m_last / phim_new
|
||||
|
||||
# Reset the regularization matrices again for new gamma
|
||||
self.reg._Wsmall = None
|
||||
self.reg._Wx = None
|
||||
self.reg._Wy = None
|
||||
self.reg._Wz = None
|
||||
|
||||
# Check if misfit is within the tolerance, otherwise scale beta
|
||||
val = self.invProb.phi_d / (self.survey.nD*0.5)
|
||||
|
||||
if np.abs(1.-val) > self.beta_tol:
|
||||
self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d
|
||||
|
||||
class Update_lin_PreCond(InversionDirective):
|
||||
"""
|
||||
Create a Jacobi preconditioner for the linear problem
|
||||
"""
|
||||
onlyOnStart=False
|
||||
|
||||
def initialize(self):
|
||||
|
||||
if getattr(self.opt, 'approxHinv', None) is None:
|
||||
# Update the pre-conditioner
|
||||
diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2.
|
||||
PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.)
|
||||
self.opt.approxHinv = PC
|
||||
|
||||
def endIter(self):
|
||||
# Cool the threshold parameter
|
||||
if self.onlyOnStart==True:
|
||||
return
|
||||
|
||||
if getattr(self.opt, 'approxHinv', None) is not None:
|
||||
# Update the pre-conditioner
|
||||
diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2.
|
||||
PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.)
|
||||
self.opt.approxHinv = PC
|
||||
|
||||
|
||||
class Update_Wj(InversionDirective):
|
||||
"""
|
||||
Create approx-sensitivity base weighting using the probing method
|
||||
"""
|
||||
k = None # Number of probing cycles
|
||||
itr = None # Iteration number to update Wj, or always update if None
|
||||
|
||||
def endIter(self):
|
||||
|
||||
if self.itr is None or self.itr == self.opt.iter:
|
||||
|
||||
m = self.invProb.curModel
|
||||
if self.k is None:
|
||||
self.k = int(self.survey.nD/10)
|
||||
|
||||
def JtJv(v):
|
||||
|
||||
Jv = self.prob.Jvec(m, v)
|
||||
|
||||
return self.prob.Jtvec(m,Jv)
|
||||
|
||||
JtJdiag = Utils.diagEst(JtJv,len(m),k=self.k)
|
||||
JtJdiag = JtJdiag / max(JtJdiag)
|
||||
|
||||
self.reg.wght = JtJdiag
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
import numpy as np
|
||||
from scipy.constants import mu_0, pi
|
||||
from scipy import special
|
||||
|
||||
def DCAnalyticHalf(txloc, rxlocs, sigma, earth_type="wholespace"):
|
||||
"""
|
||||
Analytic solution for electric potential from a postive pole
|
||||
|
||||
:param array txloc: a xyz location of A (+) electrode (np.r_[xa, ya, za])
|
||||
:param list rxlocs: xyz locations of M (+) and N (-) electrodes [M, N]
|
||||
|
||||
e.g.
|
||||
rxlocs = [M, N]
|
||||
M: xyz locations of M (+) electrode (np.c_[xmlocs, ymlocs, zmlocs])
|
||||
N: xyz locations of N (-) electrode (np.c_[xnlocs, ynlocs, znlocs])
|
||||
|
||||
:param float or complex sigma: values of conductivity
|
||||
:param string earth_type: values of conductivity ("wholsespace" or "halfspace")
|
||||
|
||||
"""
|
||||
M = rxlocs[0]
|
||||
N = rxlocs[1]
|
||||
|
||||
rM = np.sqrt( (M[:,0]-txloc[0])**2 + (M[:,1]-txloc[1])**2 + (M[:,2]-txloc[1])**2 )
|
||||
rN = np.sqrt( (N[:,0]-txloc[0])**2 + (N[:,1]-txloc[1])**2 + (N[:,2]-txloc[1])**2 )
|
||||
|
||||
phiM = 1./(4*np.pi*rM*sigma)
|
||||
phiN = 1./(4*np.pi*rN*sigma)
|
||||
phi = phiM - phiN
|
||||
|
||||
if earth_type == "halfspace":
|
||||
phi *= 2
|
||||
|
||||
return phi
|
||||
|
||||
deg2rad = lambda deg: deg/180.*np.pi
|
||||
rad2deg = lambda rad: rad*180./np.pi
|
||||
|
||||
def DCAnalyticSphere(txloc, rxloc, xc, radius, sigma, sigma1, \
|
||||
field_type = "secondary", order=12, halfspace=False):
|
||||
# def DCSpherePointCurrent(txloc, rxloc, xc, radius, rho, rho1, \
|
||||
# field_type = "secondary", order=12):
|
||||
"""
|
||||
|
||||
Parameters:
|
||||
|
||||
:param array txloc: A (+) current electrode location (x,y,z)
|
||||
:param array xc: x center of depressed sphere
|
||||
:param array rxloc: M(+) electrode locations / (Nx3 array, # of electrodes)
|
||||
|
||||
:param float radius: radius (float): radius of the sphere (m)
|
||||
:param float rho: resistivity of the background (ohm-m)
|
||||
:param float rho1: resistivity of the sphere
|
||||
:param string field_type: : "secondary", "total", "primary"
|
||||
(default="secondary")
|
||||
"secondary": secondary potential only due to sphere
|
||||
"primary": primary potential from the point source
|
||||
"total": "secondary"+"primary"
|
||||
:param float order: maximum order of Legendre polynomial (default=12)
|
||||
|
||||
Written by Seogi Kang (skang@eos.ubc.ca)
|
||||
Ph.D. Candidate of University of British Columbia, Canada
|
||||
|
||||
"""
|
||||
|
||||
Pleg = []
|
||||
# Compute Legendre Polynomial
|
||||
for i in range(order):
|
||||
Pleg.append(special.legendre(i, monic=0))
|
||||
|
||||
|
||||
rho = 1./sigma
|
||||
rho1 = 1./sigma1
|
||||
|
||||
# Center of the sphere should be aligned in txloc in y-direction
|
||||
yc = txloc[1]
|
||||
xyz = np.c_[rxloc[:,0]-xc, rxloc[:,1]-yc, rxloc[:,2]]
|
||||
r = np.sqrt( (xyz**2).sum(axis=1) )
|
||||
|
||||
x0 = abs(txloc[0]-xc)
|
||||
|
||||
costheta = xyz[:,0]/r * (txloc[0]-xc)/x0
|
||||
phi = np.zeros_like(r)
|
||||
R = (r**2+x0**2.-2.*r*x0*costheta)**0.5
|
||||
# primary potential in a whole space
|
||||
prim = rho*1./(4*np.pi*R)
|
||||
|
||||
if field_type =="primary":
|
||||
return prim
|
||||
|
||||
sphind = r < radius
|
||||
out = np.zeros_like(r)
|
||||
for n in range(order):
|
||||
An, Bn = AnBnfun(n, radius, x0, rho, rho1)
|
||||
dumout = An*r[~sphind]**(-n-1.)*Pleg[n](costheta[~sphind])
|
||||
out[~sphind] += dumout
|
||||
dumin = Bn*r[sphind]**(n)*Pleg[n](costheta[sphind])
|
||||
out[sphind] += dumin
|
||||
|
||||
out[~sphind] += prim[~sphind]
|
||||
|
||||
if halfspace:
|
||||
scale = 2
|
||||
else:
|
||||
scale = 1
|
||||
|
||||
if field_type == "secondary":
|
||||
return scale*(out-prim)
|
||||
elif field_type == "total":
|
||||
return scale*out
|
||||
|
||||
def AnBnfun(n, radius, x0, rho, rho1, I=1.):
|
||||
const = I*rho/(4*np.pi)
|
||||
bunmo = n*rho + (n+1)*rho1
|
||||
An = const * radius**(2*n+1) / x0 ** (n+1.) * n * \
|
||||
(rho1-rho) / bunmo
|
||||
Bn = const * 1. / x0 ** (n+1.) * (2*n+1) * (rho1) / bunmo
|
||||
return An, Bn
|
||||
@@ -0,0 +1,302 @@
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from TDEM import hzAnalyticDipoleT
|
||||
from FDEM import hzAnalyticDipoleF
|
||||
from FDEMcasing import *
|
||||
from DC import DCAnalyticHalf, DCAnalyticSphere
|
||||
from FDEMDipolarfields import *
|
||||
|
||||
+70
-24
@@ -1,15 +1,16 @@
|
||||
from SimPEG import Survey, Problem, Utils, Models, Maps, PropMaps, np, sp, Solver as SimpegSolver
|
||||
from scipy.constants import mu_0
|
||||
|
||||
|
||||
class EMPropMap(Maps.PropMap):
|
||||
"""
|
||||
"""
|
||||
Property Map for EM Problems. The electrical conductivity (\\(\\sigma\\)) is the default inversion property, and the default value of the magnetic permeability is that of free space (\\(\\mu = 4\\pi\\times 10^{-7} \\) H/m)
|
||||
"""
|
||||
|
||||
sigma = Maps.Property("Electrical Conductivity", defaultInvProp = True, propertyLink=('rho',Maps.ReciprocalMap))
|
||||
mu = Maps.Property("Inverse Magnetic Permeability", defaultVal = mu_0, propertyLink=('mui',Maps.ReciprocalMap))
|
||||
|
||||
rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap))
|
||||
rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap))
|
||||
mui = Maps.Property("Inverse Magnetic Permeability", defaultVal = 1./mu_0, propertyLink=('mu', Maps.ReciprocalMap))
|
||||
|
||||
|
||||
@@ -19,10 +20,10 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
Problem.BaseProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
|
||||
surveyPair = Survey.BaseSurvey
|
||||
dataPair = Survey.Data
|
||||
|
||||
PropMap = EMPropMap
|
||||
surveyPair = Survey.BaseSurvey #: The survey to pair with.
|
||||
dataPair = Survey.Data #: The data to pair with.
|
||||
|
||||
PropMap = EMPropMap #: The property mapping
|
||||
|
||||
Solver = SimpegSolver
|
||||
solverOpts = {}
|
||||
@@ -51,7 +52,7 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
if self.mapping.muMap is not None or self.mapping.muiMap is not None:
|
||||
toDelete += ['_MeMu', '_MeMuI','_MfMui','_MfMuiI']
|
||||
return toDelete
|
||||
|
||||
|
||||
@property
|
||||
def Me(self):
|
||||
"""
|
||||
@@ -61,6 +62,15 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
self._Me = self.mesh.getEdgeInnerProduct()
|
||||
return self._Me
|
||||
|
||||
@property
|
||||
def MeI(self):
|
||||
"""
|
||||
Edge inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MeI', None) is None:
|
||||
self._MeI = self.mesh.getEdgeInnerProduct(invMat=True)
|
||||
return self._MeI
|
||||
|
||||
@property
|
||||
def Mf(self):
|
||||
"""
|
||||
@@ -70,8 +80,22 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
self._Mf = self.mesh.getFaceInnerProduct()
|
||||
return self._Mf
|
||||
|
||||
@property
|
||||
def MfI(self):
|
||||
"""
|
||||
Face inner product matrix
|
||||
"""
|
||||
if getattr(self, '_MfI', None) is None:
|
||||
self._MfI = self.mesh.getFaceInnerProduct(invMat=True)
|
||||
return self._MfI
|
||||
|
||||
# ----- Magnetic Permeability ----- #
|
||||
@property
|
||||
def Vol(self):
|
||||
if getattr(self, '_Vol', None) is None:
|
||||
self._Vol = Utils.sdiag(self.mesh.vol)
|
||||
return self._Vol
|
||||
|
||||
# ----- Magnetic Permeability ----- #
|
||||
@property
|
||||
def MfMui(self):
|
||||
"""
|
||||
@@ -109,7 +133,7 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
return self._MeMuI
|
||||
|
||||
|
||||
# ----- Electrical Conductivity ----- #
|
||||
# ----- Electrical Conductivity ----- #
|
||||
#TODO: hardcoded to sigma as the model
|
||||
@property
|
||||
def MeSigma(self):
|
||||
@@ -120,18 +144,17 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
self._MeSigma = self.mesh.getEdgeInnerProduct(self.curModel.sigma)
|
||||
return self._MeSigma
|
||||
|
||||
# TODO: This should take a vector
|
||||
# TODO: This should take a vector
|
||||
def MeSigmaDeriv(self, u):
|
||||
"""
|
||||
Derivative of MeSigma with respect to the model
|
||||
"""
|
||||
"""
|
||||
return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u) * self.curModel.sigmaDeriv
|
||||
|
||||
|
||||
@property
|
||||
def MeSigmaI(self):
|
||||
"""
|
||||
Inverse of the edge inner product matrix for \\(\\sigma\\).
|
||||
Inverse of the edge inner product matrix for \\(\\sigma\\).
|
||||
"""
|
||||
if getattr(self, '_MeSigmaI', None) is None:
|
||||
self._MeSigmaI = self.mesh.getEdgeInnerProduct(self.curModel.sigma, invMat=True)
|
||||
@@ -140,16 +163,13 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
# TODO: This should take a vector
|
||||
def MeSigmaIDeriv(self, u):
|
||||
"""
|
||||
Derivative of :code:`MeSigma` with respect to the model
|
||||
"""
|
||||
Derivative of :code:`MeSigma` with respect to the model
|
||||
"""
|
||||
# TODO: only works for diagonal tensors. getEdgeInnerProductDeriv, invMat=True should be implemented in SimPEG
|
||||
|
||||
dMeSigmaI_dI = -self.MeSigmaI**2
|
||||
dMe_dsig = self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u)
|
||||
dsig_dm = self.curModel.sigmaDeriv
|
||||
return dMeSigmaI_dI * ( dMe_dsig * ( dsig_dm))
|
||||
# return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma, invMat=True)(u)
|
||||
|
||||
return dMeSigmaI_dI * ( dMe_dsig * self.curModel.sigmaDeriv )
|
||||
|
||||
@property
|
||||
def MfRho(self):
|
||||
@@ -163,10 +183,9 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
# TODO: This should take a vector
|
||||
def MfRhoDeriv(self,u):
|
||||
"""
|
||||
Derivative of :code:`MfRho` with respect to the model.
|
||||
Derivative of :code:`MfRho` with respect to the model.
|
||||
"""
|
||||
return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * (-Utils.sdiag(self.curModel.rho**2) * self.curModel.sigmaDeriv)
|
||||
# self.curModel.rhoDeriv
|
||||
return self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u) * self.curModel.rhoDeriv
|
||||
|
||||
@property
|
||||
def MfRhoI(self):
|
||||
@@ -181,6 +200,33 @@ class BaseEMProblem(Problem.BaseProblem):
|
||||
# TODO: This should take a vector
|
||||
def MfRhoIDeriv(self,u):
|
||||
"""
|
||||
Derivative of :code:`MfRhoI` with respect to the model.
|
||||
Derivative of :code:`MfRhoI` with respect to the model.
|
||||
"""
|
||||
return self.mesh.getFaceInnerProductDeriv(self.curModel.rho, invMat=True)(u) * self.curModel.rhoDeriv
|
||||
|
||||
dMfRhoI_dI = -self.MfRhoI**2
|
||||
dMf_drho = self.mesh.getFaceInnerProductDeriv(self.curModel.rho)(u)
|
||||
return dMfRhoI_dI * ( dMf_drho * self.curModel.rhoDeriv )
|
||||
|
||||
class BaseEMSurvey(Survey.BaseSurvey):
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
# Sort these by frequency
|
||||
self.srcList = srcList
|
||||
Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
|
||||
def eval(self, f):
|
||||
"""
|
||||
Project fields to receiver locations
|
||||
|
||||
:param Fields u: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: data
|
||||
"""
|
||||
data = Survey.Data(self)
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.eval(src, self.mesh, f)
|
||||
return data
|
||||
|
||||
def evalDeriv(self, f):
|
||||
raise Exception('Use Receivers to project fields deriv.')
|
||||
|
||||
+141
-153
@@ -6,11 +6,11 @@ from SimPEG.EM.Utils import omega
|
||||
from SimPEG.Utils import Zero, Identity, sdiag
|
||||
|
||||
|
||||
class Fields(SimPEG.Problem.Fields):
|
||||
class FieldsFDEM(SimPEG.Problem.Fields):
|
||||
"""
|
||||
|
||||
|
||||
Fancy Field Storage for a FDEM survey. Only one field type is stored for
|
||||
each problem, the rest are computed. The fields obejct acts like an array and is indexed by
|
||||
each problem, the rest are computed. The fields object acts like an array and is indexed by
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@@ -34,56 +34,56 @@ class Fields(SimPEG.Problem.Fields):
|
||||
|
||||
def _e(self, solution, srcList):
|
||||
"""
|
||||
Total electric field is sum of primary and secondary
|
||||
|
||||
Total electric field is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray solution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total electric field
|
||||
"""
|
||||
if getattr(self, '_ePrimary', None) is None or getattr(self, '_eSecondary', None) is None:
|
||||
if getattr(self, '_ePrimary', None) is None or getattr(self, '_eSecondary', None) is None:
|
||||
raise NotImplementedError ('Getting e from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
return self._ePrimary(solution,srcList) + self._eSecondary(solution,srcList)
|
||||
|
||||
def _b(self, solution, srcList):
|
||||
"""
|
||||
Total magnetic flux density is sum of primary and secondary
|
||||
|
||||
Total magnetic flux density is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray solution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total magnetic flux density
|
||||
:return: total magnetic flux density
|
||||
"""
|
||||
if getattr(self, '_bPrimary', None) is None or getattr(self, '_bSecondary', None) is None:
|
||||
if getattr(self, '_bPrimary', None) is None or getattr(self, '_bSecondary', None) is None:
|
||||
raise NotImplementedError ('Getting b from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
return self._bPrimary(solution, srcList) + self._bSecondary(solution, srcList)
|
||||
|
||||
def _h(self, solution, srcList):
|
||||
"""
|
||||
Total magnetic field is sum of primary and secondary
|
||||
|
||||
Total magnetic field is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray solution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total magnetic field
|
||||
"""
|
||||
if getattr(self, '_hPrimary', None) is None or getattr(self, '_hSecondary', None) is None:
|
||||
if getattr(self, '_hPrimary', None) is None or getattr(self, '_hSecondary', None) is None:
|
||||
raise NotImplementedError ('Getting h from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
return self._hPrimary(solution, srcList) + self._hSecondary(solution, srcList)
|
||||
|
||||
def _j(self, solution, srcList):
|
||||
"""
|
||||
Total current density is sum of primary and secondary
|
||||
|
||||
Total current density is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray solution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total current density
|
||||
:return: total current density
|
||||
"""
|
||||
if getattr(self, '_jPrimary', None) is None or getattr(self, '_jSecondary', None) is None:
|
||||
if getattr(self, '_jPrimary', None) is None or getattr(self, '_jSecondary', None) is None:
|
||||
raise NotImplementedError ('Getting j from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
return self._jPrimary(solution, srcList) + self._jSecondary(solution, srcList)
|
||||
@@ -92,14 +92,14 @@ class Fields(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 Src src: sorce
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source
|
||||
: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?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative times a vector (or tuple for adjoint)
|
||||
"""
|
||||
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
|
||||
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
@@ -110,35 +110,35 @@ class Fields(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 Src src: sorce
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source
|
||||
: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?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative times a vector (or tuple for adjoint)
|
||||
"""
|
||||
if getattr(self, '_bDeriv_u', None) is None or getattr(self, '_bDeriv_m', None) is None:
|
||||
if getattr(self, '_bDeriv_u', None) is None or getattr(self, '_bDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting bDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._bDeriv_u(src, v, adjoint), self._bDeriv_m(src, v, adjoint)
|
||||
return np.array(self._bDeriv_u(src, du_dm_v, adjoint) + self._bDeriv_m(src, v, adjoint), dtype = complex)
|
||||
return np.array(self._bDeriv_u(src, du_dm_v, adjoint) + self._bDeriv_m(src, v, adjoint), dtype = complex)
|
||||
|
||||
def _hDeriv(self, src, du_dm_v, v, adjoint = False):
|
||||
"""
|
||||
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 Src src: sorce
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source
|
||||
: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?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative times a vector (or tuple for adjoint)
|
||||
"""
|
||||
if getattr(self, '_hDeriv_u', None) is None or getattr(self, '_hDeriv_m', None) is None:
|
||||
if getattr(self, '_hDeriv_u', None) is None or getattr(self, '_hDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting hDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
if adjoint:
|
||||
return self._hDeriv_u(src, v, adjoint), self._hDeriv_m(src, v, adjoint)
|
||||
return np.array(self._hDeriv_u(src, du_dm_v, adjoint) + self._hDeriv_m(src, v, adjoint), dtype = complex)
|
||||
|
||||
@@ -146,26 +146,26 @@ class Fields(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 Src src: sorce
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: source
|
||||
: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?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative times a vector (or tuple for adjoint)
|
||||
"""
|
||||
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
|
||||
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint)
|
||||
return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = complex)
|
||||
|
||||
class Fields_e(Fields):
|
||||
class Fields3D_e(FieldsFDEM):
|
||||
"""
|
||||
Fields object for Problem_e.
|
||||
Fields object for Problem3D_e.
|
||||
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
:param BaseMesh mesh: mesh
|
||||
:param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'eSolution':'E'}
|
||||
@@ -180,9 +180,6 @@ class Fields_e(Fields):
|
||||
'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
|
||||
@@ -233,9 +230,9 @@ class Fields_e(Fields):
|
||||
|
||||
def _eDeriv_u(self, src, v, adjoint = False):
|
||||
"""
|
||||
Partial derivative of the total electric field with respect to the thing we
|
||||
Partial derivative of the total electric field with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -247,8 +244,8 @@ class Fields_e(Fields):
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint = False):
|
||||
"""
|
||||
Partial derivative of the total electric field with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
Partial derivative of the total electric field with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -289,14 +286,14 @@ class Fields_e(Fields):
|
||||
b = (C * eSolution)
|
||||
for i, src in enumerate(srcList):
|
||||
b[:,i] *= - 1./(1j*omega(src.freq))
|
||||
S_m, _ = src.eval(self.prob)
|
||||
b[:,i] = b[:,i]+ 1./(1j*omega(src.freq)) * S_m
|
||||
s_m, _ = src.eval(self.prob)
|
||||
b[:,i] = b[:,i]+ 1./(1j*omega(src.freq)) * s_m
|
||||
return b
|
||||
|
||||
def _bDeriv_u(self, src, du_dm_v, adjoint = False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -312,8 +309,8 @@ class Fields_e(Fields):
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint = False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the inversion model.
|
||||
|
||||
Derivative of the magnetic flux density with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -321,8 +318,8 @@ class Fields_e(Fields):
|
||||
:return: product of the magnetic flux density derivative with respect to the inversion model with a vector
|
||||
"""
|
||||
|
||||
S_mDeriv, _ = src.evalDeriv(self.prob, v, adjoint)
|
||||
return 1./(1j * omega(src.freq)) * S_mDeriv
|
||||
s_mDeriv, _ = src.evalDeriv(self.prob, v, adjoint)
|
||||
return 1./(1j * omega(src.freq)) * s_mDeriv
|
||||
|
||||
def _j(self, eSolution, srcList):
|
||||
"""
|
||||
@@ -341,7 +338,7 @@ class Fields_e(Fields):
|
||||
def _jDeriv_u(self, src, du_dm_v, adjoint = False):
|
||||
"""
|
||||
Derivative of the current density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -351,15 +348,15 @@ class Fields_e(Fields):
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) # number of components (instead of checking if cyl or not)
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
|
||||
if adjoint:
|
||||
if adjoint:
|
||||
return self._eDeriv_u(src, self._MeSigma.T * (self._aveE2CCV.T * (VI.T * du_dm_v) ), adjoint = adjoint)
|
||||
return VI * (self._aveE2CCV * (self._MeSigma * (self._eDeriv_u(src, du_dm_v, adjoint=adjoint) ) ) )
|
||||
|
||||
|
||||
|
||||
def _jDeriv_m(self, src, v, adjoint = False):
|
||||
"""
|
||||
Derivative of the current density with respect to the inversion model.
|
||||
|
||||
Derivative of the current density with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -373,7 +370,7 @@ class Fields_e(Fields):
|
||||
if adjoint:
|
||||
return self._MeSigmaDeriv(e).T * (self._aveE2CCV.T * (VI.T * v)) + self._eDeriv_m(src, self._aveE2CCV.T * (VI.T * v), adjoint=adjoint)
|
||||
return VI * (self._aveE2CCV * ( self._eDeriv_m(src, v, adjoint=adjoint) + self._MeSigmaDeriv(e) * v))
|
||||
|
||||
|
||||
|
||||
|
||||
def _h(self, eSolution, srcList):
|
||||
@@ -393,7 +390,7 @@ class Fields_e(Fields):
|
||||
def _hDeriv_u(self, src, du_dm_v, adjoint = False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -409,8 +406,8 @@ class Fields_e(Fields):
|
||||
|
||||
def _hDeriv_m(self, src, v, adjoint = False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the inversion model.
|
||||
|
||||
Derivative of the magnetic field with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -426,12 +423,12 @@ class Fields_e(Fields):
|
||||
|
||||
|
||||
|
||||
class Fields_b(Fields):
|
||||
class Fields3D_b(FieldsFDEM):
|
||||
"""
|
||||
Fields object for Problem_b.
|
||||
Fields object for Problem3D_b.
|
||||
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
:param BaseMesh mesh: mesh
|
||||
:param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'bSolution':'F'}
|
||||
@@ -446,9 +443,6 @@ class Fields_b(Fields):
|
||||
'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
|
||||
@@ -506,9 +500,9 @@ class Fields_b(Fields):
|
||||
|
||||
def _bDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total magnetic flux density with respect to the thing we
|
||||
Partial derivative of the total magnetic flux density with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -520,8 +514,8 @@ class Fields_b(Fields):
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total magnetic flux density with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
Partial derivative of the total magnetic flux density with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -560,15 +554,15 @@ class Fields_b(Fields):
|
||||
|
||||
e = ( self._edgeCurl.T * ( self._MfMui * bSolution))
|
||||
for i,src in enumerate(srcList):
|
||||
_,S_e = src.eval(self.prob)
|
||||
e[:,i] = e[:,i] + - S_e
|
||||
_,s_e = src.eval(self.prob)
|
||||
e[:,i] = e[:,i] + - s_e
|
||||
|
||||
return self._MeSigmaI * e
|
||||
|
||||
def _eDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -583,8 +577,8 @@ class Fields_b(Fields):
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the inversion model
|
||||
|
||||
Derivative of the electric field with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -593,15 +587,15 @@ class Fields_b(Fields):
|
||||
"""
|
||||
|
||||
bSolution = Utils.mkvc(self[src, 'bSolution'])
|
||||
_,S_e = src.eval(self.prob)
|
||||
_,s_e = src.eval(self.prob)
|
||||
|
||||
w = -S_e + self._edgeCurl.T * (self._MfMui * bSolution)
|
||||
_, S_eDeriv = src.evalDeriv(self.prob, v, adjoint)
|
||||
w = -s_e + self._edgeCurl.T * (self._MfMui * bSolution)
|
||||
_, s_eDeriv = src.evalDeriv(self.prob, v, adjoint)
|
||||
|
||||
|
||||
if adjoint:
|
||||
return self._MeSigmaIDeriv(w).T * v - self._MeSigmaI.T * S_eDeriv
|
||||
return self._MeSigmaIDeriv(w) * v - self._MeSigmaI * S_eDeriv
|
||||
return self._MeSigmaIDeriv(w).T * v - self._MeSigmaI.T * s_eDeriv
|
||||
return self._MeSigmaIDeriv(w) * v - self._MeSigmaI * s_eDeriv
|
||||
|
||||
def _j(self, bSolution, srcList):
|
||||
"""
|
||||
@@ -617,13 +611,13 @@ class Fields_b(Fields):
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
|
||||
return VI * (self._aveE2CCV * ( self._MeSigma * self._e(bSolution,srcList ) ) )
|
||||
|
||||
|
||||
|
||||
def _jDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the current density with respect to the thing we
|
||||
Partial derivative of the current density with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -639,8 +633,8 @@ class Fields_b(Fields):
|
||||
|
||||
def _jDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the current density with respect to the inversion model
|
||||
|
||||
Derivative of the current density with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -664,9 +658,9 @@ class Fields_b(Fields):
|
||||
|
||||
def _hDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the magnetic field with respect to the thing we
|
||||
Partial derivative of the magnetic field with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -682,8 +676,8 @@ class Fields_b(Fields):
|
||||
|
||||
def _hDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the inversion model
|
||||
|
||||
Derivative of the magnetic field with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -693,12 +687,12 @@ class Fields_b(Fields):
|
||||
return Zero()
|
||||
|
||||
|
||||
class Fields_j(Fields):
|
||||
class Fields3D_j(FieldsFDEM):
|
||||
"""
|
||||
Fields object for Problem_j.
|
||||
Fields object for Problem3D_j.
|
||||
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
:param BaseMesh mesh: mesh
|
||||
:param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'jSolution':'F'}
|
||||
@@ -713,9 +707,6 @@ class Fields_j(Fields):
|
||||
'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
|
||||
@@ -769,12 +760,12 @@ class Fields_j(Fields):
|
||||
|
||||
def _j(self, jSolution, srcList):
|
||||
"""
|
||||
Total current density is sum of primary and secondary
|
||||
|
||||
Total current density is sum of primary and secondary
|
||||
|
||||
:param numpy.ndarray jSolution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: total current density
|
||||
:return: total current density
|
||||
"""
|
||||
|
||||
return self._jPrimary(jSolution, srcList) + self._jSecondary(jSolution, srcList)
|
||||
@@ -782,9 +773,9 @@ class Fields_j(Fields):
|
||||
|
||||
def _jDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total current density with respect to the thing we
|
||||
Partial derivative of the total current density with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -797,8 +788,8 @@ class Fields_j(Fields):
|
||||
|
||||
def _jDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total current density with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
Partial derivative of the total current density with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -837,15 +828,15 @@ class Fields_j(Fields):
|
||||
h = (self._edgeCurl.T * (self._MfRho * jSolution) )
|
||||
for i, src in enumerate(srcList):
|
||||
h[:,i] *= -1./(1j*omega(src.freq))
|
||||
S_m,_ = src.eval(self.prob)
|
||||
h[:,i] = h[:,i] + 1./(1j*omega(src.freq)) * (S_m)
|
||||
s_m,_ = src.eval(self.prob)
|
||||
h[:,i] = h[:,i] + 1./(1j*omega(src.freq)) * (s_m)
|
||||
return self._MeMuI * h
|
||||
|
||||
|
||||
def _hDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -856,13 +847,13 @@ class Fields_j(Fields):
|
||||
if adjoint:
|
||||
return -1./(1j*omega(src.freq)) * self._MfRho.T * (self._edgeCurl * ( self._MeMuI.T * du_dm_v))
|
||||
return -1./(1j*omega(src.freq)) * self._MeMuI * (self._edgeCurl.T * (self._MfRho * du_dm_v) )
|
||||
|
||||
|
||||
|
||||
|
||||
def _hDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic field with respect to the inversion model
|
||||
|
||||
Derivative of the magnetic field with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -875,19 +866,19 @@ class Fields_j(Fields):
|
||||
C = self._edgeCurl
|
||||
MfRho = self._MfRho
|
||||
MfRhoDeriv = self._MfRhoDeriv
|
||||
S_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
|
||||
s_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
|
||||
|
||||
if not adjoint:
|
||||
hDeriv_m = -1./(1j*omega(src.freq)) * MeMuI * (C.T * (MfRhoDeriv(jSolution)*v ) )
|
||||
S_mDeriv = S_mDeriv(v)
|
||||
hDeriv_m = hDeriv_m + 1./(1j*omega(src.freq)) * MeMuI * ( S_mDeriv)
|
||||
s_mDeriv = s_mDeriv(v)
|
||||
hDeriv_m = hDeriv_m + 1./(1j*omega(src.freq)) * MeMuI * ( s_mDeriv)
|
||||
|
||||
elif adjoint:
|
||||
hDeriv_m = -1./(1j*omega(src.freq)) * MfRhoDeriv(jSolution).T * ( C * (MeMuI.T * v ) )
|
||||
|
||||
S_mDeriv = S_mDeriv(MeMuI.T * v)
|
||||
hDeriv_m = hDeriv_m + 1./(1j*omega(src.freq)) * S_mDeriv
|
||||
|
||||
s_mDeriv = s_mDeriv(MeMuI.T * v)
|
||||
hDeriv_m = hDeriv_m + 1./(1j*omega(src.freq)) * s_mDeriv
|
||||
|
||||
return hDeriv_m
|
||||
|
||||
def _e(self, jSolution, srcList):
|
||||
@@ -901,12 +892,12 @@ class Fields_j(Fields):
|
||||
"""
|
||||
n = int(self._aveF2CCV.shape[0] / self._nC) # number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._j(jSolution, srcList)))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._j(jSolution, srcList)))
|
||||
|
||||
def _eDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -921,8 +912,8 @@ class Fields_j(Fields):
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the inversion model
|
||||
|
||||
Derivative of the electric field with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -943,17 +934,17 @@ class Fields_j(Fields):
|
||||
:param numpy.ndarray hSolution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: secondary magnetic flux density
|
||||
:return: secondary magnetic flux density
|
||||
"""
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) # number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
|
||||
return VI * (self._aveE2CCV * ( self._MeMu * self._h(jSolution,srcList)) )
|
||||
return VI * (self._aveE2CCV * ( self._MeMu * self._h(jSolution,srcList)) )
|
||||
|
||||
def _bDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -969,8 +960,8 @@ class Fields_j(Fields):
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the inversion model
|
||||
|
||||
Derivative of the magnetic flux density with respect to the inversion model
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -980,20 +971,20 @@ class Fields_j(Fields):
|
||||
jSolution = self[src,'jSolution']
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) # number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
S_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
|
||||
s_mDeriv,_ = src.evalDeriv(self.prob, adjoint = adjoint)
|
||||
|
||||
if adjoint:
|
||||
v = self._aveE2CCV.T * ( VI.T * v)
|
||||
return 1./(1j * omega(src.freq)) * ( S_mDeriv(v) - self._MfRhoDeriv(jSolution).T * (self._edgeCurl * v ))
|
||||
return 1./(1j * omega(src.freq)) * VI * (self._aveE2CCV * ( S_mDeriv(v) - self._edgeCurl.T * ( self._MfRhoDeriv(jSolution) * v ) ) )
|
||||
return 1./(1j * omega(src.freq)) * ( s_mDeriv(v) - self._MfRhoDeriv(jSolution).T * (self._edgeCurl * v ))
|
||||
return 1./(1j * omega(src.freq)) * VI * (self._aveE2CCV * ( s_mDeriv(v) - self._edgeCurl.T * ( self._MfRhoDeriv(jSolution) * v ) ) )
|
||||
|
||||
|
||||
class Fields_h(Fields):
|
||||
class Fields3D_h(FieldsFDEM):
|
||||
"""
|
||||
Fields object for Problem_h.
|
||||
Fields object for Problem3D_h.
|
||||
|
||||
:param Mesh mesh: mesh
|
||||
:param Survey survey: survey
|
||||
:param BaseMesh mesh: mesh
|
||||
:param SimPEG.EM.FDEM.SurveyFDEM.Survey survey: survey
|
||||
"""
|
||||
|
||||
knownFields = {'hSolution':'E'}
|
||||
@@ -1008,9 +999,6 @@ class Fields_h(Fields):
|
||||
'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
|
||||
@@ -1065,9 +1053,9 @@ class Fields_h(Fields):
|
||||
|
||||
def _hDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total magnetic field with respect to the thing we
|
||||
Partial derivative of the total magnetic field with respect to the thing we
|
||||
solved for.
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1079,8 +1067,8 @@ class Fields_h(Fields):
|
||||
|
||||
def _hDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Partial derivative of the total magnetic field with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
Partial derivative of the total magnetic field with respect to the inversion model. Here, we assume that the primary does not depend on the model. Note that this also includes derivative contributions from the sources.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1119,14 +1107,14 @@ class Fields_h(Fields):
|
||||
|
||||
j = self._edgeCurl*hSolution
|
||||
for i, src in enumerate(srcList):
|
||||
_,S_e = src.eval(self.prob)
|
||||
j[:,i] = j[:,i]+ -S_e
|
||||
_,s_e = src.eval(self.prob)
|
||||
j[:,i] = j[:,i]+ -s_e
|
||||
return j
|
||||
|
||||
def _jDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the current density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1142,8 +1130,8 @@ class Fields_h(Fields):
|
||||
|
||||
def _jDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the current density with respect to the inversion model.
|
||||
|
||||
Derivative of the current density with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1151,9 +1139,9 @@ class Fields_h(Fields):
|
||||
:return: product of the current density derivative with respect to the inversion model with a vector
|
||||
"""
|
||||
|
||||
_,S_eDeriv = src.evalDeriv(self.prob, v, adjoint)
|
||||
return -S_eDeriv
|
||||
|
||||
_,s_eDeriv = src.evalDeriv(self.prob, v, adjoint)
|
||||
return -s_eDeriv
|
||||
|
||||
def _e(self, hSolution, srcList):
|
||||
"""
|
||||
Electric field from hSolution
|
||||
@@ -1165,12 +1153,12 @@ class Fields_h(Fields):
|
||||
"""
|
||||
n = int(self._aveF2CCV.shape[0] / self._nC) #number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._j(hSolution, srcList)))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._j(hSolution, srcList)))
|
||||
|
||||
def _eDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1181,12 +1169,12 @@ class Fields_h(Fields):
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
if adjoint:
|
||||
return self._edgeCurl.T * ( self._MfRho.T * ( self._aveF2CCV.T * ( VI.T * du_dm_v ) ) )
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._edgeCurl * du_dm_v ))
|
||||
return VI * (self._aveF2CCV * (self._MfRho * self._edgeCurl * du_dm_v ))
|
||||
|
||||
def _eDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the electric field with respect to the inversion model.
|
||||
|
||||
Derivative of the electric field with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
@@ -1196,7 +1184,7 @@ class Fields_h(Fields):
|
||||
hSolution = Utils.mkvc(self[src,'hSolution'])
|
||||
n = int(self._aveF2CCV.shape[0] / self._nC) #number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
if adjoint:
|
||||
if adjoint:
|
||||
return ( self._MfRhoDeriv(self._edgeCurl * hSolution).T * ( self._aveF2CCV.T * (VI.T * v) ) )
|
||||
return VI * (self._aveF2CCV * (self._MfRhoDeriv(self._edgeCurl * hSolution) * v ))
|
||||
|
||||
@@ -1207,10 +1195,10 @@ class Fields_h(Fields):
|
||||
:param numpy.ndarray hSolution: field we solved for
|
||||
:param list srcList: list of sources
|
||||
:rtype: numpy.ndarray
|
||||
:return: magnetic flux density
|
||||
:return: magnetic flux density
|
||||
"""
|
||||
h = self._h(hSolution, srcList)
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) #number of components
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) #number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
|
||||
return VI * (self._aveE2CCV * (self._MeMu * h))
|
||||
@@ -1218,14 +1206,14 @@ class Fields_h(Fields):
|
||||
def _bDeriv_u(self, src, du_dm_v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the thing we solved for
|
||||
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray du_dm_v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: product of the derivative of the magnetic flux density with respect to the field we solved for with a vector
|
||||
"""
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) #number of components
|
||||
n = int(self._aveE2CCV.shape[0] / self._nC) #number of components
|
||||
VI = sdiag(np.kron(np.ones(n), 1./self.prob.mesh.vol))
|
||||
if adjoint:
|
||||
return self._MeMu.T * (self._aveE2CCV.T * ( VI.T * du_dm_v ))
|
||||
@@ -1233,8 +1221,8 @@ class Fields_h(Fields):
|
||||
|
||||
def _bDeriv_m(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the magnetic flux density with respect to the inversion model.
|
||||
|
||||
Derivative of the magnetic flux density with respect to the inversion model.
|
||||
|
||||
:param SimPEG.EM.FDEM.Src src: source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from SimPEG import Problem, Utils, np, sp, Solver as SimpegSolver
|
||||
from scipy.constants import mu_0
|
||||
from SurveyFDEM import Survey as SurveyFDEM
|
||||
from FieldsFDEM import Fields, Fields_e, Fields_b, Fields_h, Fields_j
|
||||
from FieldsFDEM import FieldsFDEM, Fields3D_e, Fields3D_b, Fields3D_h, Fields3D_j
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SimPEG.EM.Utils import omega
|
||||
|
||||
@@ -17,10 +17,10 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
\mathbf{C} \mathbf{e} + i \omega \mathbf{b} = \mathbf{s_m} \\\\
|
||||
{\mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{b} - \mathbf{M_{\sigma}^e} \mathbf{e} = \mathbf{s_e}}
|
||||
|
||||
if using the E-B formulation (:code:`Problem_e`
|
||||
or :code:`Problem_b`). Note that in this case, :math:`\mathbf{s_e}` is an integrated quantity.
|
||||
if using the E-B formulation (:code:`Problem3D_e`
|
||||
or :code:`Problem3D_b`). Note that in this case, :math:`\mathbf{s_e}` is an integrated quantity.
|
||||
|
||||
If we write Maxwell's equations in terms of
|
||||
If we write Maxwell's equations in terms of
|
||||
\\\(\\\mathbf{h}\\\) and current density \\\(\\\mathbf{j}\\\)
|
||||
|
||||
.. math ::
|
||||
@@ -28,84 +28,85 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
\mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{j} + i \omega \mathbf{M_{\mu}^e} \mathbf{h} = \mathbf{s_m} \\\\
|
||||
\mathbf{C} \mathbf{h} - \mathbf{j} = \mathbf{s_e}
|
||||
|
||||
if using the H-J formulation (:code:`Problem_j` or :code:`Problem_h`). Note that here, :math:`\mathbf{s_m}` is an integrated quantity.
|
||||
if using the H-J formulation (:code:`Problem3D_j` or :code:`Problem3D_h`). Note that here, :math:`\mathbf{s_m}` is an integrated quantity.
|
||||
|
||||
The problem performs the elimination so that we are solving the system for \\\(\\\mathbf{e},\\\mathbf{b},\\\mathbf{j} \\\) or \\\(\\\mathbf{h}\\\)
|
||||
|
||||
"""
|
||||
|
||||
surveyPair = SurveyFDEM
|
||||
fieldsPair = Fields
|
||||
fieldsPair = FieldsFDEM
|
||||
|
||||
def fields(self, m=None):
|
||||
def fields(self, m):
|
||||
"""
|
||||
Solve the forward problem for the fields.
|
||||
|
||||
|
||||
:param numpy.array m: inversion model (nP,)
|
||||
:rtype numpy.array:
|
||||
:return F: forward solution
|
||||
:return f: forward solution
|
||||
"""
|
||||
|
||||
self.curModel = m
|
||||
F = self.fieldsPair(self.mesh, self.survey)
|
||||
f = self.fieldsPair(self.mesh, self.survey)
|
||||
|
||||
for freq in self.survey.freqs:
|
||||
A = self.getA(freq)
|
||||
rhs = self.getRHS(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
sol = Ainv * rhs
|
||||
u = Ainv * rhs
|
||||
Srcs = self.survey.getSrcByFreq(freq)
|
||||
F[Srcs, self._solutionType] = sol
|
||||
f[Srcs, self._solutionType] = u
|
||||
Ainv.clean()
|
||||
return F
|
||||
return f
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""
|
||||
Sensitivity times a vector.
|
||||
|
||||
:param numpy.array m: inversion model (nP,)
|
||||
:param numpy.array v: vector which we take sensitivity product with (nP,)
|
||||
:param SimPEG.EM.FDEM.Fields u: fields object
|
||||
:param SimPEG.EM.FDEM.FieldsFDEM.FieldsFDEM u: fields object
|
||||
:rtype numpy.array:
|
||||
:return: Jv (ndata,)
|
||||
:return: Jv (ndata,)
|
||||
"""
|
||||
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey)
|
||||
|
||||
for freq in self.survey.freqs:
|
||||
A = self.getA(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
A = self.getA(freq)
|
||||
Ainv = self.Solver(A, **self.solverOpts) # create the concept of Ainv (actually a solve)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
u_src = u[src, self._solutionType]
|
||||
u_src = f[src, self._solutionType]
|
||||
dA_dm_v = self.getADeriv(freq, u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(freq, src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(freq, src, v)
|
||||
du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
|
||||
|
||||
for rx in src.rxList:
|
||||
df_dmFun = getattr(u, '_%sDeriv'%rx.projField, None)
|
||||
df_dmFun = getattr(f, '_{0}Deriv'.format(rx.projField), None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, u, df_dm_v)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
||||
Ainv.clean()
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""
|
||||
Sensitivity transpose times a vector
|
||||
|
||||
:param numpy.array m: inversion model (nP,)
|
||||
:param numpy.array v: vector which we take adjoint product with (nP,)
|
||||
:param SimPEG.EM.FDEM.Fields u: fields object
|
||||
:param SimPEG.EM.FDEM.FieldsFDEM.FieldsFDEM u: fields object
|
||||
:rtype numpy.array:
|
||||
:return: Jv (ndata,)
|
||||
:return: Jv (ndata,)
|
||||
"""
|
||||
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
@@ -120,12 +121,12 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
ATinv = self.Solver(AT, **self.solverOpts)
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
u_src = u[src, self._solutionType]
|
||||
u_src = f[src, self._solutionType]
|
||||
|
||||
for rx in src.rxList:
|
||||
PTv = rx.evalDeriv(src, self.mesh, u, v[src, rx], adjoint=True) # wrt u, need possibility wrt m
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
||||
|
||||
df_duTFun = getattr(u, '_%sDeriv'%rx.projField, None)
|
||||
df_duTFun = getattr(f, '_{0}Deriv'.format(rx.projField), None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
|
||||
ATinvdf_duT = ATinv * df_duT
|
||||
@@ -137,14 +138,13 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
df_dmT = df_dmT + du_dmT
|
||||
|
||||
# TODO: this should be taken care of by the reciever?
|
||||
real_or_imag = rx.projComp
|
||||
if real_or_imag is 'real':
|
||||
if rx.component is 'real':
|
||||
Jtv += np.array(df_dmT, dtype=complex).real
|
||||
elif real_or_imag is 'imag':
|
||||
elif rx.component is 'imag':
|
||||
Jtv += - np.array(df_dmT, dtype=complex).real
|
||||
else:
|
||||
raise Exception('Must be real or imag')
|
||||
|
||||
|
||||
ATinv.clean()
|
||||
|
||||
return Utils.mkvc(Jtv)
|
||||
@@ -154,30 +154,31 @@ class BaseFDEMProblem(BaseEMProblem):
|
||||
Evaluates the sources for a given frequency and puts them in matrix form
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: S_m, S_e (nE or nF, nSrc)
|
||||
:rtype: tuple
|
||||
:return: (s_m, s_e) (nE or nF, nSrc)
|
||||
"""
|
||||
Srcs = self.survey.getSrcByFreq(freq)
|
||||
if self._formulation is 'EB':
|
||||
S_m = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
||||
S_e = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
||||
s_m = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
||||
s_e = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
||||
elif self._formulation is 'HJ':
|
||||
S_m = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
||||
S_e = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
||||
s_m = np.zeros((self.mesh.nE,len(Srcs)), dtype=complex)
|
||||
s_e = np.zeros((self.mesh.nF,len(Srcs)), dtype=complex)
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
smi, sei = src.eval(self)
|
||||
S_m[:,i] = S_m[:,i] + smi
|
||||
S_e[:,i] = S_e[:,i] + sei
|
||||
#Why are you adding?
|
||||
s_m[:,i] = s_m[:,i] + smi
|
||||
s_e[:,i] = s_e[:,i] + sei
|
||||
|
||||
return S_m, S_e
|
||||
return s_m, s_e
|
||||
|
||||
|
||||
##########################################################################################
|
||||
################################ E-B Formulation #########################################
|
||||
##########################################################################################
|
||||
|
||||
class Problem_e(BaseFDEMProblem):
|
||||
class Problem3D_e(BaseFDEMProblem):
|
||||
"""
|
||||
By eliminating the magnetic flux density using
|
||||
|
||||
@@ -194,12 +195,12 @@ class Problem_e(BaseFDEMProblem):
|
||||
|
||||
which we solve for :math:`\mathbf{e}`.
|
||||
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
:param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh
|
||||
"""
|
||||
|
||||
_solutionType = 'eSolution'
|
||||
_formulation = 'EB'
|
||||
fieldsPair = Fields_e
|
||||
fieldsPair = Fields3D_e
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -207,7 +208,7 @@ class Problem_e(BaseFDEMProblem):
|
||||
def getA(self, freq):
|
||||
"""
|
||||
System matrix
|
||||
|
||||
|
||||
.. math ::
|
||||
\mathbf{A} = \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f} \mathbf{C} + i \omega \mathbf{M^e_{\sigma}}
|
||||
|
||||
@@ -230,12 +231,12 @@ class Problem_e(BaseFDEMProblem):
|
||||
.. math ::
|
||||
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = i \omega \\frac{d \mathbf{M^e_{\sigma}}\mathbf{v} }{d\mathbf{m}}
|
||||
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nE,)
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nE,)
|
||||
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
"""
|
||||
|
||||
dsig_dm = self.curModel.sigmaDeriv
|
||||
@@ -248,28 +249,28 @@ class Problem_e(BaseFDEMProblem):
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Right hand side for the system
|
||||
Right hand side for the system
|
||||
|
||||
.. math ::
|
||||
\mathbf{RHS} = \mathbf{C}^{\\top} \mathbf{M_{\mu^{-1}}^f}\mathbf{s_m} -i\omega\mathbf{M_e}\mathbf{s_e}
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
"""
|
||||
|
||||
S_m, S_e = self.getSourceTerm(freq)
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
C = self.mesh.edgeCurl
|
||||
MfMui = self.MfMui
|
||||
|
||||
return C.T * (MfMui * S_m) -1j * omega(freq) * S_e
|
||||
return C.T * (MfMui * s_m) -1j * omega(freq) * s_e
|
||||
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -278,17 +279,17 @@ class Problem_e(BaseFDEMProblem):
|
||||
|
||||
C = self.mesh.edgeCurl
|
||||
MfMui = self.MfMui
|
||||
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
|
||||
if adjoint:
|
||||
dRHS = MfMui * (C * v)
|
||||
return S_mDeriv(dRHS) - 1j * omega(freq) * S_eDeriv(v)
|
||||
return s_mDeriv(dRHS) - 1j * omega(freq) * s_eDeriv(v)
|
||||
|
||||
else:
|
||||
return C.T * (MfMui * S_mDeriv(v)) -1j * omega(freq) * S_eDeriv(v)
|
||||
return C.T * (MfMui * s_mDeriv(v)) -1j * omega(freq) * s_eDeriv(v)
|
||||
|
||||
|
||||
class Problem_b(BaseFDEMProblem):
|
||||
class Problem3D_b(BaseFDEMProblem):
|
||||
"""
|
||||
We eliminate :math:`\mathbf{e}` using
|
||||
|
||||
@@ -305,12 +306,12 @@ class Problem_b(BaseFDEMProblem):
|
||||
.. note ::
|
||||
The inverse problem will not work with full anisotropy
|
||||
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
:param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh
|
||||
"""
|
||||
|
||||
_solutionType = 'bSolution'
|
||||
_formulation = 'EB'
|
||||
fieldsPair = Fields_b
|
||||
fieldsPair = Fields3D_b
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -346,12 +347,12 @@ class Problem_b(BaseFDEMProblem):
|
||||
.. math ::
|
||||
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = \mathbf{C} \\frac{\mathbf{M^e_{\sigma}} \mathbf{v}}{d\mathbf{m}}
|
||||
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nF,)
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nF,)
|
||||
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
"""
|
||||
|
||||
MfMui = self.MfMui
|
||||
@@ -373,21 +374,21 @@ class Problem_b(BaseFDEMProblem):
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Right hand side for the system
|
||||
Right hand side for the system
|
||||
|
||||
.. math ::
|
||||
\mathbf{RHS} = \mathbf{s_m} + \mathbf{M^e_{\sigma}}^{-1}\mathbf{s_e}
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
"""
|
||||
|
||||
S_m, S_e = self.getSourceTerm(freq)
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
C = self.mesh.edgeCurl
|
||||
MeSigmaI = self.MeSigmaI
|
||||
|
||||
RHS = S_m + C * ( MeSigmaI * S_e )
|
||||
RHS = s_m + C * ( MeSigmaI * s_e )
|
||||
|
||||
if self._makeASymmetric is True:
|
||||
MfMui = self.MfMui
|
||||
@@ -400,7 +401,7 @@ class Problem_b(BaseFDEMProblem):
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -408,21 +409,21 @@ class Problem_b(BaseFDEMProblem):
|
||||
"""
|
||||
|
||||
C = self.mesh.edgeCurl
|
||||
S_m, S_e = src.eval(self)
|
||||
s_m, s_e = src.eval(self)
|
||||
MfMui = self.MfMui
|
||||
|
||||
if self._makeASymmetric and adjoint:
|
||||
v = self.MfMui * v
|
||||
|
||||
MeSigmaIDeriv = self.MeSigmaIDeriv(S_e)
|
||||
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
MeSigmaIDeriv = self.MeSigmaIDeriv(s_e)
|
||||
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
|
||||
if not adjoint:
|
||||
RHSderiv = C * (MeSigmaIDeriv * v)
|
||||
SrcDeriv = S_mDeriv(v) + C * (self.MeSigmaI * S_eDeriv(v))
|
||||
SrcDeriv = s_mDeriv(v) + C * (self.MeSigmaI * s_eDeriv(v))
|
||||
elif adjoint:
|
||||
RHSderiv = MeSigmaIDeriv.T * (C.T * v)
|
||||
SrcDeriv = S_mDeriv(v) + self.MeSigmaI.T * (C.T * S_eDeriv(v))
|
||||
SrcDeriv = s_mDeriv(v) + self.MeSigmaI.T * (C.T * s_eDeriv(v))
|
||||
|
||||
if self._makeASymmetric is True and not adjoint:
|
||||
return MfMui.T * (SrcDeriv + RHSderiv)
|
||||
@@ -436,7 +437,7 @@ class Problem_b(BaseFDEMProblem):
|
||||
##########################################################################################
|
||||
|
||||
|
||||
class Problem_j(BaseFDEMProblem):
|
||||
class Problem3D_j(BaseFDEMProblem):
|
||||
"""
|
||||
We eliminate \\\(\\\mathbf{h}\\\) using
|
||||
|
||||
@@ -444,6 +445,7 @@ class Problem_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 ::
|
||||
@@ -453,12 +455,12 @@ class Problem_j(BaseFDEMProblem):
|
||||
.. note::
|
||||
This implementation does not yet work with full anisotropy!!
|
||||
|
||||
:param SimPEG.Mesh mesh: mesh
|
||||
:param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh
|
||||
"""
|
||||
|
||||
_solutionType = 'jSolution'
|
||||
_formulation = 'HJ'
|
||||
fieldsPair = Fields_j
|
||||
fieldsPair = Fields3D_j
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -497,12 +499,12 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
\\frac{\mathbf{A(\sigma)} \mathbf{v}}{d \mathbf{m}} = \mathbf{C} \mathbf{M^e_{mu^{-1}}} \mathbf{C^{\\top}} \\frac{d \mathbf{M^f_{\sigma^{-1}}}\mathbf{v} }{d \mathbf{m}}
|
||||
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nF,)
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nF,)
|
||||
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
"""
|
||||
|
||||
MeMuI = self.MeMuI
|
||||
@@ -522,22 +524,22 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Right hand side for the system
|
||||
Right hand side for the system
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{RHS} = \mathbf{C} \mathbf{M_{\mu}^e}^{-1}\mathbf{s_m} -i\omega \mathbf{s_e}
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray (nE, nSrc)
|
||||
:return: RHS
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
"""
|
||||
|
||||
S_m, S_e = self.getSourceTerm(freq)
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
C = self.mesh.edgeCurl
|
||||
MeMuI = self.MeMuI
|
||||
|
||||
RHS = C * (MeMuI * S_m) - 1j * omega(freq) * S_e
|
||||
RHS = C * (MeMuI * s_m) - 1j * omega(freq) * s_e
|
||||
if self._makeASymmetric is True:
|
||||
MfRho = self.MfRho
|
||||
return MfRho.T*RHS
|
||||
@@ -546,10 +548,10 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -558,16 +560,16 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
C = self.mesh.edgeCurl
|
||||
MeMuI = self.MeMuI
|
||||
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
|
||||
if adjoint:
|
||||
if self._makeASymmetric:
|
||||
MfRho = self.MfRho
|
||||
v = MfRho*v
|
||||
return S_mDeriv(MeMuI.T * (C.T * v)) - 1j * omega(freq) * S_eDeriv(v)
|
||||
return s_mDeriv(MeMuI.T * (C.T * v)) - 1j * omega(freq) * s_eDeriv(v)
|
||||
|
||||
else:
|
||||
RHSDeriv = C * (MeMuI * S_mDeriv(v)) - 1j * omega(freq) * S_eDeriv(v)
|
||||
RHSDeriv = C * (MeMuI * s_mDeriv(v)) - 1j * omega(freq) * s_eDeriv(v)
|
||||
|
||||
if self._makeASymmetric:
|
||||
MfRho = self.MfRho
|
||||
@@ -577,7 +579,7 @@ class Problem_j(BaseFDEMProblem):
|
||||
|
||||
|
||||
|
||||
class Problem_h(BaseFDEMProblem):
|
||||
class Problem3D_h(BaseFDEMProblem):
|
||||
"""
|
||||
We eliminate \\\(\\\mathbf{j}\\\) using
|
||||
|
||||
@@ -591,12 +593,12 @@ class Problem_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 mesh: mesh
|
||||
:param SimPEG.Mesh.BaseMesh.BaseMesh mesh: mesh
|
||||
"""
|
||||
|
||||
_solutionType = 'hSolution'
|
||||
_formulation = 'HJ'
|
||||
fieldsPair = Fields_h
|
||||
fieldsPair = Fields3D_h
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseFDEMProblem.__init__(self, mesh, **kwargs)
|
||||
@@ -608,9 +610,11 @@ class Problem_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
|
||||
@@ -626,12 +630,12 @@ class Problem_h(BaseFDEMProblem):
|
||||
.. math::
|
||||
\\frac{\mathbf{A}(\mathbf{m}) \mathbf{v}}{d \mathbf{m}} = \mathbf{C}^{\\top}\\frac{d \mathbf{M^f_{\\rho}}\mathbf{v} }{d\mathbf{m}}
|
||||
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nE,)
|
||||
:param float freq: frequency
|
||||
:param numpy.ndarray u: solution vector (nE,)
|
||||
:param numpy.ndarray v: vector to take prodct with (nP,) or (nD,) for adjoint
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
:return: derivative of the system matrix times a vector (nP,) or adjoint (nD,)
|
||||
"""
|
||||
|
||||
MeMu = self.MeMu
|
||||
@@ -644,46 +648,47 @@ class Problem_h(BaseFDEMProblem):
|
||||
|
||||
def getRHS(self, freq):
|
||||
"""
|
||||
Right hand side for the system
|
||||
Right hand side for the system
|
||||
|
||||
.. math ::
|
||||
|
||||
\mathbf{RHS} = \mathbf{M^e} \mathbf{s_m} + \mathbf{C}^{\\top} \mathbf{M_{\\rho}^f} \mathbf{s_e}
|
||||
|
||||
:param float freq: Frequency
|
||||
:rtype: numpy.ndarray
|
||||
:rtype: numpy.ndarray
|
||||
:return: RHS (nE, nSrc)
|
||||
|
||||
"""
|
||||
|
||||
S_m, S_e = self.getSourceTerm(freq)
|
||||
s_m, s_e = self.getSourceTerm(freq)
|
||||
C = self.mesh.edgeCurl
|
||||
MfRho = self.MfRho
|
||||
|
||||
return S_m + C.T * ( MfRho * S_e )
|
||||
return s_m + C.T * ( MfRho * s_e )
|
||||
|
||||
def getRHSDeriv(self, freq, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
Derivative of the right hand side with respect to the model
|
||||
|
||||
:param float freq: frequency
|
||||
:param SimPEG.EM.FDEM.Src src: FDEM source
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
:return: product of rhs deriv with a vector
|
||||
"""
|
||||
|
||||
_, S_e = src.eval(self)
|
||||
_, s_e = src.eval(self)
|
||||
C = self.mesh.edgeCurl
|
||||
MfRho = self.MfRho
|
||||
|
||||
MfRhoDeriv = self.MfRhoDeriv(S_e)
|
||||
MfRhoDeriv = self.MfRhoDeriv(s_e)
|
||||
if not adjoint:
|
||||
RHSDeriv = C.T * (MfRhoDeriv * v)
|
||||
elif adjoint:
|
||||
RHSDeriv = MfRhoDeriv.T * (C * v)
|
||||
|
||||
S_mDeriv, S_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
s_mDeriv, s_eDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
|
||||
return RHSDeriv + S_mDeriv(v) + C.T * (MfRho * S_eDeriv(v))
|
||||
return RHSDeriv + s_mDeriv(v) + C.T * (MfRho * s_eDeriv(v))
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import SimPEG
|
||||
from SimPEG import sp
|
||||
|
||||
class BaseRx(SimPEG.Survey.BaseRx):
|
||||
"""
|
||||
Frequency domain receiver base class
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
assert(orientation in ['x','y','z']), "Orientation %s not known. Orientation must be in 'x', 'y', 'z'. Arbitrary orientations have not yet been implemented."%orientation
|
||||
assert(component in ['real', 'imag']), "'component' must be 'real' or 'imag', not %s"%component
|
||||
|
||||
self.projComp = orientation
|
||||
self.component = component
|
||||
|
||||
SimPEG.Survey.BaseRx.__init__(self, locs, rxType=None) #TODO: remove rxType from baseRx
|
||||
|
||||
def projGLoc(self, u):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
return u._GLoc(self.projField) + self.projComp
|
||||
|
||||
def eval(self, src, mesh, f):
|
||||
"""
|
||||
Project fields to receivers to get data.
|
||||
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param BaseMesh mesh: mesh used
|
||||
:param Fields f: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
f_part_complex = f[src, self.projField]
|
||||
f_part = getattr(f_part_complex, self.component) # get the real or imag component
|
||||
|
||||
return P*f_part
|
||||
|
||||
def evalDeriv(self, src, mesh, f, v, adjoint=False):
|
||||
"""
|
||||
Derivative of projected fields with respect to the inversion model times a vector.
|
||||
|
||||
:param SimPEG.EM.FDEM.SrcFDEM.BaseSrc src: FDEM source
|
||||
:param BaseMesh mesh: mesh used
|
||||
:param Fields f: fields object
|
||||
:param numpy.ndarray v: vector to multiply
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
|
||||
if not adjoint:
|
||||
Pv_complex = P * v
|
||||
Pv = getattr(Pv_complex, self.component)
|
||||
elif adjoint:
|
||||
Pv_real = P.T * v
|
||||
|
||||
if self.component == 'imag':
|
||||
Pv = 1j*Pv_real
|
||||
elif self.component == 'real':
|
||||
Pv = Pv_real.astype(complex)
|
||||
else:
|
||||
raise NotImplementedError('must be real or imag')
|
||||
|
||||
return Pv
|
||||
|
||||
|
||||
class Point_e(BaseRx):
|
||||
"""
|
||||
Electric field FDEM receiver
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
self.projField = 'e'
|
||||
super(Point_e, self).__init__(locs, orientation, component)
|
||||
|
||||
|
||||
class Point_b(BaseRx):
|
||||
"""
|
||||
Magnetic flux FDEM receiver
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
self.projField = 'b'
|
||||
super(Point_b, self).__init__(locs, orientation, component)
|
||||
|
||||
|
||||
class Point_h(BaseRx):
|
||||
"""
|
||||
Magnetic field FDEM receiver
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
self.projField = 'h'
|
||||
super(Point_h, self).__init__(locs, orientation, component)
|
||||
|
||||
|
||||
class Point_j(BaseRx):
|
||||
"""
|
||||
Current density FDEM receiver
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string orientation: receiver orientation 'x', 'y' or 'z'
|
||||
:param string component: real or imaginary component 'real' or 'imag'
|
||||
"""
|
||||
|
||||
def __init__(self, locs, orientation=None, component=None):
|
||||
self.projField = 'j'
|
||||
super(Point_j, self).__init__(locs, orientation, component)
|
||||
+104
-95
@@ -9,105 +9,118 @@ class BaseSrc(Survey.BaseSrc):
|
||||
"""
|
||||
|
||||
freq = None
|
||||
# rxPair = RxFDEM
|
||||
integrate = True
|
||||
integrate = False
|
||||
_ePrimary = None
|
||||
_bPrimary = None
|
||||
_hPrimary = None
|
||||
_jPrimary = None
|
||||
|
||||
def __init__(self, rxList, **kwargs):
|
||||
Survey.BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
"""
|
||||
Evaluate the source terms.
|
||||
- :math:`S_m` : magnetic source term
|
||||
- :math:`S_e` : electric source term
|
||||
- :math:`s_m` : magnetic source term
|
||||
- :math:`s_e` : electric source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: tuple
|
||||
:return: tuple with magnetic source term and electric source term
|
||||
"""
|
||||
S_m = self.S_m(prob)
|
||||
S_e = self.S_e(prob)
|
||||
return S_m, S_e
|
||||
s_m = self.s_m(prob)
|
||||
s_e = self.s_e(prob)
|
||||
return s_m, s_e
|
||||
|
||||
def evalDeriv(self, prob, v=None, adjoint=False):
|
||||
"""
|
||||
Derivatives of the source terms with respect to the inversion model
|
||||
- :code:`S_mDeriv` : derivative of the magnetic source term
|
||||
- :code:`S_eDeriv` : derivative of the electric source term
|
||||
- :code:`s_mDeriv` : derivative of the magnetic source term
|
||||
- :code:`s_eDeriv` : derivative of the electric source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:rtype: tuple
|
||||
:return: tuple with magnetic source term and electric source term derivatives times a vector
|
||||
"""
|
||||
if v is not None:
|
||||
return self.S_mDeriv(prob, v, adjoint), self.S_eDeriv(prob, v, adjoint)
|
||||
return self.s_mDeriv(prob, v, adjoint), self.s_eDeriv(prob, v, adjoint)
|
||||
else:
|
||||
return lambda v: self.S_mDeriv(prob, v, adjoint), lambda v: self.S_eDeriv(prob, v, adjoint)
|
||||
return lambda v: self.s_mDeriv(prob, v, adjoint), lambda v: self.s_eDeriv(prob, v, adjoint)
|
||||
|
||||
def bPrimary(self, prob):
|
||||
"""
|
||||
Primary magnetic flux density
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic flux density
|
||||
"""
|
||||
return Zero()
|
||||
if self._bPrimary is None:
|
||||
return Zero()
|
||||
return self._bPrimary
|
||||
|
||||
def hPrimary(self, prob):
|
||||
"""
|
||||
Primary magnetic field
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
return Zero()
|
||||
if self._hPrimary is None:
|
||||
return Zero()
|
||||
return self._hPrimary
|
||||
|
||||
def ePrimary(self, prob):
|
||||
"""
|
||||
Primary electric field
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary electric field
|
||||
"""
|
||||
return Zero()
|
||||
if self._ePrimary is None:
|
||||
return Zero()
|
||||
return self._ePrimary
|
||||
|
||||
def jPrimary(self, prob):
|
||||
"""
|
||||
Primary current density
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary current density
|
||||
"""
|
||||
return Zero()
|
||||
if self._jPrimary is None:
|
||||
return Zero()
|
||||
return self._jPrimary
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: magnetic source term on mesh
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: electric source term on mesh
|
||||
"""
|
||||
return Zero()
|
||||
|
||||
def S_mDeriv(self, prob, v, adjoint = False):
|
||||
def s_mDeriv(self, prob, v, adjoint = False):
|
||||
"""
|
||||
Derivative of magnetic source term with respect to the inversion model
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -116,11 +129,11 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
return Zero()
|
||||
|
||||
def S_eDeriv(self, prob, v, adjoint = False):
|
||||
def s_eDeriv(self, prob, v, adjoint = False):
|
||||
"""
|
||||
Derivative of electric source term with respect to the inversion model
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:param numpy.ndarray v: vector to take product with
|
||||
:param bool adjoint: adjoint?
|
||||
:rtype: numpy.ndarray
|
||||
@@ -131,104 +144,101 @@ class BaseSrc(Survey.BaseSrc):
|
||||
|
||||
class RawVec_e(BaseSrc):
|
||||
"""
|
||||
RawVec electric source. It is defined by the user provided vector S_e
|
||||
RawVec electric source. It is defined by the user provided vector s_e
|
||||
|
||||
:param list rxList: receiver list
|
||||
:param float freq: frequency
|
||||
:param numpy.array S_e: electric source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [True]
|
||||
:param numpy.array s_e: electric source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, S_e, integrate=True): #, ePrimary=None, bPrimary=None, hPrimary=None, jPrimary=None):
|
||||
self._S_e = np.array(S_e, dtype=complex)
|
||||
def __init__(self, rxList, freq, s_e, **kwargs):
|
||||
self._s_e = np.array(s_e, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
|
||||
BaseSrc.__init__(self, rxList)
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: electric source term on mesh
|
||||
"""
|
||||
if prob._formulation is 'EB' and self.integrate is True:
|
||||
return prob.Me * self._S_e
|
||||
return self._S_e
|
||||
return prob.Me * self._s_e
|
||||
return self._s_e
|
||||
|
||||
|
||||
class RawVec_m(BaseSrc):
|
||||
"""
|
||||
RawVec magnetic source. It is defined by the user provided vector S_m
|
||||
RawVec magnetic source. It is defined by the user provided vector s_m
|
||||
|
||||
:param float freq: frequency
|
||||
:param rxList: receiver list
|
||||
:param numpy.array S_m: magnetic source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [True]
|
||||
:param numpy.array s_m: magnetic source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, S_m, integrate=True): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()):
|
||||
self._S_m = np.array(S_m, dtype=complex)
|
||||
def __init__(self, rxList, freq, s_m, **kwargs): #ePrimary=Zero(), bPrimary=Zero(), hPrimary=Zero(), jPrimary=Zero()):
|
||||
self._s_m = np.array(s_m, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
|
||||
BaseSrc.__init__(self, rxList)
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: magnetic source term on mesh
|
||||
"""
|
||||
if prob._formulation is 'HJ' and self.integrate is True:
|
||||
return prob.Me * self._S_m
|
||||
return self._S_m
|
||||
return prob.Me * self._s_m
|
||||
return self._s_m
|
||||
|
||||
|
||||
class RawVec(BaseSrc):
|
||||
"""
|
||||
RawVec source. It is defined by the user provided vectors S_m, S_e
|
||||
RawVec source. It is defined by the user provided vectors s_m, s_e
|
||||
|
||||
:param rxList: receiver list
|
||||
:param float freq: frequency
|
||||
:param numpy.array S_m: magnetic source term
|
||||
:param numpy.array S_e: electric source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [True]
|
||||
:param numpy.array s_m: magnetic source term
|
||||
:param numpy.array s_e: electric source term
|
||||
:param bool integrate: Integrate the source term (multiply by Me) [False]
|
||||
"""
|
||||
def __init__(self, rxList, freq, S_m, S_e, integrate=True):
|
||||
self._S_m = np.array(S_m, dtype=complex)
|
||||
self._S_e = np.array(S_e, dtype=complex)
|
||||
def __init__(self, rxList, freq, s_m, s_e, **kwargs):
|
||||
self._s_m = np.array(s_m, dtype=complex)
|
||||
self._s_e = np.array(s_e, dtype=complex)
|
||||
self.freq = float(freq)
|
||||
self.integrate = integrate
|
||||
BaseSrc.__init__(self, rxList)
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
Magnetic source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: magnetic source term on mesh
|
||||
"""
|
||||
if prob._formulation is 'HJ' and self.integrate is True:
|
||||
return prob.Me * self._S_m
|
||||
return self._S_m
|
||||
return prob.Me * self._s_m
|
||||
return self._s_m
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
Electric source term
|
||||
|
||||
:param Problem prob: FDEM Problem
|
||||
:param BaseFDEMProblem prob: FDEM Problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: electric source term on mesh
|
||||
"""
|
||||
if prob._formulation is 'EB' and self.integrate is True:
|
||||
return prob.Me * self._S_e
|
||||
return self._S_e
|
||||
return prob.Me * self._s_e
|
||||
return self._s_e
|
||||
|
||||
|
||||
class MagDipole(BaseSrc):
|
||||
@@ -278,21 +288,20 @@ class MagDipole(BaseSrc):
|
||||
:param float mu: background magnetic permeability
|
||||
"""
|
||||
|
||||
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu=mu_0):
|
||||
def __init__(self, rxList, freq, loc, orientation='Z', moment=1., mu=mu_0, **kwargs):
|
||||
self.freq = float(freq)
|
||||
self.loc = loc
|
||||
self.orientation = orientation
|
||||
assert orientation in ['X','Y','Z'], "Orientation (right now) doesn't actually do anything! The methods in SrcUtils should take care of this..."
|
||||
self.moment = moment
|
||||
self.mu = mu
|
||||
self.integrate = False
|
||||
BaseSrc.__init__(self, rxList)
|
||||
|
||||
def bPrimary(self, prob):
|
||||
"""
|
||||
The primary magnetic flux density from a magnetic vector potential
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -330,32 +339,32 @@ class MagDipole(BaseSrc):
|
||||
"""
|
||||
The primary magnetic field from a magnetic vector potential
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
b = self.bPrimary(prob)
|
||||
return 1./self.mu * b
|
||||
return 1./self.mu * b
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
|
||||
b_p = self.bPrimary(prob)
|
||||
if prob._formulation is 'HJ':
|
||||
b_p = prob.Me * b_p
|
||||
b_p = prob.Me * b_p
|
||||
return -1j*omega(self.freq)*b_p
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -407,7 +416,7 @@ class MagDipole_Bfield(BaseSrc):
|
||||
"""
|
||||
The primary magnetic flux density from the analytic solution for magnetic fields from a dipole
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -446,18 +455,18 @@ class MagDipole_Bfield(BaseSrc):
|
||||
"""
|
||||
The primary magnetic field from a magnetic vector potential
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
b = self.bPrimary(prob)
|
||||
return 1/self.mu * b
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -466,11 +475,11 @@ class MagDipole_Bfield(BaseSrc):
|
||||
b = prob.Me * b
|
||||
return -1j*omega(self.freq)*b
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -521,7 +530,7 @@ class CircularLoop(BaseSrc):
|
||||
"""
|
||||
The primary magnetic flux density from a magnetic vector potential
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -543,7 +552,7 @@ class CircularLoop(BaseSrc):
|
||||
if not prob.mesh.isSymmetric:
|
||||
# TODO ?
|
||||
raise NotImplementedError('Non-symmetric cyl mesh not implemented yet!')
|
||||
a = MagneticDipoleVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
|
||||
a = MagneticLoopVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
|
||||
|
||||
else:
|
||||
srcfct = MagneticDipoleVectorPotential
|
||||
@@ -558,18 +567,18 @@ class CircularLoop(BaseSrc):
|
||||
"""
|
||||
The primary magnetic field from a magnetic vector potential
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
b = self.bPrimary(prob)
|
||||
return 1./self.mu*b
|
||||
|
||||
def S_m(self, prob):
|
||||
def s_m(self, prob):
|
||||
"""
|
||||
The magnetic source term
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -578,11 +587,11 @@ class CircularLoop(BaseSrc):
|
||||
b = prob.Me * b
|
||||
return -1j*omega(self.freq)*b
|
||||
|
||||
def S_e(self, prob):
|
||||
def s_e(self, prob):
|
||||
"""
|
||||
The electric source term
|
||||
|
||||
:param Problem prob: FDEM problem
|
||||
:param BaseFDEMProblem prob: FDEM problem
|
||||
:rtype: numpy.ndarray
|
||||
:return: primary magnetic field
|
||||
"""
|
||||
@@ -604,6 +613,6 @@ class CircularLoop(BaseSrc):
|
||||
|
||||
return -C.T * (MMui_s * self.bPrimary(prob))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,129 +1,13 @@
|
||||
import SimPEG
|
||||
from SimPEG.EM.Utils import *
|
||||
from SimPEG.EM.Base import BaseEMSurvey
|
||||
from scipy.constants import mu_0
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
import SrcFDEM as Src
|
||||
import RxFDEM as Rx
|
||||
from SimPEG import sp
|
||||
|
||||
|
||||
####################################################
|
||||
# Receivers
|
||||
####################################################
|
||||
|
||||
class Rx(SimPEG.Survey.BaseRx):
|
||||
"""
|
||||
Frequency domain receivers
|
||||
|
||||
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
|
||||
:param string rxType: reciever type from knownRxTypes
|
||||
"""
|
||||
|
||||
knownRxTypes = {
|
||||
'exr':['e', 'x', 'real'],
|
||||
'eyr':['e', 'y', 'real'],
|
||||
'ezr':['e', 'z', 'real'],
|
||||
'exi':['e', 'x', 'imag'],
|
||||
'eyi':['e', 'y', 'imag'],
|
||||
'ezi':['e', 'z', 'imag'],
|
||||
|
||||
'bxr':['b', 'x', 'real'],
|
||||
'byr':['b', 'y', 'real'],
|
||||
'bzr':['b', 'z', 'real'],
|
||||
'bxi':['b', 'x', 'imag'],
|
||||
'byi':['b', 'y', 'imag'],
|
||||
'bzi':['b', 'z', 'imag'],
|
||||
|
||||
'jxr':['j', 'x', 'real'],
|
||||
'jyr':['j', 'y', 'real'],
|
||||
'jzr':['j', 'z', 'real'],
|
||||
'jxi':['j', 'x', 'imag'],
|
||||
'jyi':['j', 'y', 'imag'],
|
||||
'jzi':['j', 'z', 'imag'],
|
||||
|
||||
'hxr':['h', 'x', 'real'],
|
||||
'hyr':['h', 'y', 'real'],
|
||||
'hzr':['h', 'z', 'real'],
|
||||
'hxi':['h', 'x', 'imag'],
|
||||
'hyi':['h', 'y', 'imag'],
|
||||
'hzi':['h', 'z', 'imag'],
|
||||
}
|
||||
radius = None
|
||||
|
||||
def __init__(self, locs, rxType):
|
||||
SimPEG.Survey.BaseRx.__init__(self, locs, rxType)
|
||||
|
||||
@property
|
||||
def projField(self):
|
||||
"""Field Type projection (e.g. e b ...)"""
|
||||
return self.knownRxTypes[self.rxType][0]
|
||||
|
||||
@property
|
||||
def projComp(self):
|
||||
"""Component projection (real/imag)"""
|
||||
return self.knownRxTypes[self.rxType][2]
|
||||
|
||||
def projGLoc(self, u):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
return u._GLoc(self.rxType[0]) + self.knownRxTypes[self.rxType][1]
|
||||
|
||||
def eval(self, src, mesh, u):
|
||||
"""
|
||||
Project fields to recievers to get data.
|
||||
|
||||
:param Source src: FDEM source
|
||||
:param Mesh mesh: mesh used
|
||||
:param Fields f: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
# projGLoc = u._GLoc(self.knownRxTypes[self.rxType][0])
|
||||
# projGLoc += self.knownRxTypes[self.rxType][1]
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(u))
|
||||
u_part_complex = u[src, self.projField]
|
||||
# get the real or imag component
|
||||
real_or_imag = self.projComp
|
||||
u_part = getattr(u_part_complex, real_or_imag)
|
||||
|
||||
return P*u_part
|
||||
|
||||
def evalDeriv(self, src, mesh, u, v, adjoint=False):
|
||||
"""
|
||||
Derivative of projected fields with respect to the inversion model times a vector.
|
||||
|
||||
:param Source src: FDEM source
|
||||
:param Mesh mesh: mesh used
|
||||
:param Fields u: fields object
|
||||
:param numpy.ndarray v: vector to multiply
|
||||
:rtype: numpy.ndarray
|
||||
:return: fields projected to recievers
|
||||
"""
|
||||
|
||||
P = self.getP(mesh, self.projGLoc(u))
|
||||
|
||||
if not adjoint:
|
||||
Pv_complex = P * v
|
||||
real_or_imag = self.projComp
|
||||
Pv = getattr(Pv_complex, real_or_imag)
|
||||
elif adjoint:
|
||||
Pv_real = P.T * v
|
||||
|
||||
real_or_imag = self.projComp
|
||||
if real_or_imag == 'imag':
|
||||
Pv = 1j*Pv_real
|
||||
elif real_or_imag == 'real':
|
||||
Pv = Pv_real.astype(complex)
|
||||
else:
|
||||
raise NotImplementedError('must be real or imag')
|
||||
|
||||
return Pv
|
||||
|
||||
|
||||
####################################################
|
||||
# Survey
|
||||
####################################################
|
||||
|
||||
class Survey(SimPEG.Survey.BaseSurvey):
|
||||
class Survey(BaseEMSurvey):
|
||||
"""
|
||||
Frequency domain electromagnetic survey
|
||||
|
||||
@@ -131,12 +15,12 @@ class Survey(SimPEG.Survey.BaseSurvey):
|
||||
"""
|
||||
|
||||
srcPair = Src.BaseSrc
|
||||
rxPaair = Rx
|
||||
rxPair = Rx.BaseRx
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
# Sort these by frequency
|
||||
self.srcList = srcList
|
||||
SimPEG.Survey.BaseSurvey.__init__(self, **kwargs)
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
|
||||
_freqDict = {}
|
||||
for src in srcList:
|
||||
@@ -171,24 +55,8 @@ class Survey(SimPEG.Survey.BaseSurvey):
|
||||
Returns the sources associated with a specific frequency.
|
||||
:param float freq: frequency for which we look up sources
|
||||
:rtype: dictionary
|
||||
:return: sources at the sepcified frequency
|
||||
:return: sources at the sepcified frequency
|
||||
"""
|
||||
assert freq in self._freqDict, "The requested frequency is not in this survey."
|
||||
return self._freqDict[freq]
|
||||
|
||||
def eval(self, u):
|
||||
"""
|
||||
Project fields to receiver locations
|
||||
:param Fields u: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: data
|
||||
"""
|
||||
data = SimPEG.Survey.Data(self)
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.eval(src, self.mesh, u)
|
||||
return data
|
||||
|
||||
def evalDeriv(self, u):
|
||||
raise Exception('Use Receivers to project fields deriv.')
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
from SurveyFDEM import Rx, Src, Survey
|
||||
from FDEM import BaseFDEMProblem, Problem_e, Problem_b, Problem_j, Problem_h
|
||||
from FieldsFDEM import *
|
||||
from SurveyFDEM import Survey
|
||||
import SrcFDEM as Src
|
||||
import RxFDEM as Rx
|
||||
from ProblemFDEM import Problem3D_e, Problem3D_b, Problem3D_j, Problem3D_h
|
||||
from FieldsFDEM import Fields3D_e, Fields3D_b, Fields3D_j, Fields3D_h
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
import numpy as np
|
||||
|
||||
def getxBCyBC_CC(mesh, alpha, beta, gamma):
|
||||
# def getxBCyBC(mesh, alpha, beta, gamma):
|
||||
"""
|
||||
This is a subfunction generating mixed-boundary condition:
|
||||
|
||||
.. math::
|
||||
|
||||
\nabla \cdot \vec{j} = -\nabla \cdot \vec{j}_s = q
|
||||
|
||||
\rho \vec{j} = -\nabla \phi \phi
|
||||
|
||||
\alpha \phi + \beta \frac{\partial \phi}{\partial r} = \gamma \ at \ r = \partial \Omega
|
||||
|
||||
xBC = f_1(\alpha, \beta, \gamma)
|
||||
yBC = f(\alpha, \beta, \gamma)
|
||||
|
||||
Computes xBC and yBC for cell-centered discretizations
|
||||
"""
|
||||
if mesh.dim == 1: #1D
|
||||
if (len(alpha) != 2 or len(beta) != 2 or len(gamma) != 2):
|
||||
raise Exception("Lenght of list, alpha should be 2")
|
||||
fCCxm,fCCxp = mesh.cellBoundaryInd
|
||||
nBC = fCCxm.sum()+fCCxp.sum()
|
||||
h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp]
|
||||
|
||||
alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0]
|
||||
alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1]
|
||||
|
||||
# h_xm, h_xp = mesh.gridCC[fCCxm], mesh.gridCC[fCCxp]
|
||||
h_xm, h_xp = mesh.hx[0], mesh.hx[-1]
|
||||
|
||||
a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
|
||||
xBC_xm = 0.5*a_xm
|
||||
xBC_xp = 0.5*a_xp/b_xp
|
||||
yBC_xm = 0.5*(1.-b_xm)
|
||||
yBC_xp = 0.5*(1.-1./b_xp)
|
||||
|
||||
xBC = np.r_[xBC_xm, xBC_xp]
|
||||
yBC = np.r_[yBC_xm, yBC_xp]
|
||||
|
||||
elif mesh.dim == 2: #2D
|
||||
if (len(alpha) != 4 or len(beta) != 4 or len(gamma) != 4):
|
||||
raise Exception("Lenght of list, alpha should be 4")
|
||||
|
||||
fxm,fxp,fym,fyp = mesh.faceBoundaryInd
|
||||
nBC = fxm.sum()+fxp.sum()+fxm.sum()+fxp.sum()
|
||||
|
||||
alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0]
|
||||
alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1]
|
||||
alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2]
|
||||
alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3]
|
||||
|
||||
# h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0]
|
||||
# h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1]
|
||||
|
||||
h_xm, h_xp = mesh.hx[0]*np.ones_like(alpha_xm), mesh.hx[-1]*np.ones_like(alpha_xp)
|
||||
h_ym, h_yp = mesh.hy[0]*np.ones_like(alpha_ym), mesh.hy[-1]*np.ones_like(alpha_yp)
|
||||
|
||||
a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
|
||||
a_ym = gamma_ym/(0.5*alpha_ym-beta_ym/h_ym)
|
||||
b_ym = (0.5*alpha_ym+beta_ym/h_ym)/(0.5*alpha_ym-beta_ym/h_ym)
|
||||
a_yp = gamma_yp/(0.5*alpha_yp-beta_yp/h_yp)
|
||||
b_yp = (0.5*alpha_yp+beta_yp/h_yp)/(0.5*alpha_yp-beta_yp/h_yp)
|
||||
|
||||
xBC_xm = 0.5*a_xm
|
||||
xBC_xp = 0.5*a_xp/b_xp
|
||||
yBC_xm = 0.5*(1.-b_xm)
|
||||
yBC_xp = 0.5*(1.-1./b_xp)
|
||||
xBC_ym = 0.5*a_ym
|
||||
xBC_yp = 0.5*a_yp/b_yp
|
||||
yBC_ym = 0.5*(1.-b_ym)
|
||||
yBC_yp = 0.5*(1.-1./b_yp)
|
||||
|
||||
sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]])
|
||||
sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]])
|
||||
|
||||
xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx]
|
||||
xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy]
|
||||
yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx]
|
||||
yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy]
|
||||
|
||||
xBC = np.r_[xBC_x, xBC_y]
|
||||
yBC = np.r_[yBC_x, yBC_y]
|
||||
|
||||
elif mesh.dim == 3: #3D
|
||||
if (len(alpha) != 6 or len(beta) != 6 or len(gamma) != 6):
|
||||
raise Exception("Lenght of list, alpha should be 6")
|
||||
# fCCxm,fCCxp,fCCym,fCCyp,fCCzm,fCCzp = mesh.cellBoundaryInd
|
||||
fxm,fxp,fym,fyp,fzm,fzp = mesh.faceBoundaryInd
|
||||
nBC = fxm.sum()+fxp.sum()+fxm.sum()+fxp.sum()
|
||||
|
||||
alpha_xm, beta_xm, gamma_xm = alpha[0], beta[0], gamma[0]
|
||||
alpha_xp, beta_xp, gamma_xp = alpha[1], beta[1], gamma[1]
|
||||
alpha_ym, beta_ym, gamma_ym = alpha[2], beta[2], gamma[2]
|
||||
alpha_yp, beta_yp, gamma_yp = alpha[3], beta[3], gamma[3]
|
||||
alpha_zm, beta_zm, gamma_zm = alpha[4], beta[4], gamma[4]
|
||||
alpha_zp, beta_zp, gamma_zp = alpha[5], beta[5], gamma[5]
|
||||
|
||||
# h_xm, h_xp = mesh.gridCC[fCCxm,0], mesh.gridCC[fCCxp,0]
|
||||
# h_ym, h_yp = mesh.gridCC[fCCym,1], mesh.gridCC[fCCyp,1]
|
||||
# h_zm, h_zp = mesh.gridCC[fCCzm,2], mesh.gridCC[fCCzp,2]
|
||||
|
||||
h_xm, h_xp = mesh.hx[0]*np.ones_like(alpha_xm), mesh.hx[-1]*np.ones_like(alpha_xp)
|
||||
h_ym, h_yp = mesh.hy[0]*np.ones_like(alpha_ym), mesh.hy[-1]*np.ones_like(alpha_yp)
|
||||
h_zm, h_zp = mesh.hz[0]*np.ones_like(alpha_zm), mesh.hz[-1]*np.ones_like(alpha_zp)
|
||||
|
||||
a_xm = gamma_xm/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
b_xm = (0.5*alpha_xm+beta_xm/h_xm)/(0.5*alpha_xm-beta_xm/h_xm)
|
||||
a_xp = gamma_xp/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
b_xp = (0.5*alpha_xp+beta_xp/h_xp)/(0.5*alpha_xp-beta_xp/h_xp)
|
||||
|
||||
a_ym = gamma_ym/(0.5*alpha_ym-beta_ym/h_ym)
|
||||
b_ym = (0.5*alpha_ym+beta_ym/h_ym)/(0.5*alpha_ym-beta_ym/h_ym)
|
||||
a_yp = gamma_yp/(0.5*alpha_yp-beta_yp/h_yp)
|
||||
b_yp = (0.5*alpha_yp+beta_yp/h_yp)/(0.5*alpha_yp-beta_yp/h_yp)
|
||||
|
||||
a_zm = gamma_zm/(0.5*alpha_zm-beta_zm/h_zm)
|
||||
b_zm = (0.5*alpha_zm+beta_zm/h_zm)/(0.5*alpha_zm-beta_zm/h_zm)
|
||||
a_zp = gamma_zp/(0.5*alpha_zp-beta_zp/h_zp)
|
||||
b_zp = (0.5*alpha_zp+beta_zp/h_zp)/(0.5*alpha_zp-beta_zp/h_zp)
|
||||
|
||||
xBC_xm = 0.5*a_xm
|
||||
xBC_xp = 0.5*a_xp/b_xp
|
||||
yBC_xm = 0.5*(1.-b_xm)
|
||||
yBC_xp = 0.5*(1.-1./b_xp)
|
||||
xBC_ym = 0.5*a_ym
|
||||
xBC_yp = 0.5*a_yp/b_yp
|
||||
yBC_ym = 0.5*(1.-b_ym)
|
||||
yBC_yp = 0.5*(1.-1./b_yp)
|
||||
xBC_zm = 0.5*a_zm
|
||||
xBC_zp = 0.5*a_zp/b_zp
|
||||
yBC_zm = 0.5*(1.-b_zm)
|
||||
yBC_zp = 0.5*(1.-1./b_zp)
|
||||
|
||||
sortindsfx = np.argsort(np.r_[np.arange(mesh.nFx)[fxm], np.arange(mesh.nFx)[fxp]])
|
||||
sortindsfy = np.argsort(np.r_[np.arange(mesh.nFy)[fym], np.arange(mesh.nFy)[fyp]])
|
||||
sortindsfz = np.argsort(np.r_[np.arange(mesh.nFz)[fzm], np.arange(mesh.nFz)[fzp]])
|
||||
|
||||
xBC_x = np.r_[xBC_xm, xBC_xp][sortindsfx]
|
||||
xBC_y = np.r_[xBC_ym, xBC_yp][sortindsfy]
|
||||
xBC_z = np.r_[xBC_zm, xBC_zp][sortindsfz]
|
||||
|
||||
yBC_x = np.r_[yBC_xm, yBC_xp][sortindsfx]
|
||||
yBC_y = np.r_[yBC_ym, yBC_yp][sortindsfy]
|
||||
yBC_z = np.r_[yBC_zm, yBC_zp][sortindsfz]
|
||||
|
||||
xBC = np.r_[xBC_x, xBC_y, xBC_z]
|
||||
yBC = np.r_[yBC_x, yBC_y, yBC_z]
|
||||
|
||||
return xBC, yBC
|
||||
@@ -0,0 +1,148 @@
|
||||
import SimPEG
|
||||
from SimPEG.Utils import Identity, Zero
|
||||
import numpy as np
|
||||
from scipy.constants import epsilon_0
|
||||
|
||||
class Fields(SimPEG.Problem.Fields):
|
||||
knownFields = {}
|
||||
dtype = float
|
||||
|
||||
def _phiDeriv(self, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_phiDeriv_u', None) is None or getattr(self, '_phiDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting phiDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._phiDeriv_u(src, v, adjoint=adjoint), self._phiDeriv_m(src, v, adjoint=adjoint)
|
||||
|
||||
return np.array(self._phiDeriv_u(src, du_dm_v, adjoint) + self._phiDeriv_m(src, v, adjoint), dtype = float)
|
||||
|
||||
def _eDeriv(self, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._eDeriv_u(src, v, adjoint), self._eDeriv_m(src, v, adjoint)
|
||||
return np.array(self._eDeriv_u(src, du_dm_v, adjoint) + self._eDeriv_m(src, v, adjoint), dtype = float)
|
||||
|
||||
def _jDeriv(self, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint)
|
||||
return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = float)
|
||||
|
||||
|
||||
class Fields_CC(Fields):
|
||||
knownFields = {'phiSolution':'CC'}
|
||||
aliasFields = {
|
||||
'phi': ['phiSolution','CC','_phi'],
|
||||
'j' : ['phiSolution','F','_j'],
|
||||
'e' : ['phiSolution','F','_e'],
|
||||
'charge' : ['phiSolution','CC','_charge'],
|
||||
}
|
||||
# primary - secondary
|
||||
# CC variables
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields.__init__(self, mesh, survey, **kwargs)
|
||||
mesh.setCellGradBC("neumann")
|
||||
cellGrad = mesh.cellGrad
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
|
||||
def _GLoc(self, fieldType):
|
||||
if fieldType == 'phi':
|
||||
return 'CC'
|
||||
elif fieldType == 'e' or fieldType == 'j':
|
||||
return 'F'
|
||||
else:
|
||||
raise Exception('Field type must be phi, e, j')
|
||||
|
||||
def _phi(self, phiSolution, srcList):
|
||||
return phiSolution
|
||||
|
||||
def _phiDeriv_u(self, src, v, adjoint = False):
|
||||
return Identity()*v
|
||||
|
||||
def _phiDeriv_m(self, src, v, adjoint = False):
|
||||
return Zero()
|
||||
|
||||
def _j(self, phiSolution, srcList):
|
||||
"""
|
||||
.. math::
|
||||
\mathbf{j} = \mathbf{M}^{f \ -1}_{\rho} \mathbf{G} \phi
|
||||
"""
|
||||
return self.prob.MfRhoI*self.prob.Grad*phiSolution
|
||||
|
||||
def _e(self, phiSolution, srcList):
|
||||
"""
|
||||
In HJ formulation e is not well-defined!!
|
||||
.. math::
|
||||
\vec{e} = -\nabla \phi
|
||||
"""
|
||||
return -self.mesh.cellGrad*phiSolution
|
||||
|
||||
def _charge(self, phiSolution, srcList):
|
||||
"""
|
||||
.. math::
|
||||
\int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0}
|
||||
"""
|
||||
return epsilon_0*self.prob.Vol*(self.mesh.faceDiv*self._e(phiSolution, srcList))
|
||||
|
||||
class Fields_N(Fields):
|
||||
knownFields = {'phiSolution':'N'}
|
||||
aliasFields = {
|
||||
'phi': ['phiSolution','N','_phi'],
|
||||
'j' : ['phiSolution','E','_j'],
|
||||
'e' : ['phiSolution','E','_e'],
|
||||
'charge' : ['phiSolution','N','_charge'],
|
||||
}
|
||||
# primary - secondary
|
||||
# N variables
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields.__init__(self, mesh, survey, **kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
|
||||
def _GLoc(self, fieldType):
|
||||
if fieldType == 'phi':
|
||||
return 'N'
|
||||
elif fieldType == 'e' or fieldType == 'j':
|
||||
return 'E'
|
||||
else:
|
||||
raise Exception('Field type must be phi, e, j')
|
||||
|
||||
def _phi(self, phiSolution, srcList):
|
||||
return phiSolution
|
||||
|
||||
def _phiDeriv_u(self, src, v, adjoint = False):
|
||||
return Identity()*v
|
||||
|
||||
def _phiDeriv_m(self, src, v, adjoint = False):
|
||||
return Zero()
|
||||
|
||||
def _j(self, phiSolution, srcList):
|
||||
"""
|
||||
In EB formulation j is not well-defined!!
|
||||
.. math::
|
||||
\mathbf{j} = - \mathbf{M}^{e}_{\sigma} \mathbf{G} \phi
|
||||
"""
|
||||
return self.prob.MeSigma * self._e(phiSolution, srcList)
|
||||
|
||||
def _e(self, phiSolution, srcList):
|
||||
"""
|
||||
In HJ formulation e is not well-defined!!
|
||||
.. math::
|
||||
\vec{e} = -\nabla \phi
|
||||
"""
|
||||
return -self.mesh.nodalGrad * phiSolution
|
||||
|
||||
def _charge(self, phiSolution, srcList):
|
||||
"""
|
||||
.. math::
|
||||
\int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0}
|
||||
"""
|
||||
return - epsilon_0*(self.mesh.nodalGrad.T*self.mesh.getEdgeInnerProduct()*self._e(phiSolution, srcList))
|
||||
@@ -0,0 +1,146 @@
|
||||
import SimPEG
|
||||
from SimPEG.Utils import Identity, Zero
|
||||
import numpy as np
|
||||
|
||||
class Fields_ky(SimPEG.Problem.TimeFields):
|
||||
|
||||
"""
|
||||
|
||||
Fancy Field Storage for a 2.5D code.
|
||||
|
||||
u[:,'phi', kyInd] = phi
|
||||
print u[src0,'phi']
|
||||
|
||||
Only one field type is stored for
|
||||
each problem, the rest are computed. The fields obejct acts like an array and is indexed by
|
||||
.. code-block:: python
|
||||
f = problem.fields(m)
|
||||
e = f[srcList,'e']
|
||||
j = f[srcList,'j']
|
||||
|
||||
If accessing all sources for a given field, use the :code:`:`
|
||||
.. code-block:: python
|
||||
f = problem.fields(m)
|
||||
phi = f[:,'phi']
|
||||
e = f[:,'e']
|
||||
b = f[:,'b']
|
||||
The array returned will be size (nE or nF, nSrcs :math:`\\times` nFrequencies)
|
||||
"""
|
||||
|
||||
knownFields = {}
|
||||
dtype = float
|
||||
|
||||
def _phiDeriv(self,kyInd, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_phiDeriv_u', None) is None or getattr(self, '_phiDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting phiDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._phiDeriv_u(kyInd, src, v, adjoint=adjoint), self._phiDeriv_m(kyInd, src, v, adjoint=adjoint)
|
||||
|
||||
return np.array(self._phiDeriv_u(kyInd, src, du_dm_v, adjoint) + self._phiDeriv_m(kyInd, src, v, adjoint), dtype = float)
|
||||
|
||||
def _eDeriv(self,kyInd, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._eDeriv_u(kyInd, src, v, adjoint), self._eDeriv_m(kyInd, src, v, adjoint)
|
||||
return np.array(self._eDeriv_u(kyInd, src, du_dm_v, adjoint) + self._eDeriv_m(kyInd, src, v, adjoint), dtype = float)
|
||||
|
||||
def _jDeriv(self,kyInd, src, du_dm_v, v, adjoint=False):
|
||||
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
|
||||
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
|
||||
|
||||
if adjoint:
|
||||
return self._jDeriv_u(kyInd, src, v, adjoint), self._jDeriv_m(kyInd, src, v, adjoint)
|
||||
return np.array(self._jDeriv_u(kyInd, src, du_dm_v, adjoint) + self._jDeriv_m(kyInd, src, v, adjoint), dtype = float)
|
||||
|
||||
|
||||
# def _eDeriv(self, tInd, src, dun_dm_v, v, adjoint=False):
|
||||
# if adjoint is True:
|
||||
# return self._eDeriv_u(tInd, src, v, adjoint), self._eDeriv_m(tInd, src, v, adjoint)
|
||||
# return self._eDeriv_u(tInd, src, dun_dm_v) + self._eDeriv_m(tInd, src, v)
|
||||
|
||||
# def _bDeriv(self, tInd, src, dun_dm_v, v, adjoint=False):
|
||||
# if adjoint is True:
|
||||
# return self._bDeriv_u(tInd, src, v, adjoint), self._bDeriv_m(tInd, src, v, adjoint)
|
||||
# return self._bDeriv_u(tInd, src, dun_dm_v) + self._bDeriv_m(tInd, src, v)
|
||||
|
||||
|
||||
class Fields_ky_CC(Fields_ky):
|
||||
knownFields = {'phiSolution':'CC'}
|
||||
aliasFields = {
|
||||
'phi': ['phiSolution','CC','_phi'],
|
||||
'j' : ['phiSolution','F','_j'],
|
||||
'e' : ['phiSolution','F','_e'],
|
||||
}
|
||||
# primary - secondary
|
||||
# CC variables
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields_ky.__init__(self, mesh, survey, **kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
|
||||
def _GLoc(self, fieldType):
|
||||
if fieldType == 'phi':
|
||||
return 'CC'
|
||||
elif fieldType == 'e' or fieldType == 'j':
|
||||
return 'F'
|
||||
else:
|
||||
raise Exception('Field type must be phi, e, j')
|
||||
|
||||
def _phi(self, phiSolution, src, kyInd):
|
||||
return phiSolution
|
||||
|
||||
def _phiDeriv_u(self, kyInd, src, v, adjoint = False):
|
||||
return Identity()*v
|
||||
|
||||
def _phiDeriv_m(self, kyInd, src, v, adjoint = False):
|
||||
return Zero()
|
||||
|
||||
def _j(self, phiSolution, srcList):
|
||||
raise NotImplementedError
|
||||
|
||||
def _e(self, phiSolution, srcList):
|
||||
raise NotImplementedError
|
||||
|
||||
class Fields_ky_N(Fields_ky):
|
||||
knownFields = {'phiSolution':'N'}
|
||||
aliasFields = {
|
||||
'phi': ['phiSolution','N','_phi'],
|
||||
'j' : ['phiSolution','E','_j'],
|
||||
'e' : ['phiSolution','E','_e'],
|
||||
}
|
||||
# primary - secondary
|
||||
# CC variables
|
||||
|
||||
def __init__(self, mesh, survey, **kwargs):
|
||||
Fields_ky.__init__(self, mesh, survey, **kwargs)
|
||||
|
||||
def startup(self):
|
||||
self.prob = self.survey.prob
|
||||
|
||||
def _GLoc(self, fieldType):
|
||||
if fieldType == 'phi':
|
||||
return 'N'
|
||||
elif fieldType == 'e' or fieldType == 'j':
|
||||
return 'E'
|
||||
else:
|
||||
raise Exception('Field type must be phi, e, j')
|
||||
|
||||
def _phi(self, phiSolution, src, kyInd):
|
||||
return phiSolution
|
||||
|
||||
def _phiDeriv_u(self, kyInd, src, v, adjoint = False):
|
||||
return Identity()*v
|
||||
|
||||
def _phiDeriv_m(self, kyInd, src, v, adjoint = False):
|
||||
return Zero()
|
||||
|
||||
def _j(self, phiSolution, srcList):
|
||||
raise NotImplementedError
|
||||
|
||||
def _e(self, phiSolution, srcList):
|
||||
raise NotImplementedError
|
||||
@@ -0,0 +1,296 @@
|
||||
from SimPEG import Problem, Utils
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SurveyDC import Survey
|
||||
from FieldsDC import Fields, Fields_CC, Fields_N
|
||||
from SimPEG.Utils import sdiag
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero
|
||||
from BoundaryUtils import getxBCyBC_CC
|
||||
|
||||
class BaseDCProblem(BaseEMProblem):
|
||||
|
||||
surveyPair = Survey
|
||||
fieldsPair = Fields
|
||||
Ainv = None
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
|
||||
if not self.Ainv == None:
|
||||
self.Ainv.clean()
|
||||
|
||||
f = self.fieldsPair(self.mesh, self.survey)
|
||||
A = self.getA()
|
||||
self.Ainv = self.Solver(A, **self.solverOpts)
|
||||
RHS = self.getRHS()
|
||||
u = self.Ainv * RHS
|
||||
Srcs = self.survey.srcList
|
||||
f[Srcs, self._solutionType] = u
|
||||
return f
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
|
||||
A = self.getA()
|
||||
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType] # solution vector
|
||||
dA_dm_v = self.getADeriv(u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(src, v)
|
||||
du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
|
||||
for rx in src.rxList:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv = np.zeros(m.size)
|
||||
AT = self.getA()
|
||||
|
||||
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType]
|
||||
for rx in src.rxList:
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
||||
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
|
||||
ATinvdf_duT = self.Ainv * df_duT
|
||||
|
||||
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
Jtv += (df_dmT + du_dmT).astype(float)
|
||||
|
||||
return Utils.mkvc(Jtv)
|
||||
|
||||
def getSourceTerm(self):
|
||||
"""
|
||||
takes concept of source and turns it into a matrix
|
||||
"""
|
||||
"""
|
||||
Evaluates the sources, and puts them in matrix form
|
||||
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: q (nC or nN, nSrc)
|
||||
"""
|
||||
|
||||
Srcs = self.survey.srcList
|
||||
|
||||
if self._formulation is 'EB':
|
||||
n = self.mesh.nN
|
||||
# return NotImplementedError
|
||||
|
||||
elif self._formulation is 'HJ':
|
||||
n = self.mesh.nC
|
||||
|
||||
q = np.zeros((n, len(Srcs)))
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
q[:,i] = src.eval(self)
|
||||
return q
|
||||
|
||||
class Problem3D_CC(BaseDCProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'HJ' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_CC
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseDCProblem.__init__(self, mesh, **kwargs)
|
||||
self.setBC()
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoI = self.MfRhoI
|
||||
A = D * MfRhoI * G
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * A
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint= False):
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoIDeriv = self.MfRhoIDeriv
|
||||
|
||||
if adjoint:
|
||||
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
|
||||
|
||||
return D * (MfRhoIDeriv( G * u ) * v)
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
def setBC(self):
|
||||
if self.mesh.dim==3:
|
||||
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
gBFzm = self.mesh.gridFz[fzm,:]
|
||||
gBFzp = self.mesh.gridFz[fzp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
beta_zm, beta_zp = temp_zm, temp_zp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
|
||||
|
||||
elif self.mesh.dim==2:
|
||||
|
||||
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
||||
|
||||
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
||||
V = self.Vol
|
||||
self.Div = V * self.mesh.faceDiv
|
||||
P_BC, B = self.mesh.getBCProjWF_simple()
|
||||
M = B*self.mesh.aveCC2F
|
||||
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
||||
|
||||
|
||||
class Problem3D_N(BaseDCProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'EB' # N potentials means B is on faces
|
||||
fieldsPair = Fields_N
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseDCProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = G.T MeSigma G
|
||||
|
||||
"""
|
||||
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
A = Grad.T * MeSigma * Grad
|
||||
|
||||
# Handling Null space of A
|
||||
A[0,0] = A[0,0] + 1.
|
||||
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint=False):
|
||||
"""
|
||||
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
"""
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
if not adjoint:
|
||||
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
|
||||
elif adjoint:
|
||||
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
|
||||
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,349 @@
|
||||
from SimPEG import Problem, Utils
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SurveyDC import Survey, Survey_ky
|
||||
from FieldsDC_2D import Fields_ky, Fields_ky_CC, Fields_ky_N
|
||||
from SimPEG.Utils import sdiag
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero
|
||||
from BoundaryUtils import getxBCyBC_CC
|
||||
|
||||
class BaseDCProblem_2D(BaseEMProblem):
|
||||
|
||||
surveyPair = Survey_ky
|
||||
fieldsPair = Fields_ky
|
||||
nky = 15
|
||||
kys = np.logspace(-4, 1, nky)
|
||||
Ainv = [None for i in range(nky)]
|
||||
nT = nky # Only for using TimeFields
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
|
||||
if not self.Ainv[0] == None:
|
||||
for i in range(self.nky):
|
||||
self.Ainv[i].clean()
|
||||
|
||||
f = self.fieldsPair(self.mesh, self.survey)
|
||||
Srcs = self.survey.srcList
|
||||
for iky in range(self.nky):
|
||||
ky = self.kys[iky]
|
||||
A = self.getA(ky)
|
||||
self.Ainv[iky] = self.Solver(A, **self.solverOpts)
|
||||
RHS = self.getRHS(ky)
|
||||
u = self.Ainv[iky] * RHS
|
||||
f[Srcs, self._solutionType, iky] = u
|
||||
return f
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
Jv0 = self.dataPair(self.survey)
|
||||
|
||||
# Assume y=0.
|
||||
# This needs some thoughts to implement in general when src is dipole
|
||||
dky = np.diff(self.kys)
|
||||
dky = np.r_[dky[0], dky]
|
||||
y = 0.
|
||||
|
||||
#TODO: this loop is pretty slow .. (Parellize)
|
||||
for iky in range(self.nky):
|
||||
ky = self.kys[iky]
|
||||
A = self.getA(ky)
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType, iky] # solution vector
|
||||
dA_dm_v = self.getADeriv(ky, u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(ky, src, v)
|
||||
du_dm_v = self.Ainv[iky] * ( - dA_dm_v + dRHS_dm_v )
|
||||
for rx in src.rxList:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(iky, src, du_dm_v, v, adjoint=False)
|
||||
# Trapezoidal intergration
|
||||
Jv1_temp = 1./np.pi*rx.evalDeriv(ky, src, self.mesh, f, df_dm_v)
|
||||
if iky==0:
|
||||
#First assigment
|
||||
Jv[src, rx] = Jv1_temp*dky[iky]*np.cos(ky*y)
|
||||
else:
|
||||
Jv[src, rx] += Jv1_temp*dky[iky] /2.*np.cos(ky*y)
|
||||
Jv[src, rx] += Jv0[src, rx]*dky[iky]/2.*np.cos(ky*y)
|
||||
Jv0[src, rx] = Jv1_temp.copy()
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv = np.zeros(m.size, dtype=float)
|
||||
|
||||
# Assume y=0.
|
||||
# This needs some thoughts to implement in general when src is dipole
|
||||
dky = np.diff(self.kys)
|
||||
dky = np.r_[dky[0], dky]
|
||||
y = 0.
|
||||
|
||||
for src in self.survey.srcList:
|
||||
for rx in src.rxList:
|
||||
Jtv_temp1 = np.zeros(m.size, dtype=float)
|
||||
Jtv_temp0 = np.zeros(m.size, dtype=float)
|
||||
#TODO: this loop is pretty slow .. (Parellize)
|
||||
for iky in range(self.nky):
|
||||
u_src = f[src, self._solutionType, iky]
|
||||
ky = self.kys[iky]
|
||||
AT = self.getA(ky)
|
||||
PTv = rx.evalDeriv(ky, src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
||||
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(iky, src, None, PTv, adjoint=True)
|
||||
|
||||
ATinvdf_duT = self.Ainv[iky] * df_duT
|
||||
|
||||
dA_dmT = self.getADeriv(ky, u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv(ky, src, ATinvdf_duT, adjoint=True)
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
Jtv_temp1 = 1./np.pi*(df_dmT + du_dmT).astype(float)
|
||||
# Trapezoidal intergration
|
||||
if iky==0:
|
||||
#First assigment
|
||||
Jtv += Jtv_temp1*dky[iky]*np.cos(ky*y)
|
||||
else:
|
||||
Jtv += Jtv_temp1*dky[iky]/2.*np.cos(ky*y)
|
||||
Jtv += Jtv_temp0*dky[iky]/2.*np.cos(ky*y)
|
||||
Jtv_temp0 = Jtv_temp1.copy()
|
||||
return Utils.mkvc(Jtv)
|
||||
|
||||
def getSourceTerm(self, ky):
|
||||
"""
|
||||
takes concept of source and turns it into a matrix
|
||||
"""
|
||||
"""
|
||||
Evaluates the sources, and puts them in matrix form
|
||||
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: q (nC or nN, nSrc)
|
||||
"""
|
||||
|
||||
Srcs = self.survey.srcList
|
||||
|
||||
if self._formulation is 'EB':
|
||||
n = self.mesh.nN
|
||||
# return NotImplementedError
|
||||
|
||||
elif self._formulation is 'HJ':
|
||||
n = self.mesh.nC
|
||||
|
||||
q = np.zeros((n, len(Srcs)))
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
q[:,i] = src.eval(self)
|
||||
return q
|
||||
|
||||
class Problem2D_CC(BaseDCProblem_2D):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'HJ' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_ky_CC
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseDCProblem_2D.__init__(self, mesh, **kwargs)
|
||||
self.setBC()
|
||||
|
||||
def getA(self, ky):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
vol = self.mesh.vol
|
||||
MfRhoI = self.MfRhoI
|
||||
# Get resistivity rho
|
||||
rho = self.curModel.rho
|
||||
A = D * MfRhoI * G + Utils.sdiag(ky**2*vol/rho)
|
||||
return A
|
||||
|
||||
def getADeriv(self, ky, u, v, adjoint= False):
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
vol = self.mesh.vol
|
||||
MfRhoIDeriv = self.MfRhoIDeriv
|
||||
rho = self.curModel.rho
|
||||
if adjoint:
|
||||
return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v
|
||||
return D * ((MfRhoIDeriv( G * u )) * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v
|
||||
|
||||
def getRHS(self, ky):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm(ky)
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, ky, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, ky, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
def setBC(self):
|
||||
if self.mesh.dim==3:
|
||||
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
gBFzm = self.mesh.gridFz[fzm,:]
|
||||
gBFzp = self.mesh.gridFz[fzp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
beta_zm, beta_zp = temp_zm, temp_zp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
|
||||
|
||||
elif self.mesh.dim==2:
|
||||
|
||||
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
||||
|
||||
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
||||
V = self.Vol
|
||||
self.Div = V * self.mesh.faceDiv
|
||||
P_BC, B = self.mesh.getBCProjWF_simple()
|
||||
M = B*self.mesh.aveCC2F
|
||||
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
||||
|
||||
class Problem2D_N(BaseDCProblem_2D):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'EB' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_ky_N
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseDCProblem_2D.__init__(self, mesh, **kwargs)
|
||||
# self.setBC()
|
||||
|
||||
@property
|
||||
def MnSigma(self):
|
||||
"""
|
||||
Node inner product matrix for \\(\\sigma\\). Used in the E-B formulation
|
||||
"""
|
||||
# TODO: only works isotropic sigma
|
||||
sigma = self.curModel.sigma
|
||||
vol = self.mesh.vol
|
||||
MnSigma = Utils.sdiag(self.mesh.aveN2CC.T*(Utils.sdiag(vol)*sigma))
|
||||
|
||||
return MnSigma
|
||||
|
||||
def MnSigmaDeriv(self, u):
|
||||
"""
|
||||
Derivative of MnSigma with respect to the model
|
||||
"""
|
||||
sigma = self.curModel.sigma
|
||||
sigmaderiv = self.curModel.sigmaDeriv
|
||||
vol = self.mesh.vol
|
||||
return Utils.sdiag(u)*self.mesh.aveN2CC.T*Utils.sdiag(vol) * self.curModel.sigmaDeriv
|
||||
|
||||
def getA(self, ky):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
MeSigma = self.MeSigma
|
||||
MnSigma = self.MnSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
# Get conductivity sigma
|
||||
sigma = self.curModel.sigma
|
||||
A = Grad.T * MeSigma * Grad + ky**2*MnSigma
|
||||
|
||||
# Handling Null space of A
|
||||
A[0,0] = A[0,0] + 1.
|
||||
return A
|
||||
|
||||
def getADeriv(self, ky, u, v, adjoint= False):
|
||||
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
sigma = self.curModel.sigma
|
||||
vol = self.mesh.vol
|
||||
|
||||
if adjoint:
|
||||
return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + ky**2*self.MnSigmaDeriv(u).T*v
|
||||
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + ky**2*self.MnSigmaDeriv(u)*v
|
||||
|
||||
def getRHS(self, ky):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm(ky)
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, ky, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, ky, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
@@ -0,0 +1,129 @@
|
||||
import SimPEG
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero, closestPoints
|
||||
|
||||
class BaseRx(SimPEG.Survey.BaseRx):
|
||||
locs = None
|
||||
rxType = None
|
||||
|
||||
knownRxTypes = {
|
||||
'phi':['phi',None],
|
||||
'ex':['e','x'],
|
||||
'ey':['e','y'],
|
||||
'ez':['e','z'],
|
||||
'jx':['j','x'],
|
||||
'jy':['j','y'],
|
||||
'jz':['j','z'],
|
||||
}
|
||||
|
||||
def __init__(self, locs, rxType, **kwargs):
|
||||
SimPEG.Survey.BaseRx.__init__(self, locs, rxType, **kwargs)
|
||||
|
||||
|
||||
@property
|
||||
def projField(self):
|
||||
"""Field Type projection (e.g. e b ...)"""
|
||||
return self.knownRxTypes[self.rxType][0]
|
||||
|
||||
def projGLoc(self, f):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
comp = self.knownRxTypes[self.rxType][1]
|
||||
if comp is not None:
|
||||
return f._GLoc(self.rxType) + comp
|
||||
return f._GLoc(self.rxType)
|
||||
|
||||
def eval(self, src, mesh, f):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
return P*f[src, self.projField]
|
||||
|
||||
def evalDeriv(self, src, mesh, f, v, adjoint=False):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
if not adjoint:
|
||||
return P*v
|
||||
elif adjoint:
|
||||
return P.T*v
|
||||
|
||||
# DC.Rx.Dipole(locs)
|
||||
class Dipole(BaseRx):
|
||||
|
||||
def __init__(self, locsM, locsN, rxType = 'phi', **kwargs):
|
||||
assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size'
|
||||
locs = [locsM, locsN]
|
||||
# We may not need this ...
|
||||
BaseRx.__init__(self, locs, rxType)
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data in the receiver."""
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
# Not sure why ...
|
||||
# return int(self.locs[0].size / 2)
|
||||
|
||||
|
||||
def getP(self, mesh, Gloc):
|
||||
if mesh in self._Ps:
|
||||
return self._Ps[mesh]
|
||||
|
||||
P0 = mesh.getInterpolationMat(self.locs[0], Gloc)
|
||||
P1 = mesh.getInterpolationMat(self.locs[1], Gloc)
|
||||
P = P0 - P1
|
||||
|
||||
if self.storeProjections:
|
||||
self._Ps[mesh] = P
|
||||
|
||||
return P
|
||||
|
||||
|
||||
class Dipole_ky(BaseRx):
|
||||
|
||||
def __init__(self, locsM, locsN, rxType = 'phi', **kwargs):
|
||||
assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size'
|
||||
locs = [locsM, locsN]
|
||||
# We may not need this ...
|
||||
BaseRx.__init__(self, locs, rxType)
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data in the receiver."""
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
# Not sure why ...
|
||||
# return int(self.locs[0].size / 2)
|
||||
|
||||
def getP(self, mesh, Gloc):
|
||||
if mesh in self._Ps:
|
||||
return self._Ps[mesh]
|
||||
|
||||
P0 = mesh.getInterpolationMat(self.locs[0], Gloc)
|
||||
P1 = mesh.getInterpolationMat(self.locs[1], Gloc)
|
||||
P = P0 - P1
|
||||
if self.storeProjections:
|
||||
self._Ps[mesh] = P
|
||||
return P
|
||||
|
||||
def eval(self, kys, src, mesh, f):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
Pf = P*f[src, self.projField,:]
|
||||
return self.IntTrapezoidal(kys, Pf, y=0.)
|
||||
|
||||
def evalDeriv(self, ky, src, mesh, f, v, adjoint=False):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
if not adjoint:
|
||||
return P*v
|
||||
elif adjoint:
|
||||
return P.T*v
|
||||
|
||||
def IntTrapezoidal(self, kys, Pf, y=0.):
|
||||
phi = np.zeros(Pf.shape[0])
|
||||
nky = kys.size
|
||||
dky = np.diff(kys)
|
||||
dky = np.r_[dky[0], dky]
|
||||
phi0 = 1./np.pi*Pf[:,0]
|
||||
for iky in range(nky):
|
||||
phi1 = 1./np.pi*Pf[:,iky]
|
||||
phi += phi1*dky[iky]/2.*np.cos(kys[iky]*y)
|
||||
phi += phi0*dky[iky]/2.*np.cos(kys[iky]*y)
|
||||
phi0 = phi1.copy()
|
||||
return phi
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
import SimPEG
|
||||
# from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG.Utils import Zero, closestPoints, mkvc
|
||||
import numpy as np
|
||||
|
||||
class BaseSrc(SimPEG.Survey.BaseSrc):
|
||||
|
||||
current = 1.0
|
||||
loc = None
|
||||
|
||||
def __init__(self, rxList, **kwargs):
|
||||
SimPEG.Survey.BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
raise NotImplementedError
|
||||
|
||||
def evalDeriv(self, prob):
|
||||
return Zero()
|
||||
|
||||
|
||||
class Dipole(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, locA, locB, **kwargs):
|
||||
assert locA.shape == locB.shape, 'Shape of locA and locB should be the same'
|
||||
self.loc = [locA, locB]
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
if prob._formulation == 'HJ':
|
||||
inds = closestPoints(prob.mesh, self.loc, gridLoc='CC')
|
||||
q = np.zeros(prob.mesh.nC)
|
||||
q[inds] = self.current * np.r_[1., -1.]
|
||||
elif prob._formulation == 'EB':
|
||||
qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense()
|
||||
qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense()
|
||||
q = self.current * mkvc(qa+qb)
|
||||
return q
|
||||
|
||||
class Pole(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, loc, **kwargs):
|
||||
BaseSrc.__init__(self, rxList, loc=loc, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
if prob._formulation == 'HJ':
|
||||
inds = closestPoints(prob.mesh, self.loc)
|
||||
q = np.zeros(prob.mesh.nC)
|
||||
q[inds] = self.current * np.r_[1.]
|
||||
elif prob._formulation == 'EB':
|
||||
q = prob.mesh.getInterpolationMat(self.loc, locType='N').todense()
|
||||
q = self.current * mkvc(q)
|
||||
return q
|
||||
|
||||
|
||||
# class Dipole_ky(BaseSrc):
|
||||
|
||||
# def __init__(self, rxList, locA, locB, **kwargs):
|
||||
# assert locA.shape == locB.shape, 'Shape of locA and locB should be the same'
|
||||
# self.loc = [locA[[0,2]], locB[[0,2]]]
|
||||
# BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
# def eval(self, prob):
|
||||
# if prob._formulation == 'HJ':
|
||||
# inds = closestPoints(prob.mesh, self.loc, gridLoc='CC')
|
||||
# q = np.zeros(prob.mesh.nC)
|
||||
# q[inds] = self.current * np.r_[1., -1.]
|
||||
# elif prob._formulation == 'EB':
|
||||
# qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense()
|
||||
# qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense()
|
||||
# q = self.current * mkvc(qa+qb)
|
||||
# return q
|
||||
|
||||
# class Pole_ky(BaseSrc):
|
||||
|
||||
# def __init__(self, rxList, loc, **kwargs):
|
||||
# BaseSrc.__init__(self, rxList, loc=loc, **kwargs)
|
||||
|
||||
# def eval(self, prob):
|
||||
# if prob._formulation == 'HJ':
|
||||
# inds = closestPoints(prob.mesh, self.loc[[0,2]])
|
||||
# q = np.zeros(prob.mesh.nC)
|
||||
# q[inds] = self.current * np.r_[1.]
|
||||
# elif prob._formulation == 'EB':
|
||||
# q = prob.mesh.getInterpolationMat(self.loc[[0,2]], locType='N').todense()
|
||||
# q = self.current * mkvc(q)
|
||||
# return q
|
||||
@@ -0,0 +1,38 @@
|
||||
import SimPEG
|
||||
from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG import sp, Survey
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
from RxDC import BaseRx
|
||||
from SrcDC import BaseSrc
|
||||
|
||||
class Survey(BaseEMSurvey):
|
||||
rxPair = BaseRx
|
||||
srcPair = BaseSrc
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
self.srcList = srcList
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
|
||||
class Survey_ky(BaseEMSurvey):
|
||||
rxPair = BaseRx
|
||||
srcPair = BaseSrc
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
self.srcList = srcList
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
|
||||
def eval(self, f):
|
||||
"""
|
||||
Project fields to receiver locations
|
||||
:param Fields u: fields object
|
||||
:rtype: numpy.ndarray
|
||||
:return: data
|
||||
"""
|
||||
data = SimPEG.Survey.Data(self)
|
||||
kys = self.prob.kys
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.eval(kys, src, self.mesh, f)
|
||||
return data
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import numpy as np
|
||||
|
||||
def WennerSrcList(nElecs, aSpacing, in2D=False, plotIt=False):
|
||||
|
||||
import SimPEG.EM.Static.DC as DC
|
||||
|
||||
elocs = np.arange(0,aSpacing*nElecs,aSpacing)
|
||||
elocs -= (nElecs*aSpacing - aSpacing)/2
|
||||
space = 1
|
||||
WENNER = np.zeros((0,),dtype=int)
|
||||
for ii in range(nElecs):
|
||||
for jj in range(nElecs):
|
||||
test = np.r_[jj,jj+space,jj+space*2,jj+space*3]
|
||||
if np.any(test >= nElecs):
|
||||
break
|
||||
WENNER = np.r_[WENNER, test]
|
||||
space += 1
|
||||
WENNER = WENNER.reshape((-1,4))
|
||||
|
||||
|
||||
if plotIt:
|
||||
for i, s in enumerate('rbkg'):
|
||||
plt.plot(elocs[WENNER[:,i]],s+'.')
|
||||
plt.show()
|
||||
|
||||
# Create sources and receivers
|
||||
i = 0
|
||||
if in2D:
|
||||
getLoc = lambda ii, abmn: np.r_[elocs[WENNER[ii,abmn]],0]
|
||||
else:
|
||||
getLoc = lambda ii, abmn: np.r_[elocs[WENNER[ii,abmn]],0, 0]
|
||||
srcList = []
|
||||
for i in range(WENNER.shape[0]):
|
||||
rx = DC.Rx.Dipole(getLoc(i,1).reshape([1,-1]),getLoc(i,2).reshape([1,-1]))
|
||||
src = DC.Src.Dipole([rx], getLoc(i,0),getLoc(i,3))
|
||||
srcList += [src]
|
||||
|
||||
return srcList
|
||||
@@ -0,0 +1,8 @@
|
||||
from ProblemDC import Problem3D_CC, Problem3D_N
|
||||
from ProblemDC_2D import Problem2D_CC, Problem2D_N
|
||||
from SurveyDC import Survey, Survey_ky
|
||||
import SrcDC as Src #Pole
|
||||
import RxDC as Rx
|
||||
from FieldsDC import Fields_CC
|
||||
from BoundaryUtils import getxBCyBC_CC
|
||||
import Utils
|
||||
@@ -0,0 +1,372 @@
|
||||
from SimPEG import Problem, Utils, Maps, Mesh
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SimPEG.EM.Static.DC.FieldsDC import Fields, Fields_CC, Fields_N
|
||||
from SimPEG.Utils import sdiag
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero
|
||||
from SimPEG.EM.Static.DC import getxBCyBC_CC
|
||||
from SurveyIP import Survey
|
||||
|
||||
class IPPropMap(Maps.PropMap):
|
||||
"""
|
||||
Property Map for IP Problems. The electrical chargeability,
|
||||
(\\(\\eta\\)) is the default inversion property
|
||||
"""
|
||||
eta = Maps.Property("Electrical Chargeability", defaultInvProp = True)
|
||||
|
||||
class BaseIPProblem(BaseEMProblem):
|
||||
|
||||
surveyPair = Survey
|
||||
fieldsPair = Fields
|
||||
PropMap = IPPropMap
|
||||
Ainv = None
|
||||
sigma = None
|
||||
rho = None
|
||||
f = None
|
||||
Ainv = None
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
if self.f is None:
|
||||
self.f = self.fieldsPair(self.mesh, self.survey)
|
||||
if self.Ainv == None:
|
||||
A = self.getA()
|
||||
self.Ainv = self.Solver(A, **self.solverOpts)
|
||||
RHS = self.getRHS()
|
||||
u = self.Ainv * RHS
|
||||
Srcs = self.survey.srcList
|
||||
self.f[Srcs, self._solutionType] = u
|
||||
return self.f
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
|
||||
A = self.getA()
|
||||
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType] # solution vector
|
||||
dA_dm_v = self.getADeriv(u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(src, v)
|
||||
du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
|
||||
for rx in src.rxList:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
||||
# Conductivity (d u / d log sigma)
|
||||
if self._formulation is 'EB':
|
||||
return -Utils.mkvc(Jv)
|
||||
# Conductivity (d u / d log rho)
|
||||
if self._formulation is 'HJ':
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv = np.zeros(m.size)
|
||||
AT = self.getA()
|
||||
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType]
|
||||
for rx in src.rxList:
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
|
||||
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
ATinvdf_duT = self.Ainv * df_duT
|
||||
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
Jtv += (df_dmT + du_dmT).astype(float)
|
||||
# Conductivity ((d u / d log sigma).T)
|
||||
if self._formulation is 'EB':
|
||||
return -Utils.mkvc(Jtv)
|
||||
# Conductivity ((d u / d log rho).T)
|
||||
if self._formulation is 'HJ':
|
||||
return Utils.mkvc(Jtv)
|
||||
|
||||
def getSourceTerm(self):
|
||||
"""
|
||||
takes concept of source and turns it into a matrix
|
||||
"""
|
||||
"""
|
||||
Evaluates the sources, and puts them in matrix form
|
||||
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: q (nC or nN, nSrc)
|
||||
"""
|
||||
|
||||
Srcs = self.survey.srcList
|
||||
|
||||
if self._formulation is 'EB':
|
||||
n = self.mesh.nN
|
||||
# return NotImplementedError
|
||||
|
||||
elif self._formulation is 'HJ':
|
||||
n = self.mesh.nC
|
||||
|
||||
q = np.zeros((n, len(Srcs)))
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
q[:,i] = src.eval(self)
|
||||
return q
|
||||
|
||||
@property
|
||||
def deleteTheseOnModelUpdate(self):
|
||||
toDelete = []
|
||||
return toDelete
|
||||
|
||||
# assume log rho or log cond
|
||||
@property
|
||||
def MeSigma(self):
|
||||
"""
|
||||
Edge inner product matrix for \\(\\sigma\\). Used in the E-B formulation
|
||||
"""
|
||||
if getattr(self, '_MeSigma', None) is None:
|
||||
self._MeSigma = self.mesh.getEdgeInnerProduct(self.sigma)
|
||||
return self._MeSigma
|
||||
|
||||
@property
|
||||
def MfRhoI(self):
|
||||
"""
|
||||
Inverse of :code:`MfRho`
|
||||
"""
|
||||
if getattr(self, '_MfRhoI', None) is None:
|
||||
self._MfRhoI = self.mesh.getFaceInnerProduct(self.rho, invMat=True)
|
||||
return self._MfRhoI
|
||||
|
||||
def MfRhoIDeriv(self,u):
|
||||
"""
|
||||
Derivative of :code:`MfRhoI` with respect to the model.
|
||||
"""
|
||||
|
||||
dMfRhoI_dI = -self.MfRhoI**2
|
||||
dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u)
|
||||
drho_dlogrho = Utils.sdiag(self.rho)*self.curModel.etaDeriv
|
||||
return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho))
|
||||
|
||||
# TODO: This should take a vector
|
||||
def MeSigmaDeriv(self, u):
|
||||
"""
|
||||
Derivative of MeSigma with respect to the model
|
||||
"""
|
||||
dsigma_dlogsigma = Utils.sdiag(self.sigma)*self.curModel.etaDeriv
|
||||
return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma
|
||||
|
||||
class Problem3D_CC(BaseIPProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'HJ' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_CC
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseIPProblem.__init__(self, mesh, **kwargs)
|
||||
self.setBC()
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoI = self.MfRhoI
|
||||
A = D * MfRhoI * G
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * A
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint= False):
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoIDeriv = self.MfRhoIDeriv
|
||||
|
||||
if adjoint:
|
||||
# if self._makeASymmetric is True:
|
||||
# v = V * v
|
||||
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) )
|
||||
return D * (MfRhoIDeriv( G * u ) * v)
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return self.Vol.T * RHS
|
||||
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
def setBC(self):
|
||||
if self.mesh.dim==3:
|
||||
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
gBFzm = self.mesh.gridFz[fzm,:]
|
||||
gBFzp = self.mesh.gridFz[fzp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
beta_zm, beta_zp = temp_zm, temp_zp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
|
||||
|
||||
elif self.mesh.dim==2:
|
||||
|
||||
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
||||
|
||||
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
||||
V = self.Vol
|
||||
self.Div = V * self.mesh.faceDiv
|
||||
P_BC, B = self.mesh.getBCProjWF_simple()
|
||||
M = B*self.mesh.aveCC2F
|
||||
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
||||
|
||||
|
||||
class Problem3D_N(BaseIPProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'EB' # N potentials means B is on faces
|
||||
fieldsPair = Fields_N
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseIPProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = G.T MeSigma G
|
||||
|
||||
"""
|
||||
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
A = Grad.T * MeSigma * Grad
|
||||
|
||||
# Handling Null space of A
|
||||
A[0,0] = A[0,0] + 1.
|
||||
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint=False):
|
||||
"""
|
||||
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
"""
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
if not adjoint:
|
||||
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
|
||||
elif adjoint:
|
||||
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
|
||||
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
||||
cs = 12.5
|
||||
hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hz = [(cs,7, -1.3),(cs,20)]
|
||||
mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN")
|
||||
sigma = np.ones(mesh.nC)
|
||||
prob = BaseIPProblem(mesh, sigma=sigma)
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import SimPEG
|
||||
from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG import sp, Survey
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
from SimPEG.EM.Static.DC.SrcDC import BaseSrc
|
||||
from SimPEG.EM.Static.DC.RxDC import BaseRx
|
||||
|
||||
class Survey(BaseEMSurvey):
|
||||
rxPair = BaseRx
|
||||
srcPair = BaseSrc
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
self.srcList = srcList
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
|
||||
def dpred(self, m, f=None):
|
||||
"""
|
||||
Predicted data.
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = Pf(m)
|
||||
"""
|
||||
return self.prob.Jvec(m, m, f=f)
|
||||
@@ -0,0 +1,2 @@
|
||||
from ProblemIP import Problem3D_CC, Problem3D_N
|
||||
from SurveyIP import Survey
|
||||
@@ -0,0 +1,445 @@
|
||||
from SimPEG import Problem, Utils, Maps, Mesh
|
||||
from SimPEG.EM.Base import BaseEMProblem
|
||||
from SimPEG.EM.Static.DC.FieldsDC import Fields, Fields_CC, Fields_N
|
||||
from SimPEG.Utils import sdiag
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero
|
||||
from SimPEG.EM.Static.DC import getxBCyBC_CC
|
||||
from SurveySIP import Survey, Data
|
||||
|
||||
class ColeColePropMap(Maps.PropMap):
|
||||
"""
|
||||
Property Map for EM Problems. The electrical conductivity (\\(\\sigma\\)) is the default inversion property, and the default value of the magnetic permeability is that of free space (\\(\\mu = 4\\pi\\times 10^{-7} \\) H/m)
|
||||
"""
|
||||
|
||||
eta = Maps.Property("Electrical Conductivity", defaultInvProp=True)
|
||||
tau = Maps.Property("Electrical Conductivity", defaultVal=0.1, propertyLink=('taui', Maps.ReciprocalMap))
|
||||
taui = Maps.Property("Electrical Conductivity", defaultVal=1., propertyLink=('tau', Maps.ReciprocalMap))
|
||||
c = Maps.Property("Electrical Conductivity", defaultVal=1.)
|
||||
|
||||
|
||||
class BaseSIPProblem(BaseEMProblem):
|
||||
|
||||
surveyPair = Survey
|
||||
fieldsPair = Fields
|
||||
dataPair = Data
|
||||
PropMap = ColeColePropMap
|
||||
Ainv = None
|
||||
sigma = None
|
||||
rho = None
|
||||
f = None
|
||||
Ainv = None
|
||||
|
||||
def DebyeTime(self, t):
|
||||
peta = self.curModel.eta*np.exp(-self.curModel.taui*t)
|
||||
return peta
|
||||
|
||||
def EtaDeriv(self, t, v, adjoint=False):
|
||||
v = np.array(v, dtype=float)
|
||||
if adjoint:
|
||||
return self.curModel.etaDeriv.T * (np.exp(-self.curModel.taui*t)*v)
|
||||
else:
|
||||
return np.exp(-self.curModel.taui*t) * (self.curModel.etaDeriv*v)
|
||||
|
||||
|
||||
def TauiDeriv(self, t, v, adjoint=False):
|
||||
v = np.array(v, dtype=float)
|
||||
if adjoint:
|
||||
return -self.curModel.tauiDeriv.T * (self.curModel.eta*t*np.exp(-self.curModel.taui*t)*v)
|
||||
else:
|
||||
return -self.curModel.eta*t*np.exp(-self.curModel.taui*t) * (self.curModel.tauiDeriv*v)
|
||||
|
||||
def fields(self, m):
|
||||
self.curModel = m
|
||||
if self.f is None:
|
||||
self.f = self.fieldsPair(self.mesh, self.survey)
|
||||
if self.Ainv == None:
|
||||
A = self.getA()
|
||||
self.Ainv = self.Solver(A, **self.solverOpts)
|
||||
RHS = self.getRHS()
|
||||
u = self.Ainv * RHS
|
||||
Srcs = self.survey.srcList
|
||||
self.f[Srcs, self._solutionType] = u
|
||||
return self.f
|
||||
|
||||
def forward(self, m, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
# A = self.getA()
|
||||
JvAll = []
|
||||
for tind in range(len(self.survey.times)):
|
||||
#Pseudo-chareability
|
||||
t = self.survey.times[tind]
|
||||
v = self.DebyeTime(t)
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType] # solution vector
|
||||
dA_dm_v = self.getADeriv(u_src, v)
|
||||
dRHS_dm_v = self.getRHSDeriv(src, v)
|
||||
du_dm_v = self.Ainv * ( - dA_dm_v + dRHS_dm_v )
|
||||
for rx in src.rxList:
|
||||
timeindex = rx.getTimeP(self.survey.times)
|
||||
if timeindex[tind]:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
|
||||
Jv[src, rx, t] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
|
||||
|
||||
# Conductivity (d u / d log sigma)
|
||||
if self._formulation is 'EB':
|
||||
return -Utils.mkvc(Jv)
|
||||
# Resistivity (d u / d log rho)
|
||||
if self._formulation is 'HJ':
|
||||
return Utils.mkvc(Jv)
|
||||
|
||||
def Jvec(self, m, v, f=None):
|
||||
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
Jv = self.dataPair(self.survey) #same size as the data
|
||||
# A = self.getA()
|
||||
JvAll = []
|
||||
#Assume only eta and tau (eta first then tau)
|
||||
# v = [2*Mx1]
|
||||
v = v.reshape((int(v.size/2), 2), order='F')
|
||||
|
||||
for tind in range(len(self.survey.times)):
|
||||
t = self.survey.times[tind]
|
||||
v0 = self.EtaDeriv(t, v[:,0])
|
||||
v1 = self.TauiDeriv(t, v[:,1])
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType] # solution vector
|
||||
dA_dm_v0 = self.getADeriv(u_src, v0)
|
||||
dRHS_dm_v0 = self.getRHSDeriv(src, v0)
|
||||
du_dm_v0 = self.Ainv * ( - dA_dm_v0 + dRHS_dm_v0 )
|
||||
dA_dm_v1 = self.getADeriv(u_src, v1)
|
||||
dRHS_dm_v1 = self.getRHSDeriv(src, v1)
|
||||
du_dm_v1 = self.Ainv * ( - dA_dm_v1 + dRHS_dm_v1 )
|
||||
for rx in src.rxList:
|
||||
timeindex = rx.getTimeP(self.survey.times)
|
||||
if timeindex[tind]:
|
||||
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_dm_v0 = df_dmFun(src, du_dm_v0, v0, adjoint=False)
|
||||
df_dm_v1 = df_dmFun(src, du_dm_v1, v1, adjoint=False)
|
||||
Jv[src, rx, t] = rx.evalDeriv(src, self.mesh, f, df_dm_v0)
|
||||
Jv[src, rx, t] += rx.evalDeriv(src, self.mesh, f, df_dm_v1)
|
||||
# Conductivity (d u / d log sigma)
|
||||
if self._formulation is 'EB':
|
||||
return -Jv.tovec()
|
||||
# Resistivity (d u / d log rho)
|
||||
if self._formulation is 'HJ':
|
||||
return Jv.tovec()
|
||||
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
# Ensure v is a data object.
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
Jtv= np.zeros(m.size)
|
||||
for tind in range(len(self.survey.times)):
|
||||
t = self.survey.times[tind]
|
||||
for src in self.survey.srcList:
|
||||
u_src = f[src, self._solutionType]
|
||||
for rx in src.rxList:
|
||||
timeindex = rx.getTimeP(self.survey.times)
|
||||
if timeindex[tind]:
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx, t], adjoint=True) # wrt f, need possibility wrt m
|
||||
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
|
||||
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
|
||||
ATinvdf_duT = self.Ainv * df_duT
|
||||
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
|
||||
du_dmT = -dA_dmT + dRHS_dmT
|
||||
Jtv += np.r_[self.EtaDeriv(self.survey.times[tind], du_dmT, adjoint=True), self.TauiDeriv(self.survey.times[tind], du_dmT, adjoint=True)]
|
||||
|
||||
# Conductivity ((d u / d log sigma).T)
|
||||
if self._formulation is 'EB':
|
||||
return -Jtv
|
||||
# Conductivity ((d u / d log rho).T)
|
||||
if self._formulation is 'HJ':
|
||||
return Jtv
|
||||
|
||||
def getSourceTerm(self):
|
||||
"""
|
||||
takes concept of source and turns it into a matrix
|
||||
"""
|
||||
"""
|
||||
Evaluates the sources, and puts them in matrix form
|
||||
|
||||
:rtype: (numpy.ndarray, numpy.ndarray)
|
||||
:return: q (nC or nN, nSrc)
|
||||
"""
|
||||
|
||||
Srcs = self.survey.srcList
|
||||
|
||||
if self._formulation is 'EB':
|
||||
n = self.mesh.nN
|
||||
# return NotImplementedError
|
||||
|
||||
elif self._formulation is 'HJ':
|
||||
n = self.mesh.nC
|
||||
|
||||
q = np.zeros((n, len(Srcs)))
|
||||
|
||||
for i, src in enumerate(Srcs):
|
||||
q[:,i] = src.eval(self)
|
||||
return q
|
||||
|
||||
@property
|
||||
def deleteTheseOnModelUpdate(self):
|
||||
toDelete = []
|
||||
return toDelete
|
||||
|
||||
# assume log rho or log cond
|
||||
@property
|
||||
def MeSigma(self):
|
||||
"""
|
||||
Edge inner product matrix for \\(\\sigma\\). Used in the E-B formulation
|
||||
"""
|
||||
if getattr(self, '_MeSigma', None) is None:
|
||||
self._MeSigma = self.mesh.getEdgeInnerProduct(self.sigma)
|
||||
return self._MeSigma
|
||||
|
||||
@property
|
||||
def MfRhoI(self):
|
||||
"""
|
||||
Inverse of :code:`MfRho`
|
||||
"""
|
||||
if getattr(self, '_MfRhoI', None) is None:
|
||||
self._MfRhoI = self.mesh.getFaceInnerProduct(self.rho, invMat=True)
|
||||
return self._MfRhoI
|
||||
|
||||
def MfRhoIDeriv(self,u):
|
||||
"""
|
||||
Derivative of :code:`MfRhoI` with respect to the model.
|
||||
"""
|
||||
|
||||
dMfRhoI_dI = -self.MfRhoI**2
|
||||
dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u)
|
||||
drho_dlogrho = Utils.sdiag(self.rho)
|
||||
return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho))
|
||||
|
||||
# TODO: This should take a vector
|
||||
def MeSigmaDeriv(self, u):
|
||||
"""
|
||||
Derivative of MeSigma with respect to the model
|
||||
"""
|
||||
dsigma_dlogsigma = Utils.sdiag(self.sigma)
|
||||
return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma
|
||||
|
||||
class Problem3D_CC(BaseSIPProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'HJ' # CC potentials means J is on faces
|
||||
fieldsPair = Fields_CC
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseSIPProblem.__init__(self, mesh, **kwargs)
|
||||
self.setBC()
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = D MfRhoI G
|
||||
|
||||
"""
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
# TODO: this won't work for full anisotropy
|
||||
MfRhoI = self.MfRhoI
|
||||
A = D * MfRhoI * G
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * A
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint= False):
|
||||
|
||||
D = self.Div
|
||||
G = self.Grad
|
||||
MfRhoIDeriv = self.MfRhoIDeriv
|
||||
|
||||
if adjoint:
|
||||
# if self._makeASymmetric is True:
|
||||
# v = V * v
|
||||
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) )
|
||||
return D * (MfRhoIDeriv( G * u ) * v)
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
|
||||
# I think we should deprecate this for DC problem.
|
||||
# if self._makeASymmetric is True:
|
||||
# return self.Vol.T * RHS
|
||||
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
def setBC(self):
|
||||
if self.mesh.dim==3:
|
||||
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
gBFzm = self.mesh.gridFz[fzm,:]
|
||||
gBFzp = self.mesh.gridFz[fzp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
beta_zm, beta_zp = temp_zm, temp_zp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
|
||||
|
||||
elif self.mesh.dim==2:
|
||||
|
||||
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
|
||||
gBFxm = self.mesh.gridFx[fxm,:]
|
||||
gBFxp = self.mesh.gridFx[fxp,:]
|
||||
gBFym = self.mesh.gridFy[fym,:]
|
||||
gBFyp = self.mesh.gridFy[fyp,:]
|
||||
|
||||
# Setup Mixed B.C (alpha, beta, gamma)
|
||||
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
|
||||
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
|
||||
|
||||
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
|
||||
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
beta_xm, beta_xp = temp_xm, temp_xp
|
||||
beta_ym, beta_yp = temp_ym, temp_yp
|
||||
|
||||
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
|
||||
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
|
||||
|
||||
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
|
||||
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
|
||||
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
|
||||
|
||||
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
|
||||
V = self.Vol
|
||||
self.Div = V * self.mesh.faceDiv
|
||||
P_BC, B = self.mesh.getBCProjWF_simple()
|
||||
M = B*self.mesh.aveCC2F
|
||||
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
|
||||
|
||||
|
||||
class Problem3D_N(BaseSIPProblem):
|
||||
|
||||
_solutionType = 'phiSolution'
|
||||
_formulation = 'EB' # N potentials means B is on faces
|
||||
fieldsPair = Fields_N
|
||||
|
||||
def __init__(self, mesh, **kwargs):
|
||||
BaseSIPProblem.__init__(self, mesh, **kwargs)
|
||||
|
||||
def getA(self):
|
||||
"""
|
||||
|
||||
Make the A matrix for the cell centered DC resistivity problem
|
||||
|
||||
A = G.T MeSigma G
|
||||
|
||||
"""
|
||||
|
||||
# TODO: this won't work for full anisotropy
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
A = Grad.T * MeSigma * Grad
|
||||
|
||||
# Handling Null space of A
|
||||
A[0,0] = A[0,0] + 1.
|
||||
|
||||
return A
|
||||
|
||||
def getADeriv(self, u, v, adjoint=False):
|
||||
"""
|
||||
|
||||
Product of the derivative of our system matrix with respect to the model and a vector
|
||||
|
||||
"""
|
||||
MeSigma = self.MeSigma
|
||||
Grad = self.mesh.nodalGrad
|
||||
if not adjoint:
|
||||
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
|
||||
elif adjoint:
|
||||
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
|
||||
|
||||
|
||||
def getRHS(self):
|
||||
"""
|
||||
RHS for the DC problem
|
||||
|
||||
q
|
||||
"""
|
||||
|
||||
RHS = self.getSourceTerm()
|
||||
return RHS
|
||||
|
||||
def getRHSDeriv(self, src, v, adjoint=False):
|
||||
"""
|
||||
Derivative of the right hand side with respect to the model
|
||||
"""
|
||||
# TODO: add qDeriv for RHS depending on m
|
||||
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
|
||||
# return qDeriv
|
||||
return Zero()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
|
||||
cs = 12.5
|
||||
hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
|
||||
hz = [(cs,7, -1.3),(cs,20)]
|
||||
mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN")
|
||||
sigma = np.ones(mesh.nC)
|
||||
prob = BaseSIPProblem(mesh, sigma=sigma)
|
||||
|
||||
|
||||
@@ -0,0 +1,204 @@
|
||||
from SimPEG import Utils, Maps, Mesh, sp, np
|
||||
from SimPEG.Regularization import BaseRegularization, Simple
|
||||
|
||||
class MultiRegularization(Simple):
|
||||
"""
|
||||
**MultiRegularization Class**
|
||||
|
||||
This is used to regularize the model space
|
||||
having multiple models [m1, m2, m3, ...] ::
|
||||
|
||||
reg = Regularization(mesh)
|
||||
|
||||
"""
|
||||
nModels = None # Number of models
|
||||
ratios = None # Ratio for different models
|
||||
crossgrad = False # Use cross gradient or not
|
||||
betacross = 1.
|
||||
wx = []
|
||||
wy = []
|
||||
wz = []
|
||||
|
||||
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
|
||||
BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
|
||||
if self.nModels == None:
|
||||
raise Exception("Put nModels as a initial input!")
|
||||
if self.ratios == None:
|
||||
self.ratios = [1. for imodel in range(self.nModels)]
|
||||
|
||||
@property
|
||||
def Wsmall(self):
|
||||
"""Regularization matrix Wsmall"""
|
||||
if getattr(self,'_Wsmall', None) is None:
|
||||
vecs = []
|
||||
for imodel in range(self.nModels):
|
||||
vecs.append((self.regmesh.vol*self.alpha_s*self.wght*self.ratios[imodel])**0.5)
|
||||
self._Wsmall = Utils.sdiag(np.hstack(vecs))
|
||||
return self._Wsmall
|
||||
|
||||
@property
|
||||
def Wx(self):
|
||||
"""Regularization matrix Wx"""
|
||||
if getattr(self, '_Wx', None) is None:
|
||||
mats = []
|
||||
for imodel in range(self.nModels):
|
||||
self.wx.append(Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*self.ratios[imodel]*(self.regmesh.aveCC2Fx*self.wght))**0.5))
|
||||
mats.append(self.wx[imodel]*self.regmesh.cellDiffxStencil)
|
||||
self._Wx = sp.block_diag(mats)
|
||||
return self._Wx
|
||||
|
||||
@property
|
||||
def Wy(self):
|
||||
"""Regularization matrix Wy"""
|
||||
if getattr(self, '_Wy', None) is None:
|
||||
mats = []
|
||||
for imodel in range(self.nModels):
|
||||
self.wy.append(Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol*self.alpha_y*self.ratios[imodel]*(self.regmesh.aveCC2Fy*self.wght))**0.5))
|
||||
mats.append(self.wy[imodel]*self.regmesh.cellDiffyStencil)
|
||||
self._Wy = sp.block_diag(mats)
|
||||
return self._Wy
|
||||
|
||||
@property
|
||||
def Wz(self):
|
||||
"""Regularization matrix Wz"""
|
||||
if getattr(self, '_Wz', None) is None:
|
||||
mats = []
|
||||
for imodel in range(self.nModels):
|
||||
self.wz.append(Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*self.ratios[imodel]*(self.regmesh.aveCC2Fz*self.wght))**0.5))
|
||||
mats.append(self.wz[imodel]*self.regmesh.cellDiffzStencil)
|
||||
self._Wz = sp.block_diag(mats)
|
||||
return self._Wz
|
||||
|
||||
@property
|
||||
def Wsmooth(self):
|
||||
"""Full smoothness regularization matrix W"""
|
||||
if getattr(self, '_Wsmooth', None) is None:
|
||||
wlist = (self.Wx,)
|
||||
if self.regmesh.dim > 1:
|
||||
wlist += (self.Wy,)
|
||||
if self.regmesh.dim > 2:
|
||||
wlist += (self.Wz,)
|
||||
self._Wsmooth = sp.vstack(wlist)
|
||||
return self._Wsmooth
|
||||
|
||||
@property
|
||||
def W(self):
|
||||
"""Full regularization matrix W"""
|
||||
if getattr(self, '_W', None) is None:
|
||||
wlist = (self.Wsmall, self.Wsmooth)
|
||||
self._W = sp.vstack(wlist)
|
||||
return self._W
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def eval(self, m):
|
||||
return self._evalSmall(m) + self._evalSmooth(m)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmall(self, m):
|
||||
r = self.Wsmall * ( self.mapping * (m - self.mref) )
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalSmooth(self, m):
|
||||
if self.mrefInSmooth == True:
|
||||
r = self.Wsmooth * ( self.mapping * (m - self.mref) )
|
||||
elif self.mrefInSmooth == False:
|
||||
r = self.Wsmooth * ( self.mapping * m)
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
def cross(a,b):
|
||||
ax, ay, az = a[0], a[1], a[2]
|
||||
bx, by, bz = b[0], b[1], b[2]
|
||||
cx = ay*bz - az*by
|
||||
cy = az*bx - ax*bz
|
||||
cz = ax*by - ay*bx
|
||||
return [cx, cy, cz]
|
||||
|
||||
# TODO: Implement Cross Gradients..
|
||||
@Utils.timeIt
|
||||
def _evalCross(self, m):
|
||||
if self.crossgrad == False:
|
||||
return 0.
|
||||
elif self.crossgrad == True:
|
||||
M = (self.mapping * m).reshape((self.regmesh.nC, self.nModels), order="F")
|
||||
|
||||
ax = self.regmesh.aveFx2CC*self.regmesh.wx[0]*M[:,0]
|
||||
ay = self.regmesh.aveFy2CC*self.regmesh.wy[0]*M[:,0]
|
||||
az = self.regmesh.aveFz2CC*self.regmesh.wz[0]*M[:,0]
|
||||
bx = self.regmesh.aveFx2CC*self.regmesh.wx[1]*M[:,1]
|
||||
by = self.regmesh.aveFy2CC*self.regmesh.wy[1]*M[:,1]
|
||||
bz = self.regmesh.aveFz2CC*self.regmesh.wz[1]*M[:,1]
|
||||
#ab
|
||||
out_ab = cross([ax, ay, az], [bx, by, bz])
|
||||
r = np.r_[out_ab[0], out_ab[1], out_ab[2]]*np.sqrt(self.betacross)
|
||||
|
||||
if self.nModels == 3:
|
||||
cx = self.regmesh.aveFx2CC*self.regmesh.wx[1]*M[:,1]
|
||||
cy = self.regmesh.aveFy2CC*self.regmesh.wy[1]*M[:,1]
|
||||
cz = self.regmesh.aveFz2CC*self.regmesh.wz[1]*M[:,1]
|
||||
#ac
|
||||
out_ac = cross([ax, ay, az], [cx, cy, cz])
|
||||
#bc
|
||||
out_bc = cross([bx, by, bz], [cx, cy, cz])
|
||||
r = np.r_[r, np.hstack(out_ac)*np.sqrt(self.betacross), np.hstack(out_bc)*np.sqrt(self.betacross)]
|
||||
|
||||
return 0.5 * r.dot(r)
|
||||
|
||||
@Utils.timeIt
|
||||
def evalDeriv(self, m):
|
||||
"""
|
||||
The regularization is:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})}
|
||||
|
||||
So the derivative is straight forward:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \mathbf{W^\\top W (m-m_\\text{ref})}
|
||||
|
||||
"""
|
||||
deriv = self._evalSmallDeriv(m) + self._evalSmoothDeriv(m)
|
||||
if self.crossgrad==True:
|
||||
deriv += self._evalCrossDeriv(m)
|
||||
return deriv
|
||||
|
||||
@Utils.timeIt
|
||||
def _evalCrossDeriv(self,m):
|
||||
r = self.Wsmall * ( self.mapping * (m - self.mref) )
|
||||
return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) )
|
||||
|
||||
@Utils.timeIt
|
||||
def eval2Deriv(self, m, v=None):
|
||||
"""
|
||||
Second derivative
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array v: vector to multiply
|
||||
:rtype: scipy.sparse.csr_matrix or numpy.ndarray
|
||||
:return: WtW or WtW*v
|
||||
|
||||
The regularization is:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})}
|
||||
|
||||
So the second derivative is straight forward:
|
||||
|
||||
.. math::
|
||||
|
||||
R(m) = \mathbf{W^\\top W}
|
||||
|
||||
"""
|
||||
mD = self.mapping.deriv(m - self.mref)
|
||||
if v is None:
|
||||
return mD.T * self.W.T * self.W * mD
|
||||
|
||||
return mD.T * ( self.W.T * ( self.W * ( mD * v) ) )
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import SimPEG
|
||||
import numpy as np
|
||||
from SimPEG.Utils import Zero, closestPoints
|
||||
|
||||
class BaseRx(SimPEG.Survey.BaseTimeRx):
|
||||
locs = None
|
||||
rxType = None
|
||||
|
||||
knownRxTypes = {
|
||||
'phi':['phi',None],
|
||||
'ex':['e','x'],
|
||||
'ey':['e','y'],
|
||||
'ez':['e','z'],
|
||||
'jx':['j','x'],
|
||||
'jy':['j','y'],
|
||||
'jz':['j','z'],
|
||||
}
|
||||
|
||||
def __init__(self, locs, times, rxType, **kwargs):
|
||||
SimPEG.Survey.BaseTimeRx.__init__(self, locs, times, rxType, **kwargs)
|
||||
|
||||
@property
|
||||
def projField(self):
|
||||
"""Field Type projection (e.g. e b ...)"""
|
||||
return self.knownRxTypes[self.rxType][0]
|
||||
|
||||
def projGLoc(self, f):
|
||||
"""Grid Location projection (e.g. Ex Fy ...)"""
|
||||
comp = self.knownRxTypes[self.rxType][1]
|
||||
if comp is not None:
|
||||
return f._GLoc(self.rxType) + comp
|
||||
return f._GLoc(self.rxType)
|
||||
|
||||
def getTimeP(self, timesall):
|
||||
"""
|
||||
Returns the time projection matrix.
|
||||
|
||||
.. note::
|
||||
|
||||
This is not stored in memory, but is created on demand.
|
||||
"""
|
||||
time_inds = np.in1d(timesall, self.times)
|
||||
return time_inds
|
||||
|
||||
def evalDeriv(self, src, mesh, f, v, adjoint=False):
|
||||
P = self.getP(mesh, self.projGLoc(f))
|
||||
if not adjoint:
|
||||
return P*v
|
||||
elif adjoint:
|
||||
return P.T*v
|
||||
|
||||
|
||||
# DC.Rx.Dipole(locs)
|
||||
class Dipole(BaseRx):
|
||||
|
||||
def __init__(self, locsM, locsN, times, rxType = 'phi', **kwargs):
|
||||
assert locsM.shape == locsN.shape, 'locsM and locsN need to be the same size'
|
||||
locs = [locsM, locsN]
|
||||
# We may not need this ...
|
||||
BaseRx.__init__(self, locs, times, rxType)
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data in the receiver."""
|
||||
# return self.locs[0].shape[0] * len(self.times)
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
@property
|
||||
def nRx(self):
|
||||
"""Number of data in the receiver."""
|
||||
return self.locs[0].shape[0]
|
||||
|
||||
# Not sure why ...
|
||||
# return int(self.locs[0].size / 2)
|
||||
|
||||
|
||||
def getP(self, mesh, Gloc):
|
||||
if mesh in self._Ps:
|
||||
return self._Ps[mesh]
|
||||
|
||||
P0 = mesh.getInterpolationMat(self.locs[0], Gloc)
|
||||
P1 = mesh.getInterpolationMat(self.locs[1], Gloc)
|
||||
P = P0 - P1
|
||||
|
||||
if self.storeProjections:
|
||||
self._Ps[mesh] = P
|
||||
|
||||
return P
|
||||
@@ -0,0 +1,64 @@
|
||||
import SimPEG
|
||||
# from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG.Utils import Zero, closestPoints, mkvc
|
||||
import numpy as np
|
||||
|
||||
class BaseSrc(SimPEG.Survey.BaseSrc):
|
||||
|
||||
current = 1.0
|
||||
loc = None
|
||||
|
||||
def __init__(self, rxList, **kwargs):
|
||||
SimPEG.Survey.BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
raise NotImplementedError
|
||||
|
||||
def evalDeriv(self, prob):
|
||||
return Zero()
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
"""Number of data"""
|
||||
return self.vnD.sum()
|
||||
|
||||
@property
|
||||
def vnD(self):
|
||||
"""Vector number of data"""
|
||||
return np.array([rx.nD*len(rx.times) for rx in self.rxList])
|
||||
|
||||
|
||||
|
||||
class Dipole(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, locA, locB, **kwargs):
|
||||
assert locA.shape == locB.shape, 'Shape of locA and locB should be the same'
|
||||
self.loc = [locA, locB]
|
||||
BaseSrc.__init__(self, rxList, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
if prob._formulation == 'HJ':
|
||||
inds = closestPoints(prob.mesh, self.loc, gridLoc='CC')
|
||||
q = np.zeros(prob.mesh.nC)
|
||||
q[inds] = self.current * np.r_[1., -1.]
|
||||
elif prob._formulation == 'EB':
|
||||
qa = prob.mesh.getInterpolationMat(self.loc[0], locType='N').todense()
|
||||
qb = -prob.mesh.getInterpolationMat(self.loc[1], locType='N').todense()
|
||||
q = self.current * mkvc(qa+qb)
|
||||
return q
|
||||
|
||||
class Pole(BaseSrc):
|
||||
|
||||
def __init__(self, rxList, loc, **kwargs):
|
||||
BaseSrc.__init__(self, rxList, loc=loc, **kwargs)
|
||||
|
||||
def eval(self, prob):
|
||||
if prob._formulation == 'HJ':
|
||||
inds = closestPoints(prob.mesh, self.loc)
|
||||
q = np.zeros(prob.mesh.nC)
|
||||
q[inds] = self.current * np.r_[1.]
|
||||
elif prob._formulation == 'EB':
|
||||
q = prob.mesh.getInterpolationMat(self.loc, locType='N').todense()
|
||||
q = self.current * mkvc(q)
|
||||
return q
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import SimPEG
|
||||
from SimPEG.EM.Base import BaseEMSurvey
|
||||
from SimPEG import np, sp, Survey, Utils
|
||||
from SimPEG.Utils import Zero, Identity
|
||||
from SimPEG.EM.Static.SIP.SrcSIP import BaseSrc
|
||||
from SimPEG.EM.Static.SIP.RxSIP import BaseRx
|
||||
import uuid
|
||||
|
||||
|
||||
class Survey(BaseEMSurvey):
|
||||
rxPair = BaseRx
|
||||
srcPair = BaseSrc
|
||||
times = None
|
||||
|
||||
def __init__(self, srcList, **kwargs):
|
||||
self.srcList = srcList
|
||||
BaseEMSurvey.__init__(self, srcList, **kwargs)
|
||||
self.getUniqueTimes()
|
||||
|
||||
def getUniqueTimes(self):
|
||||
time_rx = []
|
||||
for src in self.srcList:
|
||||
for rx in src.rxList:
|
||||
time_rx.append(rx.times)
|
||||
self.times = np.unique(np.hstack(time_rx))
|
||||
|
||||
def dpred(self, m, f=None):
|
||||
"""
|
||||
Predicted data.
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = Pf(m)
|
||||
"""
|
||||
return self.prob.forward(m, f=f)
|
||||
|
||||
|
||||
class Data(SimPEG.Survey.Data):
|
||||
"""Fancy data storage by Src and Rx"""
|
||||
|
||||
def __init__(self, survey, v=None):
|
||||
self.uid = str(uuid.uuid4())
|
||||
self.survey = survey
|
||||
self._dataDict = {}
|
||||
for src in self.survey.srcList:
|
||||
self._dataDict[src] = {}
|
||||
for rx in src.rxList:
|
||||
self._dataDict[src][rx] = {}
|
||||
|
||||
if v is not None:
|
||||
self.fromvec(v)
|
||||
|
||||
def _ensureCorrectKey(self, key):
|
||||
if type(key) is tuple:
|
||||
if len(key) is not 3:
|
||||
raise KeyError('Key must be [Src, Rx, tInd]')
|
||||
if key[0] not in self.survey.srcList:
|
||||
raise KeyError('Src Key must be a source in the survey.')
|
||||
if key[1] not in key[0].rxList:
|
||||
raise KeyError('Rx Key must be a receiver for the source.')
|
||||
return key
|
||||
elif isinstance(key, self.survey.srcPair):
|
||||
if key not in self.survey.srcList:
|
||||
raise KeyError('Key must be a source in the survey.')
|
||||
return key, None, None
|
||||
else:
|
||||
raise KeyError('Key must be [Src] or [Src,Rx] or [Src, Rx, tInd]')
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
src, rx, t = self._ensureCorrectKey(key)
|
||||
assert rx is not None, 'set data using [Src, Rx]'
|
||||
assert isinstance(value, np.ndarray), 'value must by ndarray'
|
||||
assert value.size == rx.nD, "value must have the same number of data as the source."
|
||||
self._dataDict[src][rx][t] = Utils.mkvc(value)
|
||||
|
||||
def __getitem__(self, key):
|
||||
src, rx, t = self._ensureCorrectKey(key)
|
||||
if rx is not None:
|
||||
if rx not in self._dataDict[src]:
|
||||
raise Exception('Data for receiver has not yet been set.')
|
||||
return self._dataDict[src][rx][t]
|
||||
|
||||
return np.concatenate([self[src,rx, t] for rx in src.rxList])
|
||||
|
||||
def tovec(self):
|
||||
val = []
|
||||
for src in self.survey.srcList:
|
||||
for rx in src.rxList:
|
||||
for t in rx.times:
|
||||
val.append(self[src, rx, t])
|
||||
return np.concatenate(val)
|
||||
|
||||
|
||||
def fromvec(self, v):
|
||||
v = Utils.mkvc(v)
|
||||
assert v.size == self.survey.nD, 'v must have the correct number of data.'
|
||||
indBot, indTop = 0, 0
|
||||
for src in self.survey.srcList:
|
||||
for rx in src.rxList:
|
||||
for t in rx.times:
|
||||
indTop += rx.nRx
|
||||
self[src, rx, t] = v[indBot:indTop]
|
||||
indBot += rx.nRx
|
||||
@@ -0,0 +1,5 @@
|
||||
from ProblemSIP import Problem3D_CC, Problem3D_N
|
||||
from SurveySIP import Survey, Data
|
||||
import SrcSIP as Src #Pole
|
||||
import RxSIP as Rx
|
||||
from Regularization import MultiRegularization
|
||||
@@ -0,0 +1,317 @@
|
||||
from SimPEG import np
|
||||
from SimPEG.EM.Static import DC, IP
|
||||
|
||||
def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None):
|
||||
"""
|
||||
Read list of 2D tx-rx location and plot a speudo-section of apparent
|
||||
resistivity.
|
||||
|
||||
Assumes flat topo for now...
|
||||
|
||||
Input:
|
||||
:param d2D, z0
|
||||
:switch stype -> Either 'pdp' (pole-dipole) | 'dpdp' (dipole-dipole)
|
||||
:switch dtype=-> Either 'appr' (app. res) | 'appc' (app. con) | 'volt' (potential)
|
||||
Output:
|
||||
:figure scatter plot overlayed on image
|
||||
|
||||
Edited Feb 17th, 2016
|
||||
|
||||
@author: dominiquef
|
||||
|
||||
"""
|
||||
from SimPEG import np
|
||||
from scipy.interpolate import griddata
|
||||
import pylab as plt
|
||||
|
||||
# Set depth to 0 for now
|
||||
z0 = 0.
|
||||
|
||||
# Pre-allocate
|
||||
midx = []
|
||||
midz = []
|
||||
rho = []
|
||||
LEG = []
|
||||
count = 0 # Counter for data
|
||||
for ii in range(DCsurvey.nSrc):
|
||||
|
||||
Tx = DCsurvey.srcList[ii].loc
|
||||
Rx = DCsurvey.srcList[ii].rxList[0].locs
|
||||
|
||||
nD = DCsurvey.srcList[ii].rxList[0].nD
|
||||
|
||||
data = DCsurvey.dobs[count:count+nD]
|
||||
count += nD
|
||||
|
||||
# Get distances between each poles A-B-M-N
|
||||
if stype == 'pdp':
|
||||
MA = np.abs(Tx[0] - Rx[0][:,0])
|
||||
NA = np.abs(Tx[0] - Rx[1][:,0])
|
||||
MN = np.abs(Rx[1][:,0] - Rx[0][:,0])
|
||||
|
||||
# Create mid-point location
|
||||
Cmid = Tx[0]
|
||||
Pmid = (Rx[0][:,0] + Rx[1][:,0])/2
|
||||
if DCsurvey.mesh.dim == 2:
|
||||
zsrc = Tx[1]
|
||||
elif DCsurvey.mesh.dim ==3:
|
||||
zsrc = Tx[2]
|
||||
|
||||
elif stype == 'dpdp':
|
||||
MA = np.abs(Tx[0][0] - Rx[0][:,0])
|
||||
MB = np.abs(Tx[1][0] - Rx[0][:,0])
|
||||
NA = np.abs(Tx[0][0] - Rx[1][:,0])
|
||||
NB = np.abs(Tx[1][0] - Rx[1][:,0])
|
||||
|
||||
# Create mid-point location
|
||||
Cmid = (Tx[0][0] + Tx[1][0])/2
|
||||
Pmid = (Rx[0][:,0] + Rx[1][:,0])/2
|
||||
if DCsurvey.mesh.dim == 2:
|
||||
zsrc = (Tx[0][1] + Tx[1][1])/2
|
||||
elif DCsurvey.mesh.dim ==3:
|
||||
zsrc = (Tx[0][2] + Tx[1][2])/2
|
||||
|
||||
# Change output for dtype
|
||||
if dtype == 'volt':
|
||||
|
||||
rho = np.hstack([rho,data])
|
||||
|
||||
else:
|
||||
|
||||
# Compute pant leg of apparent rho
|
||||
if stype == 'pdp':
|
||||
|
||||
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
|
||||
|
||||
elif stype == 'dpdp':
|
||||
|
||||
leg = data * 2*np.pi / ( 1/MA - 1/MB + 1/NB - 1/NA )
|
||||
LEG.append(1./(2*np.pi) *( 1/MA - 1/MB + 1/NB - 1/NA ))
|
||||
else:
|
||||
print """dtype must be 'pdp'(pole-dipole) | 'dpdp' (dipole-dipole) """
|
||||
break
|
||||
|
||||
|
||||
if dtype == 'appc':
|
||||
|
||||
leg = np.log10(abs(1./leg))
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
elif dtype == 'appr':
|
||||
|
||||
leg = np.log10(abs(leg))
|
||||
rho = np.hstack([rho,leg])
|
||||
|
||||
else:
|
||||
print """dtype must be 'appr' | 'appc' | 'volt' """
|
||||
break
|
||||
|
||||
|
||||
midx = np.hstack([midx, ( Cmid + Pmid )/2 ])
|
||||
if DCsurvey.mesh.dim==3:
|
||||
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + zsrc ])
|
||||
elif DCsurvey.mesh.dim==2:
|
||||
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + zsrc ])
|
||||
ax = axs
|
||||
|
||||
# Grid points
|
||||
grid_x, grid_z = np.mgrid[np.min(midx):np.max(midx), np.min(midz):np.max(midz)]
|
||||
grid_rho = griddata(np.c_[midx,midz], rho.T, (grid_x, grid_z), method='linear')
|
||||
|
||||
if clim == None:
|
||||
vmin, vmax = rho.min(), rho.max()
|
||||
else:
|
||||
vmin, vmax = clim[0], clim[1]
|
||||
|
||||
grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho)
|
||||
ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, clim=(vmin, vmax), vmin=vmin, vmax=vmax)
|
||||
cbar = plt.colorbar(format="$10^{%.1f}$",fraction=0.04,orientation="horizontal")
|
||||
|
||||
cmin,cmax = cbar.get_clim()
|
||||
ticks = np.linspace(cmin,cmax,3)
|
||||
cbar.set_ticks(ticks)
|
||||
cbar.ax.tick_params(labelsize=10)
|
||||
|
||||
if dtype == 'appc':
|
||||
cbar.set_label("App.Cond",size=12)
|
||||
elif dtype == 'appr':
|
||||
cbar.set_label("App.Res.",size=12)
|
||||
elif dtype == 'volt':
|
||||
cbar.set_label("Potential (V)",size=12)
|
||||
|
||||
# Plot apparent resistivity
|
||||
ax.scatter(midx,midz,s=10,c=rho.T, vmin =vmin, vmax = vmax, clim=(vmin, vmax))
|
||||
|
||||
#ax.set_xticklabels([])
|
||||
#ax.set_yticklabels([])
|
||||
|
||||
plt.gca().set_aspect('equal', adjustable='box')
|
||||
|
||||
|
||||
|
||||
return ph, LEG
|
||||
|
||||
def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
|
||||
"""
|
||||
Load in endpoints and survey specifications to generate Tx, Rx location
|
||||
stations.
|
||||
|
||||
Assumes flat topo for now...
|
||||
|
||||
Input:
|
||||
:param endl -> input endpoints [x1, y1, z1, x2, y2, z2]
|
||||
:object mesh -> SimPEG mesh object
|
||||
:switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient'
|
||||
: param a, n -> pole seperation, number of rx dipoles per tx
|
||||
|
||||
Output:
|
||||
:param Tx, Rx -> List objects for each tx location
|
||||
Lines: P1x, P1y, P1z, P2x, P2y, P2z
|
||||
|
||||
Created on Wed December 9th, 2015
|
||||
|
||||
@author: dominiquef
|
||||
!! Require clean up to deal with DCsurvey
|
||||
"""
|
||||
|
||||
from SimPEG import np
|
||||
|
||||
def xy_2_r(x1,x2,y1,y2):
|
||||
r = np.sqrt( np.sum((x2 - x1)**2 + (y2 - y1)**2) )
|
||||
return r
|
||||
|
||||
## Evenly distribute electrodes and put on surface
|
||||
# Mesure survey length and direction
|
||||
dl_len = xy_2_r(endl[0,0],endl[1,0],endl[0,1],endl[1,1])
|
||||
|
||||
dl_x = ( endl[1,0] - endl[0,0] ) / dl_len
|
||||
dl_y = ( endl[1,1] - endl[0,1] ) / dl_len
|
||||
|
||||
nstn = np.floor( dl_len / a )
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a
|
||||
|
||||
if mesh.dim==2:
|
||||
ztop = mesh.vectorNy[-1]
|
||||
# Create line of P1 locations
|
||||
M = np.c_[stn_x, np.ones(nstn).T*ztop]
|
||||
# Create line of P2 locations
|
||||
N = np.c_[stn_x+a*dl_x, np.ones(nstn).T*ztop]
|
||||
|
||||
elif mesh.dim==3:
|
||||
ztop = mesh.vectorNz[-1]
|
||||
# Create line of P1 locations
|
||||
M = np.c_[stn_x, stn_y, np.ones(nstn).T*ztop]
|
||||
# Create line of P2 locations
|
||||
N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*ztop]
|
||||
|
||||
|
||||
## Build list of Tx-Rx locations depending on survey type
|
||||
# Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn]
|
||||
# Pole-dipole: Moving pole on one end -> [A a MN1 a MN2 ... MNn a B]
|
||||
SrcList = []
|
||||
|
||||
|
||||
if stype != 'gradient':
|
||||
|
||||
for ii in range(0, int(nstn)-1):
|
||||
|
||||
|
||||
if stype == 'dpdp':
|
||||
tx = np.c_[M[ii,:],N[ii,:]]
|
||||
elif stype == 'pdp':
|
||||
tx = np.c_[M[ii,:],M[ii,:]]
|
||||
|
||||
# Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]])
|
||||
|
||||
# Current elctrode seperation
|
||||
AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1])
|
||||
|
||||
# Number of receivers to fit
|
||||
nstn = np.min([np.floor( (AB - b) / a ) , n])
|
||||
|
||||
# Check if there is enough space, else break the loop
|
||||
if nstn <= 0:
|
||||
continue
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a
|
||||
|
||||
# Create receiver poles
|
||||
|
||||
if mesh.dim==3:
|
||||
# Create line of P1 locations
|
||||
P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*ztop]
|
||||
# Create line of P2 locations
|
||||
P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*ztop]
|
||||
rxClass = DC.Rx.Dipole(P1, P2)
|
||||
|
||||
elif mesh.dim==2:
|
||||
# Create line of P1 locations
|
||||
P1 = np.c_[stn_x, np.ones(nstn).T*ztop]
|
||||
# Create line of P2 locations
|
||||
P2 = np.c_[stn_x+a*dl_x, np.ones(nstn).T*ztop]
|
||||
rxClass = DC.Rx.Dipole_ky(P1, P2)
|
||||
|
||||
if stype == 'dpdp':
|
||||
srcClass = DC.Src.Dipole([rxClass], M[ii,:],N[ii,:])
|
||||
elif stype == 'pdp':
|
||||
srcClass = DC.Src.Pole([rxClass], M[ii,:])
|
||||
SrcList.append(srcClass)
|
||||
|
||||
elif stype == 'gradient':
|
||||
|
||||
# Gradient survey only requires Tx at end of line and creates a square
|
||||
# grid of receivers at in the middle at a pre-set minimum distance
|
||||
|
||||
# Get the edge limit of survey area
|
||||
min_x = endl[0,0] + dl_x * b
|
||||
min_y = endl[0,1] + dl_y * b
|
||||
|
||||
max_x = endl[1,0] - dl_x * b
|
||||
max_y = endl[1,1] - dl_y * b
|
||||
|
||||
box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 )
|
||||
box_w = box_l/2.
|
||||
|
||||
nstn = np.floor( box_l / a )
|
||||
|
||||
# Compute discrete pole location along line
|
||||
stn_x = min_x + np.array(range(int(nstn)))*dl_x*a
|
||||
stn_y = min_y + np.array(range(int(nstn)))*dl_y*a
|
||||
|
||||
# Define number of cross lines
|
||||
nlin = int(np.floor( box_w / a ))
|
||||
lind = range(-nlin,nlin+1)
|
||||
|
||||
ngrad = nstn * len(lind)
|
||||
|
||||
rx = np.zeros([ngrad,6])
|
||||
for ii in range( len(lind) ):
|
||||
|
||||
# Move line in perpendicular direction by dipole spacing
|
||||
lxx = stn_x - lind[ii]*a*dl_y
|
||||
lyy = stn_y + lind[ii]*a*dl_x
|
||||
|
||||
|
||||
M = np.c_[ lxx, lyy , np.ones(nstn).T*ztop]
|
||||
N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*ztop]
|
||||
rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N]
|
||||
|
||||
if mesh.dim==3:
|
||||
rxClass = DC.Rx.Dipole(rx[:,:3], rx[:,3:])
|
||||
elif mesh.dim==2:
|
||||
M = M[:,[0,2]]
|
||||
N = N[:,[0,2]]
|
||||
rxClass = DC.Rx.Dipole_ky(rx[:,[0,2]], rx[:,[3,5]])
|
||||
srcClass = DC.Src.Dipole([rxClass], M[0,:], N[-1,:])
|
||||
SrcList.append(srcClass)
|
||||
else:
|
||||
print """stype must be either 'pdp', 'dpdp' or 'gradient'. """
|
||||
|
||||
|
||||
return SrcList
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
from StaticUtils import *
|
||||
@@ -0,0 +1,3 @@
|
||||
import DC
|
||||
import IP
|
||||
import SIP
|
||||
+13
-13
@@ -108,11 +108,11 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
Ainv.clean()
|
||||
return F
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param numpy.ndarray v: vector (model object)
|
||||
:param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m
|
||||
:param FieldsTDEM f: Fields resulting from m
|
||||
:rtype: numpy.ndarray
|
||||
:return: w (data object)
|
||||
|
||||
@@ -125,19 +125,19 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
"""
|
||||
if self.verbose: print '%s\nCalculating J(v)\n%s'%('*'*50,'*'*50)
|
||||
self.curModel = m
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
p = self.Gvec(m, v, u)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
p = self.Gvec(m, v, f)
|
||||
y = self.solveAh(m, p)
|
||||
Jv = self.survey.evalDeriv(u, v=y)
|
||||
Jv = self.survey.evalDeriv(f, v=y)
|
||||
if self.verbose: print '%s\nDone calculating J(v)\n%s'%('*'*50,'*'*50)
|
||||
return - mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""
|
||||
:param numpy.array m: Conductivity model
|
||||
:param numpy.ndarray,SimPEG.Survey.Data v: vector (data object)
|
||||
:param simpegEM.TDEM.FieldsTDEM u: Fields resulting from m
|
||||
:param numpy.ndarray v: vector (or a :class:`SimPEG.Survey.Data` object)
|
||||
:param FieldsTDEM u: Fields resulting from m
|
||||
:rtype: numpy.ndarray
|
||||
:return: w (model object)
|
||||
|
||||
@@ -150,15 +150,15 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
|
||||
"""
|
||||
if self.verbose: print '%s\nCalculating J^T(v)\n%s'%('*'*50,'*'*50)
|
||||
self.curModel = m
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
if not isinstance(v, self.dataPair):
|
||||
v = self.dataPair(self.survey, v)
|
||||
|
||||
p = self.survey.evalDeriv(u, v=v, adjoint=True)
|
||||
p = self.survey.evalDeriv(f, v=v, adjoint=True)
|
||||
y = self.solveAht(m, p)
|
||||
w = self.Gtvec(m, y, u)
|
||||
w = self.Gtvec(m, y, f)
|
||||
if self.verbose: print '%s\nDone calculating J^T(v)\n%s'%('*'*50,'*'*50)
|
||||
return - mkvc(w)
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ class SrcTDEM_VMD_MVP(SrcTDEM):
|
||||
def getInitialFields(self, mesh):
|
||||
"""Vertical magnetic dipole, magnetic vector potential"""
|
||||
if self.waveformType == "STEPOFF":
|
||||
print ">> Step waveform: Non-zero initial condition"
|
||||
print ">> Step waveform: Non-zero initial condition"
|
||||
if mesh._meshType is 'CYL':
|
||||
if mesh.isSymmetric:
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, 'Ey')
|
||||
@@ -96,8 +96,8 @@ class SrcTDEM_VMD_MVP(SrcTDEM):
|
||||
elif mesh._meshType is 'TENSOR':
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'])
|
||||
else:
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
return {"b": mesh.edgeCurl*MVP}
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
return {"b": mesh.edgeCurl*MVP}
|
||||
elif self.waveformType == "GENERAL":
|
||||
print ">> General waveform: Zero initial condition"
|
||||
return {"b": np.zeros(mesh.nF)}
|
||||
@@ -113,7 +113,7 @@ class SrcTDEM_VMD_MVP(SrcTDEM):
|
||||
elif mesh._meshType is 'TENSOR':
|
||||
MVP = MagneticDipoleVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'])
|
||||
else:
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
raise Exception('Unknown mesh for VMD')
|
||||
return mesh.edgeCurl.T*MfMui*mesh.edgeCurl*MVP
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ class SrcTDEM_CircularLoop_MVP(SrcTDEM):
|
||||
self.loc = loc
|
||||
self.radius = radius
|
||||
self.waveformType = waveformType
|
||||
SrcTDEM.__init__(self,rxList)
|
||||
SrcTDEM.__init__(self,rxList)
|
||||
|
||||
def getInitialFields(self, mesh):
|
||||
"""Circular Loop, magnetic vector potential"""
|
||||
@@ -153,7 +153,7 @@ class SrcTDEM_CircularLoop_MVP(SrcTDEM):
|
||||
elif mesh._meshType is 'TENSOR':
|
||||
MVP = MagneticLoopVectorPotential(self.loc, mesh, ['Ex','Ey','Ez'], self.radius)
|
||||
else:
|
||||
raise Exception('Unknown mesh for CircularLoop')
|
||||
raise Exception('Unknown mesh for CircularLoop')
|
||||
return mesh.edgeCurl.T*MfMui*mesh.edgeCurl*MVP
|
||||
|
||||
|
||||
|
||||
+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 simpegEM.TDEM.FieldsTDEM u: Fields resulting from m
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:param FieldsTDEM u: Fields resulting from m
|
||||
:rtype: 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 simpegEM.TDEM.FieldsTDEM u: Fields resulting from m
|
||||
:rtype: np.ndarray (like a model)
|
||||
:return: p
|
||||
:param FieldsTDEM u: Fields resulting from m
|
||||
:rtype: numpy.ndarray
|
||||
:return: p (like a model)
|
||||
|
||||
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 simpegEM.TDEM.FieldsTDEM p: Fields object
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:param FieldsTDEM p: Fields object
|
||||
:rtype: 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 simpegEM.TDEM.FieldsTDEM p: Fields object
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:param FieldsTDEM p: Fields object
|
||||
:rtype: 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 simpegEM.TDEM.FieldsTDEM vec: Fields object
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:param FieldsTDEM vec: Fields object
|
||||
:rtype: 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 simpegEM.TDEM.FieldsTDEM vec: Fields object
|
||||
:rtype: simpegEM.TDEM.FieldsTDEM
|
||||
:param FieldsTDEM vec: Fields object
|
||||
:rtype: FieldsTDEM
|
||||
:return: f
|
||||
|
||||
Multiply the matrix \\\(\\\hat{A}\\\) by a fields vector where
|
||||
|
||||
@@ -20,56 +20,61 @@ def getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False):
|
||||
mesh = Mesh.TensorMesh([hx,hy,hz],['C','C','C'])
|
||||
|
||||
if useMu is True:
|
||||
mapping = [('sigma', Maps.ExpMap(mesh)), ('mu', Maps.IdentityMap(mesh))]
|
||||
mapping = [('sigma', Maps.ExpMap(mesh)), ('mu', Maps.IdentityMap(mesh))]
|
||||
else:
|
||||
mapping = Maps.ExpMap(mesh)
|
||||
|
||||
x = np.array([np.linspace(-5.*cs,-2.*cs,3),np.linspace(5.*cs,2.*cs,3)]) + cs/4. #don't sample right by the source, slightly off alignment from either staggered grid
|
||||
XYZ = Utils.ndgrid(x,x,np.linspace(-2.*cs,2.*cs,5))
|
||||
Rx0 = EM.FDEM.Rx(XYZ, comp)
|
||||
Rx0 = getattr(EM.FDEM.Rx, 'Point_' + comp[0])
|
||||
if comp[2] == 'r':
|
||||
real_or_imag = 'real'
|
||||
elif comp[2] == 'i':
|
||||
real_or_imag = 'imag'
|
||||
rx0 = Rx0(XYZ, comp[1], 'imag')
|
||||
|
||||
Src = []
|
||||
|
||||
for SrcType in SrcList:
|
||||
if SrcType is 'MagDipole':
|
||||
Src.append(EM.FDEM.Src.MagDipole([Rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
Src.append(EM.FDEM.Src.MagDipole([rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
elif SrcType is 'MagDipole_Bfield':
|
||||
Src.append(EM.FDEM.Src.MagDipole_Bfield([Rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
Src.append(EM.FDEM.Src.MagDipole_Bfield([rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
elif SrcType is 'CircularLoop':
|
||||
Src.append(EM.FDEM.Src.CircularLoop([Rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
Src.append(EM.FDEM.Src.CircularLoop([rx0], freq=freq, loc=np.r_[0.,0.,0.]))
|
||||
elif SrcType is 'RawVec':
|
||||
if fdemType is 'e' or fdemType is 'b':
|
||||
S_m = np.zeros(mesh.nF)
|
||||
S_e = np.zeros(mesh.nE)
|
||||
S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1e-3
|
||||
S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1e-3
|
||||
Src.append(EM.FDEM.Src.RawVec([Rx0], freq, S_m, S_e))
|
||||
Src.append(EM.FDEM.Src.RawVec([rx0], freq, S_m, mesh.getEdgeInnerProduct()*S_e))
|
||||
|
||||
elif fdemType is 'h' or fdemType is 'j':
|
||||
S_m = np.zeros(mesh.nE)
|
||||
S_e = np.zeros(mesh.nF)
|
||||
S_m[Utils.closestPoints(mesh,[0.,0.,0.],'Ez') + np.sum(mesh.vnE[:1])] = 1e-3
|
||||
S_e[Utils.closestPoints(mesh,[0.,0.,0.],'Fz') + np.sum(mesh.vnF[:1])] = 1e-3
|
||||
Src.append(EM.FDEM.Src.RawVec([Rx0], freq, S_m, S_e))
|
||||
Src.append(EM.FDEM.Src.RawVec([rx0], freq, mesh.getEdgeInnerProduct()*S_m, S_e))
|
||||
|
||||
if verbose:
|
||||
print ' Fetching %s problem' % (fdemType)
|
||||
|
||||
if fdemType == 'e':
|
||||
survey = EM.FDEM.Survey(Src)
|
||||
prb = EM.FDEM.Problem_e(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_e(mesh, mapping=mapping)
|
||||
|
||||
elif fdemType == 'b':
|
||||
survey = EM.FDEM.Survey(Src)
|
||||
prb = EM.FDEM.Problem_b(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping)
|
||||
|
||||
elif fdemType == 'j':
|
||||
survey = EM.FDEM.Survey(Src)
|
||||
prb = EM.FDEM.Problem_j(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_j(mesh, mapping=mapping)
|
||||
|
||||
elif fdemType == 'h':
|
||||
survey = EM.FDEM.Survey(Src)
|
||||
prb = EM.FDEM.Problem_h(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_h(mesh, mapping=mapping)
|
||||
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
@@ -90,7 +95,7 @@ def crossCheckTest(SrcList, fdemType1, fdemType2, comp, addrandoms = False, useM
|
||||
prb1 = getFDEMProblem(fdemType1, comp, SrcList, freq, useMu, verbose)
|
||||
mesh = prb1.mesh
|
||||
print 'Cross Checking Forward: %s, %s formulations - %s' % (fdemType1, fdemType2, comp)
|
||||
|
||||
|
||||
logsig = np.log(np.ones(mesh.nC)*CONDUCTIVITY)
|
||||
mu = np.ones(mesh.nC)*MU
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import TDEM
|
||||
import FDEM
|
||||
import Static
|
||||
import Base
|
||||
import Analytics
|
||||
import Utils
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from SimPEG import *
|
||||
import SimPEG.DCIP as DC
|
||||
import SimPEG.EM.Static.DC as DC
|
||||
|
||||
def run(plotIt=False):
|
||||
def run(plotIt=True):
|
||||
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=False):
|
||||
# ax.plot(xyz_rxP[:,0],xyz_rxP[:,1], 'w.')
|
||||
# ax.plot(xyz_rxN[:,0],xyz_rxN[:,1], 'r.', ms = 3)
|
||||
|
||||
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)
|
||||
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)
|
||||
problem.pair(survey)
|
||||
try:
|
||||
from pymatsolver import MumpsSolver
|
||||
@@ -65,4 +65,4 @@ def run(plotIt=False):
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print run(plotIt=True)
|
||||
print run()
|
||||
|
||||
@@ -2,19 +2,27 @@ from SimPEG import Mesh, Utils, np, sp
|
||||
import SimPEG.DCIP as DC
|
||||
import time
|
||||
|
||||
def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
def run(loc=None, sig=None, radi=None, param=None, surveyType='dipole-dipole', unitType='appConductivity', plotIt=True):
|
||||
"""
|
||||
DC Forward Simulation
|
||||
=====================
|
||||
|
||||
Forward model conductive spheres in a half-space and plot a pseudo-section
|
||||
Forward model two conductive spheres in a half-space and plot a
|
||||
pseudo-section. Assumes an infinite line source and measures along the
|
||||
center of the spheres.
|
||||
|
||||
Created by @fourndo on Mon Feb 01 19:28:06 2016
|
||||
INPUT:
|
||||
loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]]
|
||||
radi = Radius of spheres [r1,r2]
|
||||
param = Conductivity of background and two spheres [m0,m1,m2]
|
||||
surveyType = survey type 'pole-dipole' or 'dipole-dipole'
|
||||
unitType = Data type "appResistivity" | "appConductivity" | "volt"
|
||||
Created by @fourndo
|
||||
|
||||
"""
|
||||
|
||||
assert stype in ['pdp', 'dpdp'], "Source type (stype) must be pdp or dpdp (pole dipole or dipole dipole)"
|
||||
|
||||
assert surveyType in ['pole-dipole', 'dipole-dipole'], "Source type (surveyType) must be pdp or dpdp (pole dipole or dipole dipole)"
|
||||
assert unitType in ['appResistivity', 'appConductivity', 'volt'], "Unit type (unitType) must be appResistivity or appConductivity or volt (potential)"
|
||||
|
||||
if loc is None:
|
||||
loc = np.c_[[-50.,0.,-50.],[50.,0.,-50.]]
|
||||
@@ -27,7 +35,6 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
|
||||
|
||||
# First we need to create a mesh and a model.
|
||||
|
||||
# This is our mesh
|
||||
dx = 5.
|
||||
|
||||
@@ -52,14 +59,10 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
# Get index of the center
|
||||
indy = int(mesh.nCy/2)
|
||||
|
||||
|
||||
# Plot the model for reference
|
||||
# Define core mesh extent
|
||||
xlim = 200
|
||||
zlim = 125
|
||||
|
||||
# Specify the survey type: "pdp" | "dpdp"
|
||||
|
||||
zlim = 100
|
||||
|
||||
# Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh
|
||||
ends = [(-175,0),(175,0)]
|
||||
@@ -70,19 +73,20 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
locs = np.c_[mesh.gridCC[indx,0],mesh.gridCC[indx,1],np.ones(2).T*mesh.vectorNz[-1]]
|
||||
|
||||
# We will handle the geometry of the survey for you and create all the combination of tx-rx along line
|
||||
# [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2])
|
||||
survey, Tx, Rx = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2])
|
||||
# [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, surveyType, param[0], param[1], param[2])
|
||||
survey, Tx, Rx = DC.gen_DCIPsurvey(locs, mesh, surveyType, param[0], param[1], param[2])
|
||||
|
||||
# Define some global geometry
|
||||
dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) )
|
||||
dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len
|
||||
dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len
|
||||
azm = np.arctan(dl_y/dl_x)
|
||||
#azm = np.arctan(dl_y/dl_x)
|
||||
|
||||
#Set boundary conditions
|
||||
mesh.setCellGradBC('neumann')
|
||||
|
||||
# Define the differential operators needed for the DC problem
|
||||
# Define the linear system needed for the DC problem. We assume an infitite
|
||||
# line source for simplicity.
|
||||
Div = mesh.faceDiv
|
||||
Grad = mesh.cellGrad
|
||||
Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model)))
|
||||
@@ -114,8 +118,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
rxloc_N = np.asarray(Rx[ii][:,3:])
|
||||
|
||||
|
||||
# For usual cases "dpdp" or "gradient"
|
||||
if stype == 'pdp':
|
||||
# For usual cases 'dipole-dipole' or "gradient"
|
||||
if surveyType == 'pole-dipole':
|
||||
# Create an "inifinity" pole
|
||||
tx = np.squeeze(Tx[ii][:,0:1])
|
||||
tinf = tx + np.array([dl_x,dl_y,0])*dl_len*2
|
||||
@@ -145,16 +149,23 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
print 'Forward completed'
|
||||
|
||||
# Let's just convert the 3D format into 2D (distance along line) and plot
|
||||
# [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc))
|
||||
survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc))
|
||||
survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc) , 'Xloc')
|
||||
survey2D.dobs =np.hstack(data)
|
||||
# Here is an example for the first tx-rx array
|
||||
|
||||
if plotIt:
|
||||
import matplotlib.pyplot as plt
|
||||
fig = plt.figure()
|
||||
fig = plt.figure(figsize=(7,7))
|
||||
ax = plt.subplot(2,1,1, aspect='equal')
|
||||
mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True)
|
||||
ax.set_title('E-W section at '+str(mesh.vectorCCy[indy])+' m')
|
||||
# Plot the location of the spheres for reference
|
||||
circle1=plt.Circle((loc[0,0], loc[2,0]), radi[0], color='w', fill=False, lw=3)
|
||||
circle2=plt.Circle((loc[0,1], loc[2,1]), radi[1], color='k', fill=False, lw=3)
|
||||
ax.add_artist(circle1)
|
||||
ax.add_artist(circle2)
|
||||
|
||||
dat = mesh.plotSlice(np.log10(model), ax = ax, normal = 'Y',
|
||||
ind = indy,grid=True, clim = np.log10([sig.min(),sig.max()]))
|
||||
|
||||
ax.set_title('3-D model')
|
||||
plt.gca().set_aspect('equal', adjustable='box')
|
||||
|
||||
plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v')
|
||||
@@ -163,22 +174,32 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
|
||||
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
|
||||
|
||||
|
||||
ax = plt.subplot(2,1,2, aspect='equal')
|
||||
pos = ax.get_position()
|
||||
ax.set_position([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height])
|
||||
pos = ax.get_position()
|
||||
cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set
|
||||
cb = fig.colorbar(dat[0],cax=cbarax, orientation="horizontal",
|
||||
ax = ax, ticks=np.linspace(np.log10(sig.min()),
|
||||
np.log10(sig.max()), 3), format="$10^{%.1f}$")
|
||||
cb.set_label("Conductivity (S/m)",size=12)
|
||||
cb.ax.tick_params(labelsize=12)
|
||||
|
||||
# Second plot for the predicted apparent resistivity data
|
||||
ax2 = plt.subplot(2,1,2, aspect='equal')
|
||||
|
||||
# Plot the location of the spheres for reference
|
||||
circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3)
|
||||
circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3)
|
||||
ax.add_artist(circle1)
|
||||
ax.add_artist(circle2)
|
||||
circle1=plt.Circle((loc[0,0], loc[2,0]), radi[0], color='w', fill=False, lw=3)
|
||||
circle2=plt.Circle((loc[0,1], loc[2,1]), radi[1], color='k', fill=False, lw=3)
|
||||
ax2.add_artist(circle1)
|
||||
ax2.add_artist(circle2)
|
||||
|
||||
# Add the speudo section
|
||||
DC.plot_pseudoSection(survey2D,ax,stype)
|
||||
|
||||
# plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v')
|
||||
dat = DC.plot_pseudoSection(survey2D, ax2, surveyType=surveyType, unitType=unitType) # plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v')
|
||||
# plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y')
|
||||
# plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k')
|
||||
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
|
||||
ax2.set_title('Apparent Conductivity data')
|
||||
|
||||
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
|
||||
plt.show()
|
||||
|
||||
return fig, ax
|
||||
|
||||
@@ -42,17 +42,16 @@ def run(plotIt=True):
|
||||
ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5)
|
||||
|
||||
|
||||
rxOffset=10.
|
||||
bzi = EM.FDEM.Rx(np.array([[rxOffset, 0., 1e-3]]), 'bzi')
|
||||
rxOffset=10.
|
||||
bzi = EM.FDEM.Rx.Point_b(np.array([[rxOffset, 0., 1e-3]]), orientation='z', component='imag')
|
||||
|
||||
freqs = np.logspace(1,3,10)
|
||||
srcLoc = np.array([0., 0., 10.])
|
||||
|
||||
srcList = []
|
||||
[srcList.append(EM.FDEM.Src.MagDipole([bzi],freq, srcLoc,orientation='Z')) for freq in freqs]
|
||||
srcList = [EM.FDEM.Src.MagDipole([bzi],freq, srcLoc,orientation='Z') for freq in freqs]
|
||||
|
||||
survey = EM.FDEM.Survey(srcList)
|
||||
prb = EM.FDEM.Problem_b(mesh, mapping=mapping)
|
||||
prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping)
|
||||
|
||||
try:
|
||||
from pymatsolver import MumpsSolver
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
from SimPEG import *
|
||||
from SimPEG.EM import FDEM, Analytics, mu_0
|
||||
import time
|
||||
|
||||
try:
|
||||
from pymatsolver import MumpsSolver
|
||||
solver = MumpsSolver
|
||||
except Exception:
|
||||
solver = SolverLU
|
||||
pass
|
||||
|
||||
def run(plotIt=True):
|
||||
"""
|
||||
EM: Schenkel and Morrison Casing Model
|
||||
======================================
|
||||
|
||||
Here we create and run a FDEM forward simulation to calculate the vertical
|
||||
current inside a steel-cased. The model is based on the Schenkel and
|
||||
Morrison Casing Model, and the results are used in a 2016 SEG abstract by
|
||||
Yang et al.
|
||||
|
||||
.. 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.
|
||||
|
||||
|
||||
The model consists of:
|
||||
|
||||
- Air: Conductivity 1e-8 S/m, above z = 0
|
||||
- Background: conductivity 1e-2 S/m, below z = 0
|
||||
- Casing: conductivity 1e6 S/m
|
||||
- 300m long
|
||||
- radius of 0.1m
|
||||
- thickness of 6e-3m
|
||||
|
||||
Inside the casing, we take the same conductivity as the background.
|
||||
|
||||
We are using an EM code to simulate DC, so we use frequency low enough
|
||||
that the skin depth inside the casing is longer than the casing length (f
|
||||
= 1e-6 Hz). The plot produced is of the current inside the casing.
|
||||
|
||||
These results are shown in the SEG abstract by Yang et al., 2016: 3D DC
|
||||
resistivity modeling of steel casing for reservoir monitoring using
|
||||
equivalent resistor network. The solver used to produce these results and
|
||||
achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_
|
||||
|
||||
.. _pymatsolver: https://github.com/rowanc1/pymatsolver
|
||||
|
||||
This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1
|
||||
|
||||
If you would use this example for a code comparison, or build upon it, a
|
||||
citation would be much appreciated!
|
||||
|
||||
"""
|
||||
|
||||
if plotIt:
|
||||
import matplotlib.pylab as plt
|
||||
|
||||
# ------------------ MODEL ------------------
|
||||
sigmaair = 1e-8 # air
|
||||
sigmaback = 1e-2 # background
|
||||
sigmacasing = 1e6 # casing
|
||||
sigmainside = sigmaback # inside the casing
|
||||
|
||||
|
||||
casing_t = 0.006 # 1cm thickness
|
||||
casing_l = 300 # length of the casing
|
||||
|
||||
casing_r = 0.1
|
||||
casing_a = casing_r - casing_t/2. # inner radius
|
||||
casing_b = casing_r + casing_t/2. # outer radius
|
||||
casing_z = np.r_[-casing_l,0.]
|
||||
|
||||
|
||||
# ------------------ SURVEY PARAMETERS ------------------
|
||||
freqs = np.r_[1e-6] #[1e-1, 1, 5] # frequencies
|
||||
dsz = -300 # down-hole z source location
|
||||
src_loc = np.r_[0.,0.,dsz]
|
||||
inf_loc = np.r_[0.,0.,1e4]
|
||||
|
||||
print 'Skin Depth: ', [(500./np.sqrt(sigmaback*_)) for _ in freqs]
|
||||
|
||||
|
||||
# ------------------ MESH ------------------
|
||||
# fine cells near well bore
|
||||
csx1, csx2 = 2e-3, 60.
|
||||
pfx1, pfx2 = 1.3, 1.3
|
||||
ncx1 = np.ceil(casing_b/csx1+2)
|
||||
|
||||
# pad nicely to second cell size
|
||||
npadx1 = np.floor(np.log(csx2/csx1) / np.log(pfx1))
|
||||
hx1a,hx1b = Utils.meshTensor([(csx1,ncx1)]),Utils.meshTensor([(csx1,npadx1,pfx1)])
|
||||
dx1 = sum(hx1a)+sum(hx1b)
|
||||
dx1 = np.floor(dx1/csx2)
|
||||
hx1b *= (dx1*csx2 - sum(hx1a))/sum(hx1b)
|
||||
|
||||
# second chunk of mesh
|
||||
dx2 = 300. # uniform mesh out to here
|
||||
ncx2 = np.ceil((dx2 - dx1)/csx2)
|
||||
npadx2 = 45
|
||||
hx2a, hx2b = Utils.meshTensor([(csx2,ncx2)]), Utils.meshTensor([(csx2,npadx2,pfx2)])
|
||||
hx = np.hstack([hx1a,hx1b,hx2a,hx2b])
|
||||
|
||||
# z-direction
|
||||
csz = 0.05
|
||||
nza = 10
|
||||
ncz, npadzu, npadzd = np.int(np.ceil(np.diff(casing_z)[0]/csz))+10, 68, 68 # cell size, number of core cells, number of padding cells in the x- direction
|
||||
hz = Utils.meshTensor([(csz,npadzd,-1.3), (csz,ncz), (csz,npadzu,1.3)]) # vector of cell widths in the z-direction
|
||||
|
||||
# Mesh
|
||||
mesh = Mesh.CylMesh([hx,1.,hz], [0.,0.,-np.sum(hz[:npadzu+ncz-nza])])
|
||||
|
||||
print 'Mesh Extent xmax: %f,: zmin: %f, zmax: %f'%(mesh.vectorCCx.max(), mesh.vectorCCz.min(), mesh.vectorCCz.max())
|
||||
print 'Number of cells', mesh.nC
|
||||
|
||||
if plotIt is True:
|
||||
fig, ax = plt.subplots(1, 1, figsize=(6, 4))
|
||||
ax.set_title('Simulation Mesh')
|
||||
mesh.plotGrid(ax=ax)
|
||||
plt.show()
|
||||
|
||||
# Put the model on the mesh
|
||||
sigWholespace = sigmaback*np.ones((mesh.nC))
|
||||
|
||||
sigBack = sigWholespace.copy()
|
||||
sigBack[mesh.gridCC[:,2] > 0.] = sigmaair
|
||||
|
||||
sigCasing = sigBack.copy()
|
||||
iCasingZ = (mesh.gridCC[:,2] <= casing_z[1]) & (mesh.gridCC[:,2] >= casing_z[0])
|
||||
iCasingX = (mesh.gridCC[:,0] >= casing_a) & (mesh.gridCC[:,0] <= casing_b)
|
||||
iCasing = iCasingX & iCasingZ
|
||||
sigCasing[iCasing] = sigmacasing
|
||||
|
||||
|
||||
if plotIt is True:
|
||||
|
||||
# plotting parameters
|
||||
xlim = np.r_[0., 0.2]
|
||||
zlim = np.r_[-350., 10.]
|
||||
clim_sig = np.r_[-8,6]
|
||||
|
||||
# plot models
|
||||
fig, ax = plt.subplots(1,1,figsize=(4,4))
|
||||
|
||||
f = plt.colorbar(mesh.plotImage(np.log10(sigCasing),ax=ax)[0], ax=ax)
|
||||
ax.grid(which='both')
|
||||
ax.set_title('Log_10 (Sigma)')
|
||||
ax.set_xlim(xlim)
|
||||
ax.set_ylim(zlim)
|
||||
f.set_clim(clim_sig)
|
||||
|
||||
plt.show()
|
||||
|
||||
|
||||
# -------------- Sources --------------------
|
||||
# Define Custom Current Sources
|
||||
|
||||
# surface source
|
||||
sg_x = np.zeros(mesh.vnF[0],dtype=complex)
|
||||
sg_y = np.zeros(mesh.vnF[1],dtype=complex)
|
||||
sg_z = np.zeros(mesh.vnF[2],dtype=complex)
|
||||
|
||||
nza = 2 # put the wire two cells above the surface
|
||||
ncin = 2
|
||||
|
||||
# vertically directed wire
|
||||
sgv_indx = (mesh.gridFz[:,0] > casing_a) & (mesh.gridFz[:,0] < casing_a + csx1) # hook it up to casing at the surface
|
||||
sgv_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] >= -csz*2)
|
||||
sgv_ind = sgv_indx & sgv_indz
|
||||
sg_z[sgv_ind] = -1.
|
||||
|
||||
# horizontally directed wire
|
||||
sgh_indx = (mesh.gridFx[:,0] > casing_a) & (mesh.gridFx[:,0] <= inf_loc[2])
|
||||
sgh_indz = (mesh.gridFx[:,2] > csz*(nza-0.5)) & (mesh.gridFx[:,2] < csz*(nza+0.5))
|
||||
sgh_ind = sgh_indx & sgh_indz
|
||||
sg_x[sgh_ind] = -1.
|
||||
|
||||
sgv2_indx = (mesh.gridFz[:,0] >= mesh.gridFx[sgh_ind,0].max()) & (mesh.gridFz[:,0] <= inf_loc[2]*1.2) # hook it up to casing at the surface
|
||||
sgv2_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] >= -csz*2)
|
||||
sgv2_ind = sgv2_indx & sgv2_indz
|
||||
sg_z[sgv2_ind] = 1.
|
||||
|
||||
# assemble the source
|
||||
sg = np.hstack([sg_x,sg_y,sg_z])
|
||||
sg_p = [FDEM.Src.RawVec_e([],_,sg/mesh.area) for _ in freqs]
|
||||
|
||||
# downhole source
|
||||
dg_x = np.zeros(mesh.vnF[0],dtype=complex)
|
||||
dg_y = np.zeros(mesh.vnF[1],dtype=complex)
|
||||
dg_z = np.zeros(mesh.vnF[2],dtype=complex)
|
||||
|
||||
# vertically directed wire
|
||||
dgv_indx = (mesh.gridFz[:,0] < csx1) # go through the center of the well
|
||||
dgv_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] > dsz + csz/2.)
|
||||
dgv_ind = dgv_indx & dgv_indz
|
||||
dg_z[dgv_ind] = -1.
|
||||
|
||||
# couple to the casing downhole
|
||||
dgh_indx = mesh.gridFx[:,0] < casing_a + csx1
|
||||
dgh_indz = (mesh.gridFx[:,2] < dsz + csz) & (mesh.gridFx[:,2] >= dsz)
|
||||
dgh_ind = dgh_indx & dgh_indz
|
||||
dg_x[dgh_ind] = 1.
|
||||
|
||||
# horizontal part at surface
|
||||
dgh2_indx = mesh.gridFx[:,0] <= inf_loc[2]*1.2
|
||||
dgh2_indz = sgh_indz.copy()
|
||||
dgh2_ind = dgh2_indx & dgh2_indz
|
||||
dg_x[dgh2_ind] = -1.
|
||||
|
||||
# vertical part at surface
|
||||
dgv2_ind = sgv2_ind.copy()
|
||||
dg_z[dgv2_ind] = 1.
|
||||
|
||||
# assemble the source
|
||||
dg = np.hstack([dg_x,dg_y,dg_z])
|
||||
dg_p = [FDEM.Src.RawVec_e([],_,dg/mesh.area) for _ in freqs]
|
||||
|
||||
# ------------ Problem and Survey ---------------
|
||||
survey = FDEM.Survey(sg_p + dg_p)
|
||||
mapping = [('sigma', Maps.IdentityMap(mesh))]
|
||||
problem = FDEM.Problem3D_h(mesh, mapping=mapping, Solver=solver)
|
||||
problem.pair(survey)
|
||||
|
||||
# ------------- Solve ---------------------------
|
||||
t0 = time.time()
|
||||
fieldsCasing = problem.fields(sigCasing)
|
||||
print 'Time to solve 2 sources', time.time() - t0
|
||||
|
||||
# Plot current
|
||||
|
||||
# current density
|
||||
jn0 = fieldsCasing[dg_p,'j']
|
||||
jn1 = fieldsCasing[sg_p,'j']
|
||||
|
||||
# current
|
||||
in0 = [mesh.area*fieldsCasing[dg_p,'j'][:,i] for i in range(len(freqs))]
|
||||
in1 = [mesh.area*fieldsCasing[sg_p,'j'][:,i] for i in range(len(freqs))]
|
||||
|
||||
in0 = np.vstack(in0).T
|
||||
in1 = np.vstack(in1).T
|
||||
|
||||
# integrate to get z-current inside casing
|
||||
inds_inx = (mesh.gridFz[:,0] >= casing_a) & (mesh.gridFz[:,0] <= casing_b)
|
||||
inds_inz = (mesh.gridFz[:,2] >= dsz ) & (mesh.gridFz[:,2] <= 0)
|
||||
inds_fz = inds_inx & inds_inz
|
||||
|
||||
indsx = [False]*mesh.nFx
|
||||
inds = list(indsx) + list(inds_fz)
|
||||
|
||||
in0_in = in0[np.r_[inds]]
|
||||
in1_in = in1[np.r_[inds]]
|
||||
z_in = mesh.gridFz[inds_fz,2]
|
||||
|
||||
in0_in = in0_in.reshape([in0_in.shape[0]/3,3])
|
||||
in1_in = in1_in.reshape([in1_in.shape[0]/3,3])
|
||||
z_in = z_in.reshape([z_in.shape[0]/3,3])
|
||||
|
||||
I0 = in0_in.sum(1).real
|
||||
I1 = in1_in.sum(1).real
|
||||
z_in = z_in[:,0]
|
||||
|
||||
if plotIt is True:
|
||||
fig, ax = plt.subplots(1,2,figsize=(12,4))
|
||||
|
||||
ax[0].plot(z_in,np.absolute(I0), z_in,np.absolute(I1))
|
||||
ax[0].legend(['top casing', 'bottom casing'],loc='best')
|
||||
ax[0].set_title('Magnitude of Vertical Current in Casing')
|
||||
|
||||
ax[1].semilogy(z_in,np.absolute(I0), z_in,np.absolute(I1))
|
||||
ax[1].legend(['top casing', 'bottom casing'],loc='best')
|
||||
ax[1].set_title('Magnitude of Vertical Current in Casing')
|
||||
ax[1].set_ylim([1e-2, 1.])
|
||||
|
||||
plt.show()
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
from SimPEG import *
|
||||
|
||||
|
||||
def run(N=100, plotIt=True):
|
||||
"""
|
||||
Inversion: Linear Problem
|
||||
=========================
|
||||
|
||||
Here we go over the basics of creating a linear problem and inversion.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
np.random.seed(1)
|
||||
|
||||
std_noise = 1e-2
|
||||
|
||||
mesh = Mesh.TensorMesh([N])
|
||||
|
||||
m0 = np.ones(mesh.nC) * 1e-4
|
||||
mref = np.zeros(mesh.nC)
|
||||
|
||||
nk = 10
|
||||
jk = np.linspace(1.,nk,nk)
|
||||
p = -2.
|
||||
q = 1.
|
||||
|
||||
g = lambda k: np.exp(p*jk[k]*mesh.vectorCCx)*np.cos(np.pi*q*jk[k]*mesh.vectorCCx)
|
||||
|
||||
G = np.empty((nk, mesh.nC))
|
||||
|
||||
for i in range(nk):
|
||||
G[i,:] = g(i)
|
||||
|
||||
mtrue = np.zeros(mesh.nC)
|
||||
mtrue[mesh.vectorCCx > 0.3] = 1.
|
||||
mtrue[mesh.vectorCCx > 0.45] = -0.5
|
||||
mtrue[mesh.vectorCCx > 0.6] = 0
|
||||
|
||||
|
||||
prob = Problem.LinearProblem(mesh, G)
|
||||
survey = Survey.LinearSurvey()
|
||||
survey.pair(prob)
|
||||
survey.dobs = prob.fields(mtrue) + std_noise * np.random.randn(nk)
|
||||
|
||||
wd = np.ones(nk) * std_noise
|
||||
|
||||
# Distance weighting
|
||||
wr = np.sum(prob.G**2.,axis=0)**0.5
|
||||
wr = ( wr/np.max(wr) )
|
||||
|
||||
dmis = DataMisfit.l2_DataMisfit(survey)
|
||||
dmis.Wd = 1./wd
|
||||
|
||||
betaest = Directives.BetaEstimate_ByEig()
|
||||
|
||||
reg = Regularization.Sparse(mesh)
|
||||
reg.mref = mref
|
||||
reg.cell_weights = wr
|
||||
|
||||
reg.mref = np.zeros(mesh.nC)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest,update_Jacobi])
|
||||
|
||||
# Run inversion
|
||||
mrec = inv.run(m0)
|
||||
|
||||
print "Final misfit:" + str(invProb.dmisfit.eval(mrec))
|
||||
|
||||
|
||||
if plotIt:
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2))
|
||||
for i in range(prob.G.shape[0]):
|
||||
axes[0].plot(prob.G[i,:])
|
||||
axes[0].set_title('Columns of matrix G')
|
||||
|
||||
axes[1].plot(mesh.vectorCCx, mtrue, 'b-')
|
||||
axes[1].plot(mesh.vectorCCx, reg.l2model, 'r-')
|
||||
#axes[1].legend(('True Model', 'Recovered Model'))
|
||||
axes[1].set_ylim(-1.0,1.25)
|
||||
|
||||
axes[1].plot(mesh.vectorCCx, mrec, 'k-',lw = 2)
|
||||
axes[1].legend(('True Model', 'Smooth l2-l2',
|
||||
'Sparse lp:' + str(reg.norms[0]) + ', lqx:' + str(reg.norms[1]) ), fontsize = 12)
|
||||
plt.show()
|
||||
|
||||
return prob, survey, mesh, mrec
|
||||
|
||||
if __name__ == '__main__':
|
||||
run()
|
||||
@@ -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.ActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx)
|
||||
actMap = simpeg.Maps.InjectActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx)
|
||||
mappingExpAct = simpeg.Maps.ExpMap(m1d) * actMap
|
||||
|
||||
## Setup the layout of the survey, set the sources and the connected receivers
|
||||
@@ -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)
|
||||
fig = MT.Utils.dataUtils.plotMT1DModelData(problem, [m_0])
|
||||
fig.suptitle('Target - smooth true')
|
||||
|
||||
|
||||
@@ -100,7 +100,7 @@ def run(plotIt=True):
|
||||
# Regularization - with a regularization mesh
|
||||
regMesh = simpeg.Mesh.TensorMesh([m1d.hx[problem.mapping.sigmaMap.maps[-1].indActive]],m1d.x0)
|
||||
reg = simpeg.Regularization.Tikhonov(regMesh)
|
||||
reg.smoothModel = True
|
||||
reg.mrefInSmooth = True
|
||||
reg.alpha_s = 1e-7
|
||||
reg.alpha_x = 1.
|
||||
# Inversion problem
|
||||
|
||||
@@ -12,7 +12,7 @@ except:
|
||||
def run(plotIt=True, nFreq=1):
|
||||
"""
|
||||
MT: 3D: Forward
|
||||
=======================
|
||||
===============
|
||||
|
||||
Forward model 3D MT data.
|
||||
|
||||
@@ -46,16 +46,15 @@ def run(plotIt=True, nFreq=1):
|
||||
survey = MT.Survey(srcList)
|
||||
|
||||
## Setup the problem object
|
||||
problem = MT.Problem3D.eForm_ps(M, sigmaPrimary=sigBG)
|
||||
problem = MT.Problem3D.eForm_ps(M, sigmaPrimary=sigBG, Solver=Solver)
|
||||
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
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
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()
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
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()
|
||||
|
||||
+12
-31
@@ -1,22 +1,25 @@
|
||||
from SimPEG import Mesh, Utils, np, SolverLU
|
||||
|
||||
## 2D DC forward modeling example with Tensor and Curvilinear Meshes
|
||||
|
||||
def run(plotIt=True):
|
||||
|
||||
"""
|
||||
Mesh: Basic Forward 2D DC Resistivity
|
||||
=====================================
|
||||
|
||||
2D DC forward modeling example with Tensor and Curvilinear Meshes
|
||||
"""
|
||||
|
||||
# Step1: Generate Tensor and Curvilinear Mesh
|
||||
sz = [40,40]
|
||||
# Tensor Mesh
|
||||
tM = Mesh.TensorMesh(sz)
|
||||
# Curvilinear Mesh
|
||||
rM = Mesh.CurvilinearMesh(Utils.meshutils.exampleLrmGrid(sz,'rotate'))
|
||||
|
||||
# Step2: Direct Current (DC) operator
|
||||
def DCfun(mesh, pts):
|
||||
D = mesh.faceDiv
|
||||
G = D.T
|
||||
sigma = 1e-2*np.ones(mesh.nC)
|
||||
Msigi = mesh.getFaceInnerProduct(1./sigma)
|
||||
MsigI = Utils.sdInv(Msigi)
|
||||
A = D*MsigI*G
|
||||
MsigI = mesh.getFaceInnerProduct(sigma, invProp=True, invMat=True)
|
||||
A = -D*MsigI*D.T
|
||||
A[-1,-1] /= mesh.vol[-1] # Remove null space
|
||||
rhs = np.zeros(mesh.nC)
|
||||
txind = Utils.meshutils.closestPoints(mesh, pts)
|
||||
@@ -37,39 +40,17 @@ def run(plotIt=True):
|
||||
if not plotIt: return
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib
|
||||
from matplotlib.mlab import griddata
|
||||
|
||||
#Step4: Making Figure
|
||||
fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2))
|
||||
label = ["(a)", "(b)"]
|
||||
opts = {}
|
||||
vmin, vmax = phitM.min(), phitM.max()
|
||||
dat = tM.plotImage(phitM, ax=axes[0], clim=(vmin, vmax), grid=True)
|
||||
|
||||
#TODO: At the moment Curvilinear Mesh do not have plotimage
|
||||
|
||||
Xi = tM.gridCC[:,0].reshape(sz[0], sz[1], order='F')
|
||||
Yi = tM.gridCC[:,1].reshape(sz[0], sz[1], order='F')
|
||||
PHIrM = griddata(rM.gridCC[:,0], rM.gridCC[:,1], phirM, Xi, Yi, interp='linear')
|
||||
axes[1].contourf(Xi, Yi, PHIrM, 100, vmin=vmin, vmax=vmax)
|
||||
|
||||
dat = rM.plotImage(phirM, ax=axes[1], clim=(vmin, vmax), grid=True)
|
||||
cb = plt.colorbar(dat[0], ax=axes[0]); cb.set_label("Voltage (V)")
|
||||
cb = plt.colorbar(dat[0], ax=axes[1]); cb.set_label("Voltage (V)")
|
||||
|
||||
tM.plotGrid(ax=axes[0], **opts)
|
||||
axes[0].set_title('TensorMesh')
|
||||
rM.plotGrid(ax=axes[1], **opts)
|
||||
axes[1].set_title('CurvilinearMesh')
|
||||
for i in range(2):
|
||||
axes[i].set_xlim(0.025, 0.975)
|
||||
axes[i].set_ylim(0.025, 0.975)
|
||||
axes[i].text(0., 1.0, label[i], fontsize=20)
|
||||
if i==0:
|
||||
axes[i].set_ylabel("y")
|
||||
else:
|
||||
axes[i].set_ylabel(" ")
|
||||
axes[i].set_xlabel("x")
|
||||
plt.show()
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
from SimPEG import *
|
||||
from SimPEG.Utils import surface2ind_topo
|
||||
|
||||
|
||||
def run(plotIt=True, nx=5, ny=5):
|
||||
"""
|
||||
|
||||
Utils: surface2ind_topo
|
||||
=======================
|
||||
|
||||
Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below
|
||||
a topographic surface.
|
||||
|
||||
"""
|
||||
|
||||
mesh = Mesh.TensorMesh([nx,ny], x0='CC') # 2D mesh
|
||||
xtopo = np.linspace(mesh.gridN[:,0].min(), mesh.gridN[:,0].max())
|
||||
topo = 0.4*np.sin(xtopo*5) # define a topographic surface
|
||||
|
||||
Topo = np.hstack([Utils.mkvc(xtopo,2), Utils.mkvc(topo,2)]) #make it an array
|
||||
|
||||
indcc = surface2ind_topo(mesh, Topo, 'CC')
|
||||
|
||||
if plotIt:
|
||||
from matplotlib.pylab import plt
|
||||
from scipy.interpolate import interp1d
|
||||
fig, ax = plt.subplots(1,1, figsize=(6,6))
|
||||
mesh.plotGrid(ax=ax, nodes=True, centers=True)
|
||||
ax.plot(xtopo,topo,'k',linewidth=1)
|
||||
ax.plot(mesh.vectorCCx, interp1d(xtopo,topo)(mesh.vectorCCx),'--k',linewidth=3)
|
||||
|
||||
aveN2CC = Utils.sdiag(mesh.aveN2CC.T.sum(1))*mesh.aveN2CC.T
|
||||
a = aveN2CC * indcc
|
||||
a[a > 0] = 1.
|
||||
a[a < 0.25] = np.nan
|
||||
a = a.reshape(mesh.vnN, order='F')
|
||||
masked_array = np.ma.array(a, mask=np.isnan(a))
|
||||
ax.pcolor(mesh.vectorNx,mesh.vectorNy,masked_array.T, cmap=plt.cm.gray, alpha=0.2)
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
run(plotIt=True)
|
||||
@@ -5,10 +5,14 @@ import DC_Analytic_Dipole
|
||||
import DC_Forward_PseudoSection
|
||||
import EM_FDEM_1D_Inversion
|
||||
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
|
||||
@@ -18,8 +22,9 @@ import Mesh_QuadTree_HangingNodes
|
||||
import Mesh_Tensor_Creation
|
||||
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_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"]
|
||||
__examples__ = ["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"]
|
||||
|
||||
##### AUTOIMPORTS #####
|
||||
|
||||
@@ -35,7 +40,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', 'examples'])
|
||||
docExamplesDir = os.path.sep.join(fName.split(os.path.sep)[:-3] + ['docs', 'content', 'examples'])
|
||||
shutil.rmtree(docExamplesDir)
|
||||
os.makedirs(docExamplesDir)
|
||||
|
||||
@@ -92,12 +97,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', 'examples', name + '.rst']))
|
||||
rst = os.path.sep.join((filePath.split(os.path.sep)[:-3] + ['docs', 'content', '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.csr_matrix
|
||||
:rtype: scipy.sparse.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.csr_matrix
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: derivative of transformed model
|
||||
|
||||
The *transform* changes the model into the physical property.
|
||||
|
||||
@@ -45,19 +45,19 @@ class RichardsSurvey(Survey.BaseSurvey):
|
||||
|
||||
@Utils.count
|
||||
@Utils.requires('prob')
|
||||
def dpred(self, m, u=None):
|
||||
def dpred(self, m, f=None):
|
||||
"""
|
||||
Create the projected data from a model.
|
||||
The field, u, (if provided) will be used for the predicted data
|
||||
The field, f, (if provided) will be used for the predicted data
|
||||
instead of recalculating the fields (which may be expensive!).
|
||||
|
||||
.. math::
|
||||
d_\\text{pred} = P(u(m), m)
|
||||
d_\\text{pred} = P(f(m), m)
|
||||
|
||||
Where P is a projection of the fields onto the data space.
|
||||
"""
|
||||
if u is None: u = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(u, m))
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(f, m))
|
||||
|
||||
@Utils.requires('prob')
|
||||
def eval(self, U, m):
|
||||
@@ -233,16 +233,16 @@ class RichardsProblem(Problem.BaseTimeProblem):
|
||||
return r, J
|
||||
|
||||
@Utils.timeIt
|
||||
def Jfull(self, m, u=None):
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
def Jfull(self, m, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
nn = len(u)-1
|
||||
nn = len(f)-1
|
||||
Asubs, Adiags, Bs = range(nn), range(nn), range(nn)
|
||||
for ii in range(nn):
|
||||
dt = self.timeSteps[ii]
|
||||
bc = self.getBoundaryConditions(ii, u[ii])
|
||||
Asubs[ii], Adiags[ii], Bs[ii] = self.diagsJacobian(m, u[ii], u[ii+1], dt, bc)
|
||||
bc = self.getBoundaryConditions(ii, f[ii])
|
||||
Asubs[ii], Adiags[ii], Bs[ii] = self.diagsJacobian(m, f[ii], f[ii+1], dt, bc)
|
||||
Ad = sp.block_diag(Adiags)
|
||||
zRight = Utils.spzeros((len(Asubs)-1)*Asubs[0].shape[0],Adiags[0].shape[1])
|
||||
zTop = Utils.spzeros(Adiags[0].shape[0], len(Adiags)*Adiags[0].shape[1])
|
||||
@@ -251,7 +251,7 @@ class RichardsProblem(Problem.BaseTimeProblem):
|
||||
B = np.array(sp.vstack(Bs).todense())
|
||||
|
||||
Ainv = self.Solver(A, **self.solverOpts)
|
||||
P = self.survey.evalDeriv(u, m)
|
||||
P = self.survey.evalDeriv(f, m)
|
||||
AinvB = Ainv * B
|
||||
z = np.zeros((self.mesh.nC, B.shape[1]))
|
||||
zAinvB = np.vstack((z, AinvB))
|
||||
@@ -259,41 +259,41 @@ class RichardsProblem(Problem.BaseTimeProblem):
|
||||
return J
|
||||
|
||||
@Utils.timeIt
|
||||
def Jvec(self, m, v, u=None):
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
def Jvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
JvC = range(len(u)-1) # Cell to hold each row of the long vector.
|
||||
JvC = range(len(f)-1) # Cell to hold each row of the long vector.
|
||||
|
||||
# This is done via forward substitution.
|
||||
bc = self.getBoundaryConditions(0, u[0])
|
||||
temp, Adiag, B = self.diagsJacobian(m, u[0], u[1], self.timeSteps[0], bc)
|
||||
bc = self.getBoundaryConditions(0, f[0])
|
||||
temp, Adiag, B = self.diagsJacobian(m, f[0], f[1], self.timeSteps[0], bc)
|
||||
Adiaginv = self.Solver(Adiag, **self.solverOpts)
|
||||
JvC[0] = Adiaginv * (B*v)
|
||||
|
||||
for ii in range(1,len(u)-1):
|
||||
bc = self.getBoundaryConditions(ii, u[ii])
|
||||
Asub, Adiag, B = self.diagsJacobian(m, u[ii], u[ii+1], self.timeSteps[ii], bc)
|
||||
for ii in range(1,len(f)-1):
|
||||
bc = self.getBoundaryConditions(ii, f[ii])
|
||||
Asub, Adiag, B = self.diagsJacobian(m, f[ii], f[ii+1], self.timeSteps[ii], bc)
|
||||
Adiaginv = self.Solver(Adiag, **self.solverOpts)
|
||||
JvC[ii] = Adiaginv * (B*v - Asub*JvC[ii-1])
|
||||
|
||||
P = self.survey.evalDeriv(u, m)
|
||||
P = self.survey.evalDeriv(f, m)
|
||||
return P * np.concatenate([np.zeros(self.mesh.nC)] + JvC)
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec(self, m, v, u=None):
|
||||
if u is None:
|
||||
u = self.field(m)
|
||||
def Jtvec(self, m, v, f=None):
|
||||
if f is None:
|
||||
f = self.field(m)
|
||||
|
||||
P = self.survey.evalDeriv(u, m)
|
||||
P = self.survey.evalDeriv(f, m)
|
||||
PTv = P.T*v
|
||||
|
||||
# This is done via backward substitution.
|
||||
minus = 0
|
||||
BJtv = 0
|
||||
for ii in range(len(u)-1,0,-1):
|
||||
bc = self.getBoundaryConditions(ii-1, u[ii-1])
|
||||
Asub, Adiag, B = self.diagsJacobian(m, u[ii-1], u[ii], self.timeSteps[ii-1], bc)
|
||||
for ii in range(len(f)-1,0,-1):
|
||||
bc = self.getBoundaryConditions(ii-1, f[ii-1])
|
||||
Asub, Adiag, B = self.diagsJacobian(m, f[ii-1], f[ii], self.timeSteps[ii-1], bc)
|
||||
#select the correct part of v
|
||||
vpart = range((ii)*Adiag.shape[0], (ii+1)*Adiag.shape[0])
|
||||
AdiaginvT = self.Solver(Adiag.T, **self.solverOpts)
|
||||
|
||||
+13
-13
@@ -82,23 +82,23 @@ class BaseInvProblem(object):
|
||||
self._warmstart = value
|
||||
|
||||
def getFields(self, m, store=False, deleteWarmstart=True):
|
||||
u = None
|
||||
f = None
|
||||
|
||||
for mtest, u_ofmtest in self.warmstart:
|
||||
if m is mtest:
|
||||
u = u_ofmtest
|
||||
f = u_ofmtest
|
||||
if self.debug: print 'InvProb is Warm Starting!'
|
||||
break
|
||||
|
||||
if u is None:
|
||||
u = self.prob.fields(m)
|
||||
if f is None:
|
||||
f = self.prob.fields(m)
|
||||
|
||||
if deleteWarmstart:
|
||||
self.warmstart = []
|
||||
if store:
|
||||
self.warmstart += [(m,u)]
|
||||
self.warmstart += [(m,f)]
|
||||
|
||||
return u
|
||||
return f
|
||||
|
||||
@Utils.timeIt
|
||||
def evalFunction(self, m, return_g=True, return_H=True):
|
||||
@@ -109,21 +109,21 @@ class BaseInvProblem(object):
|
||||
gc.collect()
|
||||
|
||||
# Store fields if doing a line-search
|
||||
u = self.getFields(m, store=(return_g==False and return_H==False))
|
||||
f = self.getFields(m, store=(return_g==False and return_H==False))
|
||||
|
||||
phi_d = self.dmisfit.eval(m, u=u)
|
||||
phi_d = self.dmisfit.eval(m, f=f)
|
||||
phi_m = self.reg.eval(m)
|
||||
|
||||
self.dpred = self.survey.dpred(m, u=u) # This is a cheap matrix vector calculation.
|
||||
self.dpred = self.survey.dpred(m, f=f) # This is a cheap matrix vector calculation.
|
||||
|
||||
self.phi_d, self.phi_d_last = phi_d, self.phi_d
|
||||
self.phi_m, self.phi_m_last = phi_m, self.phi_m
|
||||
|
||||
f = phi_d + self.beta * phi_m
|
||||
phi = phi_d + self.beta * phi_m
|
||||
|
||||
out = (f,)
|
||||
out = (phi,)
|
||||
if return_g:
|
||||
phi_dDeriv = self.dmisfit.evalDeriv(m, u=u)
|
||||
phi_dDeriv = self.dmisfit.evalDeriv(m, f=f)
|
||||
phi_mDeriv = self.reg.evalDeriv(m)
|
||||
|
||||
g = phi_dDeriv + self.beta * phi_mDeriv
|
||||
@@ -131,7 +131,7 @@ class BaseInvProblem(object):
|
||||
|
||||
if return_H:
|
||||
def H_fun(v):
|
||||
phi_d2Deriv = self.dmisfit.eval2Deriv(m, v, u=u)
|
||||
phi_d2Deriv = self.dmisfit.eval2Deriv(m, v, f=f)
|
||||
phi_m2Deriv = self.reg.eval2Deriv(m, v=v)
|
||||
|
||||
return phi_d2Deriv + self.beta * phi_m2Deriv
|
||||
|
||||
+3
-1
@@ -33,7 +33,9 @@ class BaseInversion(object):
|
||||
self._directiveList = value
|
||||
self._directiveList.inversion = self
|
||||
|
||||
def __init__(self, invProb, directiveList=[], **kwargs):
|
||||
def __init__(self, invProb, directiveList=None, **kwargs):
|
||||
if directiveList is None:
|
||||
directiveList = []
|
||||
self.directiveList = directiveList
|
||||
Utils.setKwargs(self, **kwargs)
|
||||
|
||||
|
||||
+14
-14
@@ -1,5 +1,5 @@
|
||||
from SimPEG import SolverLU as SimpegSolver, PropMaps, Utils, mkvc, sp, np
|
||||
from SimPEG.EM.FDEM.FDEM import BaseFDEMProblem
|
||||
from SimPEG.EM.FDEM.ProblemFDEM import BaseFDEMProblem
|
||||
from SurveyMT import Survey, Data
|
||||
from FieldsMT import BaseMTFields
|
||||
|
||||
@@ -27,7 +27,7 @@ class BaseMTProblem(BaseFDEMProblem):
|
||||
# Might need to add more stuff here.
|
||||
|
||||
## NEED to clean up the Jvec and Jtvec to use Zero and Identities for None components.
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""
|
||||
Function to calculate the data sensitivities dD/dm times a vector.
|
||||
|
||||
@@ -39,8 +39,8 @@ class BaseMTProblem(BaseFDEMProblem):
|
||||
"""
|
||||
|
||||
# Calculate the fields
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
if f is None:
|
||||
f= self.fields(m)
|
||||
# Set current model
|
||||
self.curModel = m
|
||||
# Initiate the Jv object
|
||||
@@ -56,9 +56,9 @@ class BaseMTProblem(BaseFDEMProblem):
|
||||
# We need fDeriv_m = df/du*du/dm + df/dm
|
||||
# Construct du/dm, it requires a solve
|
||||
# NOTE: need to account for the 2 polarizations in the derivatives.
|
||||
u_src = u[src,:]
|
||||
f_src = f[src,:]
|
||||
# dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by dA_duI. The 2 columns are each of the polarizations.
|
||||
dA_dm = self.getADeriv_m(freq, u_src, v) # Size: nE,2 (u_px,u_py) in the columns.
|
||||
dA_dm = self.getADeriv_m(freq, f_src, v) # Size: nE,2 (u_px,u_py) in the columns.
|
||||
dRHS_dm = self.getRHSDeriv_m(freq, v) # Size: nE,2 (u_px,u_py) in the columns.
|
||||
if dRHS_dm is None:
|
||||
du_dm = dA_duI * ( -dA_dm )
|
||||
@@ -68,13 +68,13 @@ class BaseMTProblem(BaseFDEMProblem):
|
||||
for rx in src.rxList:
|
||||
# Get the projection derivative
|
||||
# v should be of size 2*nE (for 2 polarizations)
|
||||
PDeriv_u = lambda t: rx.evalDeriv(src, self.mesh, u, t) # wrt u, we don't have have PDeriv wrt m
|
||||
PDeriv_u = lambda t: rx.evalDeriv(src, self.mesh, f, t) # wrt u, we don't have have PDeriv wrt m
|
||||
Jv[src, rx] = PDeriv_u(mkvc(du_dm))
|
||||
dA_duI.clean()
|
||||
# Return the vectorized sensitivities
|
||||
return mkvc(Jv)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""
|
||||
Function to calculate the transpose of the data sensitivities (dD/dm)^T times a vector.
|
||||
|
||||
@@ -85,8 +85,8 @@ class BaseMTProblem(BaseFDEMProblem):
|
||||
:return: Data sensitivities wrt m
|
||||
"""
|
||||
|
||||
if u is None:
|
||||
u = self.fields(m)
|
||||
if f is None:
|
||||
f = self.fields(m)
|
||||
|
||||
self.curModel = m
|
||||
|
||||
@@ -103,15 +103,15 @@ class BaseMTProblem(BaseFDEMProblem):
|
||||
|
||||
for src in self.survey.getSrcByFreq(freq):
|
||||
ftype = self._fieldType + 'Solution'
|
||||
u_src = u[src, :]
|
||||
f_src = f[src, :]
|
||||
|
||||
for rx in src.rxList:
|
||||
# Get the adjoint evalDeriv
|
||||
# PTv needs to be nE,
|
||||
PTv = rx.evalDeriv(src, self.mesh, u, mkvc(v[src, rx],2), adjoint=True) # wrt u, need possibility wrt m
|
||||
PTv = rx.evalDeriv(src, self.mesh, f, mkvc(v[src, rx],2), adjoint=True) # wrt u, need possibility wrt m
|
||||
# Get the
|
||||
dA_duIT = ATinv * PTv
|
||||
dA_dmT = self.getADeriv_m(freq, u_src, mkvc(dA_duIT), adjoint=True)
|
||||
dA_dmT = self.getADeriv_m(freq, f_src, mkvc(dA_duIT), adjoint=True)
|
||||
dRHS_dmT = self.getRHSDeriv_m(freq, mkvc(dA_duIT), adjoint=True)
|
||||
# Make du_dmT
|
||||
if dRHS_dmT is None:
|
||||
@@ -129,4 +129,4 @@ class BaseMTProblem(BaseFDEMProblem):
|
||||
raise Exception('Must be real or imag')
|
||||
# Clean the factorization, clear memory.
|
||||
ATinv.clean()
|
||||
return Jtv
|
||||
return Jtv
|
||||
|
||||
+2
-2
@@ -86,7 +86,7 @@ class polxy_1Dprimary(BaseMTSrc):
|
||||
Get the electrical field source
|
||||
"""
|
||||
e_p = self.ePrimary(problem)
|
||||
Map_sigma_p = Maps.Vertical1DMap(problem.mesh)
|
||||
Map_sigma_p = Maps.SurjectVertical1D(problem.mesh)
|
||||
sigma_p = Map_sigma_p._transform(self.sigma1d)
|
||||
# Make mass matrix
|
||||
# Note: M(sig) - M(sig_p) = M(sig - sig_p)
|
||||
@@ -163,7 +163,7 @@ class polxy_3Dprimary(BaseMTSrc):
|
||||
Get the electrical field source
|
||||
"""
|
||||
e_p = self.ePrimary(problem)
|
||||
Map_sigma_p = Maps.Vertical1DMap(problem.mesh)
|
||||
Map_sigma_p = Maps.SurjectVertical1D(problem.mesh)
|
||||
sigma_p = Map_sigma_p._transform(self.sigma1d)
|
||||
# Make mass matrix
|
||||
# Note: M(sig) - M(sig_p) = M(sig - sig_p)
|
||||
|
||||
@@ -427,15 +427,15 @@ class Survey(SimPEGsurvey.BaseSurvey):
|
||||
assert freq in self._freqDict, "The requested frequency is not in this survey."
|
||||
return self._freqDict[freq]
|
||||
|
||||
def eval(self, u):
|
||||
def eval(self, f):
|
||||
data = Data(self)
|
||||
for src in self.srcList:
|
||||
sys.stdout.flush()
|
||||
for rx in src.rxList:
|
||||
data[src, rx] = rx.eval(src, self.mesh, u)
|
||||
data[src, rx] = rx.eval(src, self.mesh, f)
|
||||
return data
|
||||
|
||||
def evalDeriv(self, u):
|
||||
def evalDeriv(self, f):
|
||||
raise Exception('Use Transmitters to project fields deriv.')
|
||||
|
||||
#################
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,17 +7,16 @@ from SimPEG.MT.Utils.dataUtils import rec2ndarr
|
||||
# Import modules
|
||||
import numpy as np
|
||||
import os, sys, re
|
||||
try:
|
||||
import osr
|
||||
except ImportError as e:
|
||||
print 'Could not import osr, missing the gdal package'
|
||||
pass
|
||||
|
||||
|
||||
class EDIimporter:
|
||||
"""
|
||||
A class to import EDIfiles.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# Define data converters
|
||||
_impUnitEDI2SI = 4*np.pi*1e-4 # Convert Z[mV/km/nT] (as in EDI)to Z[V/A] SI unit
|
||||
_impUnitSI2EDI = 1./_impUnitEDI2SI # ConvertZ[V/A] SI unit to Z[mV/km/nT] (as in EDI)
|
||||
|
||||
@@ -26,8 +25,8 @@ class EDIimporter:
|
||||
comps = None
|
||||
|
||||
# Hidden properties
|
||||
_outEPSG = None
|
||||
_2out = None
|
||||
_outEPSG = None # Project info
|
||||
_2out = None # The projection operator
|
||||
|
||||
|
||||
def __init__(self, EDIfilesList, compList=None, outEPSG=None):
|
||||
@@ -113,6 +112,12 @@ class EDIimporter:
|
||||
# nOutData=length(obj.data);
|
||||
# obj.data(nOutData+1:nOutData+length(TEMP.data),:) = TEMP.data;
|
||||
def _transfromPoints(self,longD,latD):
|
||||
# Import the coordinate projections
|
||||
try:
|
||||
import osr
|
||||
except ImportError as e:
|
||||
print 'Could not import osr, missing the gdal package\nCan not project coordinates'
|
||||
raise e
|
||||
# Coordinates convertor
|
||||
if self._2out is None:
|
||||
src = osr.SpatialReference()
|
||||
|
||||
+330
-246
File diff suppressed because it is too large
Load Diff
+26
-24
@@ -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,list n: number of cells in each direction (dim, )
|
||||
:param numpy.array,list x0: Origin of the mesh (dim, )
|
||||
:param numpy.array n: (or list) number of cells in each direction (dim, )
|
||||
:param numpy.array x0: (or list) Origin of the mesh (dim, )
|
||||
|
||||
"""
|
||||
|
||||
@@ -34,8 +34,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Origin of the mesh
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: x0
|
||||
:rtype: numpy.array
|
||||
:return: x0, (dim, )
|
||||
"""
|
||||
return self._x0
|
||||
|
||||
@@ -116,8 +116,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Total number of edges in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: [nEx, nEy, nEz]
|
||||
:rtype: numpy.array
|
||||
:return: [nEx, nEy, nEz], (dim, )
|
||||
|
||||
.. plot::
|
||||
:include-source:
|
||||
@@ -173,8 +173,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Total number of faces in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: [nFx, nFy, nFz]
|
||||
:rtype: numpy.array
|
||||
:return: [nFx, nFy, nFz], (dim, )
|
||||
|
||||
.. plot::
|
||||
:include-source:
|
||||
@@ -200,8 +200,8 @@ class BaseMesh(object):
|
||||
"""
|
||||
Face Normals
|
||||
|
||||
:rtype: numpy.array (sum(nF), dim)
|
||||
:return: normals
|
||||
:rtype: numpy.array
|
||||
:return: normals, (sum(nF), dim)
|
||||
"""
|
||||
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 (sum(nE), dim)
|
||||
:return: normals
|
||||
:rtype: numpy.array
|
||||
:return: normals, (sum(nE), dim)
|
||||
"""
|
||||
if self.dim == 2:
|
||||
tX = np.c_[np.ones(self.nEx), np.zeros(self.nEx)]
|
||||
@@ -236,8 +236,9 @@ 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 with shape (nF, )
|
||||
:return: projected face vector
|
||||
:rtype: numpy.array
|
||||
:return: projected face vector, (nF, )
|
||||
|
||||
"""
|
||||
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)'
|
||||
@@ -248,8 +249,9 @@ 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 with shape (nE, )
|
||||
:return: projected edge vector
|
||||
:rtype: numpy.array
|
||||
:return: projected edge vector, (nE, )
|
||||
|
||||
"""
|
||||
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)'
|
||||
@@ -295,7 +297,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Total number of cells in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:rtype: numpy.array
|
||||
:return: [nCx, nCy, nCz]
|
||||
"""
|
||||
return np.array([x for x in [self.nCx, self.nCy, self.nCz] if not x is None])
|
||||
@@ -335,7 +337,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Total number of nodes in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:rtype: numpy.array
|
||||
:return: [nNx, nNy, nNz]
|
||||
"""
|
||||
return np.array([x for x in [self.nNx, self.nNy, self.nNz] if not x is None])
|
||||
@@ -345,7 +347,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of x-edges in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:rtype: numpy.array
|
||||
:return: vnEx
|
||||
"""
|
||||
return np.array([x for x in [self.nCx, self.nNy, self.nNz] if not x is None])
|
||||
@@ -355,7 +357,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of y-edges in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:rtype: numpy.array
|
||||
: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])
|
||||
@@ -365,7 +367,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of z-edges in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:rtype: numpy.array
|
||||
: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])
|
||||
@@ -375,7 +377,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of x-faces in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:rtype: numpy.array
|
||||
:return: vnFx
|
||||
"""
|
||||
return np.array([x for x in [self.nNx, self.nCy, self.nCz] if not x is None])
|
||||
@@ -385,7 +387,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of y-faces in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:rtype: numpy.array
|
||||
: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])
|
||||
@@ -395,7 +397,7 @@ class BaseRectangularMesh(BaseMesh):
|
||||
"""
|
||||
Number of z-faces in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:rtype: numpy.array
|
||||
: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,6 +2,7 @@ from SimPEG import Utils, np
|
||||
from BaseMesh import BaseRectangularMesh
|
||||
from DiffOperators import DiffOperators
|
||||
from InnerProducts import InnerProducts
|
||||
from View import CurvView
|
||||
|
||||
# Some helper functions.
|
||||
length2D = lambda x: (x[:, 0]**2 + x[:, 1]**2)**0.5
|
||||
@@ -10,7 +11,7 @@ normalize2D = lambda x: x/np.kron(np.ones((1, 2)), Utils.mkvc(length2D(x), 2))
|
||||
normalize3D = lambda x: x/np.kron(np.ones((1, 3)), Utils.mkvc(length3D(x), 2))
|
||||
|
||||
|
||||
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
|
||||
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts, CurvView):
|
||||
"""
|
||||
CurvilinearMesh is a mesh class that deals with curvilinear meshes.
|
||||
|
||||
@@ -330,102 +331,6 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
|
||||
|
||||
|
||||
|
||||
#############################################
|
||||
# Plotting Functions #
|
||||
#############################################
|
||||
|
||||
def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False):
|
||||
"""Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions.
|
||||
|
||||
|
||||
.. plot::
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh, Utils
|
||||
X, Y = Utils.exampleLrmGrid([3,3],'rotate')
|
||||
M = Mesh.CurvilinearMesh([X, Y])
|
||||
M.plotGrid(showIt=True)
|
||||
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
mkvc = Utils.mkvc
|
||||
|
||||
axOpts = {'projection':'3d'} if self.dim == 3 else {}
|
||||
if ax is None: ax = plt.subplot(111, **axOpts)
|
||||
|
||||
NN = self.r(self.gridN, 'N', 'N', 'M')
|
||||
if self.dim == 2:
|
||||
|
||||
if lines:
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
|
||||
|
||||
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
|
||||
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
|
||||
|
||||
X = np.r_[X1, X2]
|
||||
Y = np.r_[Y1, Y2]
|
||||
|
||||
ax.plot(X, Y, 'b-')
|
||||
if centers:
|
||||
ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro')
|
||||
|
||||
# Nx = self.r(self.normals, 'F', 'Fx', 'V')
|
||||
# Ny = self.r(self.normals, 'F', 'Fy', 'V')
|
||||
# Tx = self.r(self.tangents, 'E', 'Ex', 'V')
|
||||
# Ty = self.r(self.tangents, 'E', 'Ey', 'V')
|
||||
|
||||
# ax.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
|
||||
|
||||
# nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
|
||||
# ax.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
|
||||
# ax.plot(nX, nY, 'r-')
|
||||
|
||||
# nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
|
||||
# #ax.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
|
||||
# ax.plot(nX, nY, 'g-')
|
||||
|
||||
# tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
|
||||
# tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
|
||||
# ax.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
|
||||
# ax.plot(tX, tY, 'r-')
|
||||
|
||||
# nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
|
||||
# #ax.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
|
||||
# ax.plot(nX, nY, 'g-')
|
||||
|
||||
elif self.dim == 3:
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :, :]), mkvc(NN[0][1:, :, :]), mkvc(NN[0][:-1, :, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :, :]), mkvc(NN[1][1:, :, :]), mkvc(NN[1][:-1, :, :])*np.nan].flatten()
|
||||
Z1 = np.c_[mkvc(NN[2][:-1, :, :]), mkvc(NN[2][1:, :, :]), mkvc(NN[2][:-1, :, :])*np.nan].flatten()
|
||||
|
||||
X2 = np.c_[mkvc(NN[0][:, :-1, :]), mkvc(NN[0][:, 1:, :]), mkvc(NN[0][:, :-1, :])*np.nan].flatten()
|
||||
Y2 = np.c_[mkvc(NN[1][:, :-1, :]), mkvc(NN[1][:, 1:, :]), mkvc(NN[1][:, :-1, :])*np.nan].flatten()
|
||||
Z2 = np.c_[mkvc(NN[2][:, :-1, :]), mkvc(NN[2][:, 1:, :]), mkvc(NN[2][:, :-1, :])*np.nan].flatten()
|
||||
|
||||
X3 = np.c_[mkvc(NN[0][:, :, :-1]), mkvc(NN[0][:, :, 1:]), mkvc(NN[0][:, :, :-1])*np.nan].flatten()
|
||||
Y3 = np.c_[mkvc(NN[1][:, :, :-1]), mkvc(NN[1][:, :, 1:]), mkvc(NN[1][:, :, :-1])*np.nan].flatten()
|
||||
Z3 = np.c_[mkvc(NN[2][:, :, :-1]), mkvc(NN[2][:, :, 1:]), mkvc(NN[2][:, :, :-1])*np.nan].flatten()
|
||||
|
||||
X = np.r_[X1, X2, X3]
|
||||
Y = np.r_[Y1, Y2, Y3]
|
||||
Z = np.r_[Z1, Z2, Z3]
|
||||
|
||||
ax.plot(X, Y, 'b', zs=Z)
|
||||
ax.set_zlabel('x3')
|
||||
|
||||
ax.grid(True)
|
||||
ax.set_xlabel('x1')
|
||||
ax.set_ylabel('x2')
|
||||
|
||||
if showIt: plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
nc = 5
|
||||
h1 = np.cumsum(np.r_[0, np.ones(nc)/(nc)])
|
||||
|
||||
+18
-15
@@ -68,8 +68,8 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
"""
|
||||
Number of x-faces in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnFx
|
||||
:rtype: numpy.array
|
||||
:return: vnFx, (dim, )
|
||||
"""
|
||||
return self.vnC
|
||||
|
||||
@@ -78,8 +78,8 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
"""
|
||||
Number of y-edges in each direction
|
||||
|
||||
:rtype: numpy.array (dim, )
|
||||
:return: vnEy or None if dim < 2
|
||||
:rtype: numpy.array
|
||||
:return: vnEy or None if dim < 2, (dim, )
|
||||
"""
|
||||
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 (dim, )
|
||||
:return: vnEz or None if nCy > 1
|
||||
:rtype: numpy.array
|
||||
:return: vnEz or None if nCy > 1, (dim, )
|
||||
"""
|
||||
if self.isSymmetric:
|
||||
return np.r_[self.nNx, self.nNy, self.nCz]
|
||||
@@ -330,7 +330,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
raise NotImplementedError('wrapping in the averaging is not yet implemented')
|
||||
return self._aveF2CCV
|
||||
|
||||
def getInterpolationMatCartMesh(self, Mrect, locType='CC'):
|
||||
def getInterpolationMatCartMesh(self, Mrect, locType='CC', locTypeTo=None):
|
||||
"""
|
||||
Takes a cartesian mesh and returns a projection to translate onto the cartesian grid.
|
||||
"""
|
||||
@@ -338,19 +338,22 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
assert self.isSymmetric, "Currently we have not taken into account other projections for more complicated CylMeshes"
|
||||
|
||||
|
||||
if locTypeTo is None:
|
||||
locTypeTo = locType
|
||||
|
||||
if locType == 'F':
|
||||
# do this three times for each component
|
||||
X = self.getInterpolationMatCartMesh(Mrect, locType='Fx')
|
||||
Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy')
|
||||
Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz')
|
||||
X = self.getInterpolationMatCartMesh(Mrect, locType='Fx', locTypeTo=locTypeTo+'x')
|
||||
Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy', locTypeTo=locTypeTo+'y')
|
||||
Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz', locTypeTo=locTypeTo+'z')
|
||||
return sp.vstack((X,Y,Z))
|
||||
if locType == 'E':
|
||||
X = self.getInterpolationMatCartMesh(Mrect, locType='Ex')
|
||||
Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey')
|
||||
Z = spzeros(Mrect.nEz, self.nE)
|
||||
X = self.getInterpolationMatCartMesh(Mrect, locType='Ex', locTypeTo=locTypeTo+'x')
|
||||
Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey', locTypeTo=locTypeTo+'y')
|
||||
Z = spzeros(getattr(Mrect, 'n' + locTypeTo + 'z'), self.nE)
|
||||
return sp.vstack((X,Y,Z))
|
||||
|
||||
grid = getattr(Mrect, 'grid' + locType)
|
||||
grid = getattr(Mrect, 'grid' + locTypeTo)
|
||||
# This is unit circle stuff, 0 to 2*pi, starting at x-axis, rotating counter clockwise in an x-y slice
|
||||
theta = - np.arctan2(grid[:,0] - self.cartesianOrigin[0], grid[:,1] - self.cartesianOrigin[1]) + np.pi/2
|
||||
theta[theta < 0] += np.pi*2.0
|
||||
@@ -366,7 +369,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
|
||||
'Ex': Mrect.tangents[:Mrect.nEx,:],
|
||||
'Ey': Mrect.tangents[Mrect.nEx:(Mrect.nEx+Mrect.nEy),:],
|
||||
'Ez': Mrect.tangents[-Mrect.nEz:,:],
|
||||
}[locType]
|
||||
}[locTypeTo]
|
||||
if 'F' in locType:
|
||||
normals = np.c_[np.cos(theta), np.sin(theta), np.zeros(theta.size)]
|
||||
proj = ( normals * dotMe ).sum(axis=1)
|
||||
|
||||
+109
-30
@@ -307,24 +307,28 @@ class DiffOperators(object):
|
||||
return BC
|
||||
_cellGradBC_list = 'neumann'
|
||||
|
||||
def _cellGradStencil(self):
|
||||
BC = self.setCellGradBC(self._cellGradBC_list)
|
||||
n = self.vnC
|
||||
if(self.dim == 1):
|
||||
G = ddxCellGrad(n[0], BC[0])
|
||||
elif(self.dim == 2):
|
||||
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0]))
|
||||
G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0]))
|
||||
G = sp.vstack((G1, G2), format="csr")
|
||||
elif(self.dim == 3):
|
||||
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0]))
|
||||
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0]))
|
||||
G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0]))
|
||||
G = sp.vstack((G1, G2, G3), format="csr")
|
||||
return G
|
||||
|
||||
def cellGrad():
|
||||
doc = "The cell centered Gradient, takes you to cell faces."
|
||||
|
||||
def fget(self):
|
||||
if(self._cellGrad is None):
|
||||
BC = self.setCellGradBC(self._cellGradBC_list)
|
||||
n = self.vnC
|
||||
if(self.dim == 1):
|
||||
G = ddxCellGrad(n[0], BC[0])
|
||||
elif(self.dim == 2):
|
||||
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0]))
|
||||
G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0]))
|
||||
G = sp.vstack((G1, G2), format="csr")
|
||||
elif(self.dim == 3):
|
||||
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0]))
|
||||
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0]))
|
||||
G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0]))
|
||||
G = sp.vstack((G1, G2, G3), format="csr")
|
||||
G = self._cellGradStencil()
|
||||
# Compute areas of cell faces & volumes
|
||||
S = self.area
|
||||
V = self.aveCC2F*self.vol # Average volume between adjacent cells
|
||||
@@ -361,19 +365,24 @@ class DiffOperators(object):
|
||||
_cellGradBC = None
|
||||
cellGradBC = property(**cellGradBC())
|
||||
|
||||
def _cellGradxStencil(self):
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
if(self.dim == 1):
|
||||
G1 = ddxCellGrad(n[0], BC)
|
||||
elif(self.dim == 2):
|
||||
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC))
|
||||
elif(self.dim == 3):
|
||||
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC))
|
||||
return G1
|
||||
|
||||
|
||||
def cellGradx():
|
||||
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
|
||||
|
||||
def fget(self):
|
||||
if getattr(self, '_cellGradx', None) is None:
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
if(self.dim == 1):
|
||||
G1 = ddxCellGrad(n[0], BC)
|
||||
elif(self.dim == 2):
|
||||
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC))
|
||||
elif(self.dim == 3):
|
||||
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC))
|
||||
G1 = self._cellGradxStencil()
|
||||
# Compute areas of cell faces & volumes
|
||||
V = self.aveCC2F*self.vol
|
||||
L = self.r(self.area/V, 'F','Fx', 'V')
|
||||
@@ -382,17 +391,22 @@ class DiffOperators(object):
|
||||
return locals()
|
||||
cellGradx = property(**cellGradx())
|
||||
|
||||
def _cellGradyStencil(self):
|
||||
if self.dim < 2: return None
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
if(self.dim == 2):
|
||||
G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0]))
|
||||
elif(self.dim == 3):
|
||||
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0]))
|
||||
return G2
|
||||
|
||||
def cellGrady():
|
||||
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
|
||||
def fget(self):
|
||||
if self.dim < 2: return None
|
||||
if getattr(self, '_cellGrady', None) is None:
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
if(self.dim == 2):
|
||||
G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0]))
|
||||
elif(self.dim == 3):
|
||||
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0]))
|
||||
G2 = self._cellGradyStencil()
|
||||
# Compute areas of cell faces & volumes
|
||||
V = self.aveCC2F*self.vol
|
||||
L = self.r(self.area/V, 'F','Fy', 'V')
|
||||
@@ -401,14 +415,19 @@ class DiffOperators(object):
|
||||
return locals()
|
||||
cellGrady = property(**cellGrady())
|
||||
|
||||
def _cellGradzStencil(self):
|
||||
if self.dim < 3: return None
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0]))
|
||||
return G3
|
||||
|
||||
def cellGradz():
|
||||
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
|
||||
def fget(self):
|
||||
if self.dim < 3: return None
|
||||
if getattr(self, '_cellGradz', None) is None:
|
||||
BC = ['neumann', 'neumann']
|
||||
n = self.vnC
|
||||
G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0]))
|
||||
G3 = self._cellGradzStencil()
|
||||
# Compute areas of cell faces & volumes
|
||||
V = self.aveCC2F*self.vol
|
||||
L = self.r(self.area/V, 'F','Fz', 'V')
|
||||
@@ -565,7 +584,67 @@ class DiffOperators(object):
|
||||
|
||||
return Pbc, Pin, Pout
|
||||
|
||||
def getBCProjWF_simple(self, discretization='CC'):
|
||||
"""
|
||||
|
||||
The weak form boundary condition projection matrices
|
||||
when mixed boundary condition is used
|
||||
|
||||
|
||||
"""
|
||||
|
||||
if discretization is not 'CC':
|
||||
raise NotImplementedError('Boundary conditions only implemented for CC discretization.')
|
||||
|
||||
def projBC(n):
|
||||
ij = ([0,n], [0,1])
|
||||
vals = [0,0]
|
||||
vals[0] = 1
|
||||
vals[1] = 1
|
||||
return sp.csr_matrix((vals, ij), shape=(n+1,2))
|
||||
|
||||
def projDirichlet(n, bc):
|
||||
bc = checkBC(bc)
|
||||
ij = ([0,n], [0,1])
|
||||
vals = [0,0]
|
||||
if(bc[0] == 'dirichlet'):
|
||||
vals[0] = -1
|
||||
if(bc[1] == 'dirichlet'):
|
||||
vals[1] = 1
|
||||
return sp.csr_matrix((vals, ij), shape=(n+1,2))
|
||||
|
||||
BC = [['dirichlet','dirichlet'],['dirichlet','dirichlet'],['dirichlet','dirichlet']]
|
||||
n = self.vnC
|
||||
indF = self.faceBoundaryInd
|
||||
if(self.dim == 1):
|
||||
Pbc = projDirichlet(n[0], BC[0])
|
||||
B = projBC(n[0])
|
||||
indF = indF[0] | indF[1]
|
||||
Pbc = Pbc*sdiag(self.area[indF])
|
||||
|
||||
elif(self.dim == 2):
|
||||
Pbc1 = sp.kron(speye(n[1]), projDirichlet(n[0], BC[0]))
|
||||
Pbc2 = sp.kron(projDirichlet(n[1], BC[1]), speye(n[0]))
|
||||
Pbc = sp.block_diag((Pbc1, Pbc2), format="csr")
|
||||
B1 = sp.kron(speye(n[1]), projBC(n[0]))
|
||||
B2 = sp.kron(projBC(n[1]), speye(n[0]))
|
||||
B = sp.block_diag((B1, B2), format="csr")
|
||||
indF = np.r_[(indF[0] | indF[1]), (indF[2] | indF[3])]
|
||||
Pbc = Pbc*sdiag(self.area[indF])
|
||||
|
||||
elif(self.dim == 3):
|
||||
Pbc1 = kron3(speye(n[2]), speye(n[1]), projDirichlet(n[0], BC[0]))
|
||||
Pbc2 = kron3(speye(n[2]), projDirichlet(n[1], BC[1]), speye(n[0]))
|
||||
Pbc3 = kron3(projDirichlet(n[2], BC[2]), speye(n[1]), speye(n[0]))
|
||||
Pbc = sp.block_diag((Pbc1, Pbc2, Pbc3), format="csr")
|
||||
B1 = kron3(speye(n[2]), speye(n[1]), projBC(n[0]))
|
||||
B2 = kron3(speye(n[2]), projBC(n[1]), speye(n[0]))
|
||||
B3 = kron3(projBC(n[2]), speye(n[1]), speye(n[0]))
|
||||
B = sp.block_diag((B1, B2, B3), format="csr")
|
||||
indF = np.r_[(indF[0] | indF[1]), (indF[2] | indF[3]), (indF[4] | indF[5])]
|
||||
Pbc = Pbc*sdiag(self.area[indF])
|
||||
|
||||
return Pbc, B.T
|
||||
# --------------- Averaging ---------------------
|
||||
|
||||
@property
|
||||
|
||||
@@ -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.csr_matrix
|
||||
:rtype: scipy.sparse.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.csr_matrix
|
||||
:rtype: scipy.sparse.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.csr_matrix
|
||||
:rtype: scipy.sparse.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,13 +115,12 @@ 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 np.ndarray u: vector that multiplies dMdmu
|
||||
:rtype: scipy.csr_matrix
|
||||
:param numpy.ndarray u: vector that multiplies dMdmu
|
||||
:rtype: scipy.sparse.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)
|
||||
@@ -133,7 +132,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.csr_matrix
|
||||
:rtype: scipy.sparse.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)
|
||||
@@ -145,7 +144,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.csr_matrix
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: dMdm, the derivative of the inner product matrix (nE, nC*nA)
|
||||
"""
|
||||
fast = None
|
||||
@@ -169,7 +168,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.csr_matrix
|
||||
:rtype: scipy.sparse.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"
|
||||
|
||||
+23
-37
@@ -6,13 +6,11 @@ class TensorMeshIO(object):
|
||||
@classmethod
|
||||
def readUBC(TensorMesh, fileName):
|
||||
"""
|
||||
Read UBC GIF 3DTensor mesh and generate 3D Tensor mesh in simpegTD
|
||||
Read UBC GIF 3D tensor mesh and generate 3D TensorMesh in SimPEG.
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF mesh file
|
||||
|
||||
Output:
|
||||
:param SimPEG TensorMesh object
|
||||
:param string fileName: path to the UBC GIF mesh file
|
||||
:rtype: TensorMesh
|
||||
:return: The tensor mesh for the fileName.
|
||||
"""
|
||||
|
||||
# Interal function to read cell size lines for the UBC mesh files.
|
||||
@@ -21,10 +19,9 @@ class TensorMeshIO(object):
|
||||
if '*' in seg:
|
||||
st = seg
|
||||
sp = seg.split('*')
|
||||
re = np.array(sp[0],dtype=int)*(' ' + sp[1])
|
||||
re = int(sp[0])*(' ' + sp[1])
|
||||
line = line.replace(st,re.strip())
|
||||
return np.array(line.split(),dtype=float)
|
||||
|
||||
# Read the file as line strings, remove lines with comment = !
|
||||
msh = np.genfromtxt(fileName,delimiter='\n',dtype=np.str,comments='!')
|
||||
|
||||
@@ -49,11 +46,9 @@ class TensorMeshIO(object):
|
||||
Read VTK Rectilinear (vtr xml file) and return SimPEG Tensor mesh and model
|
||||
|
||||
Input:
|
||||
:param vtrFileName, path to the vtr model file to write to
|
||||
|
||||
Output:
|
||||
:return SimPEG TensorMesh object
|
||||
:return SimPEG model dictionary
|
||||
:param string fileName: path to the vtr model file to read
|
||||
:rtype: tuple
|
||||
:return: (TensorMesh, modelDictionary)
|
||||
|
||||
"""
|
||||
# Import
|
||||
@@ -103,9 +98,8 @@ class TensorMeshIO(object):
|
||||
Makes and saves a VTK rectilinear file (vtr) for a simpeg Tensor mesh and model.
|
||||
|
||||
Input:
|
||||
:param str, path to the output vtk file
|
||||
:param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK
|
||||
:param models, dictionary of numpy.array - Name('s) and array('s). Match number of cells
|
||||
: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
|
||||
|
||||
"""
|
||||
# Import
|
||||
@@ -163,12 +157,9 @@ class TensorMeshIO(object):
|
||||
"""
|
||||
Read UBC 3DTensor mesh model and generate 3D Tensor mesh model in simpeg
|
||||
|
||||
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
|
||||
:param string fileName: path to the UBC GIF mesh file to read
|
||||
:rtype: numpy.ndarray
|
||||
:return: model with TensorMesh ordered
|
||||
"""
|
||||
f = open(fileName, 'r')
|
||||
model = np.array(map(float, f.readlines()))
|
||||
@@ -184,8 +175,7 @@ class TensorMeshIO(object):
|
||||
Writes a model associated with a SimPEG TensorMesh
|
||||
to a UBC-GIF format model file.
|
||||
|
||||
:param str fileName: File to write to
|
||||
:param simpeg.Mesh.TensorMesh mesh: The mesh
|
||||
:param string fileName: File to write to
|
||||
:param numpy.ndarray model: The model
|
||||
"""
|
||||
|
||||
@@ -202,8 +192,8 @@ class TensorMeshIO(object):
|
||||
"""
|
||||
Writes a SimPEG TensorMesh to a UBC-GIF format mesh file.
|
||||
|
||||
:param str fileName: File to write to
|
||||
:param simpeg.Mesh.TensorMesh mesh: The mesh
|
||||
:param string fileName: File to write to
|
||||
:param dict models: A dictionary of the models
|
||||
|
||||
"""
|
||||
assert mesh.dim == 3
|
||||
@@ -232,9 +222,8 @@ class TreeMeshIO(object):
|
||||
"""
|
||||
Write UBC ocTree mesh and model files from a simpeg ocTree mesh and model.
|
||||
|
||||
: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
|
||||
: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
|
||||
"""
|
||||
|
||||
# Calculate information to write in the file.
|
||||
@@ -287,10 +276,9 @@ 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
|
||||
@@ -336,11 +324,9 @@ class TreeMeshIO(object):
|
||||
"""
|
||||
Read UBC OcTree model and get vector
|
||||
|
||||
Input:
|
||||
:param fileName, path to the UBC GIF model file to read
|
||||
|
||||
Output:
|
||||
:return numpy array, OcTree model
|
||||
:param string fileName: path to the UBC GIF model file to read
|
||||
:rtype: numpy.ndarray
|
||||
:return: 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.csr_matrix
|
||||
:rtype: scipy.sparse.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.csr_matrix
|
||||
:rtype: scipy.sparse.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"
|
||||
|
||||
+10
-4
@@ -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.csr_matrix
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: M, the interpolation matrix
|
||||
|
||||
locType can be::
|
||||
@@ -2131,10 +2131,16 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO):
|
||||
def plotSlice(self, v, vType='CC',
|
||||
normal='Z', ind=None, grid=True, view='real',
|
||||
ax=None, clim=None, showIt=False,
|
||||
pcolorOpts={},
|
||||
streamOpts={'color':'k'},
|
||||
gridOpts={'color':'k', 'alpha':0.5}):
|
||||
pcolorOpts=None,
|
||||
streamOpts=None,
|
||||
gridOpts=None):
|
||||
|
||||
if pcolorOpts is None:
|
||||
pcolorOpts = {}
|
||||
if streamOpts is None:
|
||||
streamOpts = {'color':'k'}
|
||||
if gridOpts is None:
|
||||
gridOpts = {'color':'k', 'alpha':0.5}
|
||||
assert vType in ['CC','F','E']
|
||||
assert self.dim == 3
|
||||
|
||||
|
||||
+106
-50
@@ -42,9 +42,9 @@ class TensorView(object):
|
||||
|
||||
def plotImage(self, v, vType='CC', grid=False, view='real',
|
||||
ax=None, clim=None, showIt=False,
|
||||
pcolorOpts={},
|
||||
streamOpts={'color':'k'},
|
||||
gridOpts={'color':'k'},
|
||||
pcolorOpts=None,
|
||||
streamOpts=None,
|
||||
gridOpts=None,
|
||||
numbering=True, annotationColor='w'
|
||||
):
|
||||
"""
|
||||
@@ -84,6 +84,12 @@ class TensorView(object):
|
||||
M.plotImage(v, annotationColor='k', showIt=True)
|
||||
|
||||
"""
|
||||
if pcolorOpts is None:
|
||||
pcolorOpts = {}
|
||||
if streamOpts is None:
|
||||
streamOpts = {'color':'k'}
|
||||
if gridOpts is None:
|
||||
gridOpts = {'color':'k'}
|
||||
|
||||
if ax is None:
|
||||
fig = plt.figure()
|
||||
@@ -174,9 +180,9 @@ class TensorView(object):
|
||||
def plotSlice(self, v, vType='CC',
|
||||
normal='Z', ind=None, grid=False, view='real',
|
||||
ax=None, clim=None, showIt=False,
|
||||
pcolorOpts={},
|
||||
streamOpts={'color':'k'},
|
||||
gridOpts={'color':'k', 'alpha':0.5}
|
||||
pcolorOpts=None,
|
||||
streamOpts=None,
|
||||
gridOpts=None
|
||||
):
|
||||
|
||||
"""
|
||||
@@ -197,6 +203,12 @@ class TensorView(object):
|
||||
M.plotSlice(M.cellGrad*b, 'F', view='vec', grid=True, showIt=True, pcolorOpts={'alpha':0.8})
|
||||
|
||||
"""
|
||||
if pcolorOpts is None:
|
||||
pcolorOpts = {}
|
||||
if streamOpts is None:
|
||||
streamOpts = {'color':'k'}
|
||||
if gridOpts is None:
|
||||
gridOpts = {'color':'k', 'alpha':0.5}
|
||||
if type(vType) in [list, tuple]:
|
||||
assert ax is None, "cannot specify an axis to plot on with this function."
|
||||
fig, axs = plt.subplots(1,len(vType))
|
||||
@@ -206,7 +218,7 @@ class TensorView(object):
|
||||
return out
|
||||
viewOpts = ['real','imag','abs','vec']
|
||||
normalOpts = ['X', 'Y', 'Z']
|
||||
vTypeOpts = ['CC', 'CCv','F','E','Fx','Fy','Fz','E','Ex','Ey','Ez']
|
||||
vTypeOpts = ['CC', 'CCv','N','F','E','Fx','Fy','Fz','E','Ex','Ey','Ez']
|
||||
|
||||
# Some user error checking
|
||||
assert vType in vTypeOpts, "vType must be in ['%s']" % "','".join(vTypeOpts)
|
||||
@@ -289,11 +301,17 @@ class TensorView(object):
|
||||
|
||||
def _plotImage2D(self, v, vType='CC', grid=False, view='real',
|
||||
ax=None, clim=None, showIt=False,
|
||||
pcolorOpts={},
|
||||
streamOpts={'color':'k'},
|
||||
gridOpts={'color':'k'}
|
||||
pcolorOpts=None,
|
||||
streamOpts=None,
|
||||
gridOpts=None
|
||||
):
|
||||
|
||||
if pcolorOpts is None:
|
||||
pcolorOpts = {}
|
||||
if streamOpts is None:
|
||||
streamOpts = {'color':'k'}
|
||||
if gridOpts is None:
|
||||
gridOpts = {'color':'k'}
|
||||
vTypeOptsCC = ['N','CC','Fx','Fy','Ex','Ey']
|
||||
vTypeOptsV = ['CCv','F','E']
|
||||
vTypeOpts = vTypeOptsCC + vTypeOptsV
|
||||
@@ -534,7 +552,8 @@ class CurvView(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def plotGrid(self, length=0.05, showIt=False):
|
||||
|
||||
def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False):
|
||||
"""Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions.
|
||||
|
||||
|
||||
@@ -542,60 +561,63 @@ class CurvView(object):
|
||||
:include-source:
|
||||
|
||||
from SimPEG import Mesh, Utils
|
||||
X, Y = Utils.exampleCurvGird([3,3],'rotate')
|
||||
X, Y = Utils.exampleLrmGrid([3,3],'rotate')
|
||||
M = Mesh.CurvilinearMesh([X, Y])
|
||||
M.plotGrid(showIt=True)
|
||||
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
|
||||
axOpts = {'projection':'3d'} if self.dim == 3 else {}
|
||||
if ax is None: ax = plt.subplot(111, **axOpts)
|
||||
|
||||
NN = self.r(self.gridN, 'N', 'N', 'M')
|
||||
if self.dim == 2:
|
||||
fig = plt.figure(2)
|
||||
fig.clf()
|
||||
ax = plt.subplot(111)
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
|
||||
|
||||
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
|
||||
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
|
||||
if lines:
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
|
||||
|
||||
X = np.r_[X1, X2]
|
||||
Y = np.r_[Y1, Y2]
|
||||
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
|
||||
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
|
||||
|
||||
plt.plot(X, Y)
|
||||
X = np.r_[X1, X2]
|
||||
Y = np.r_[Y1, Y2]
|
||||
|
||||
plt.hold(True)
|
||||
Nx = self.r(self.normals, 'F', 'Fx', 'V')
|
||||
Ny = self.r(self.normals, 'F', 'Fy', 'V')
|
||||
Tx = self.r(self.tangents, 'E', 'Ex', 'V')
|
||||
Ty = self.r(self.tangents, 'E', 'Ey', 'V')
|
||||
ax.plot(X, Y, 'b-')
|
||||
if centers:
|
||||
ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro')
|
||||
|
||||
plt.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
|
||||
# Nx = self.r(self.normals, 'F', 'Fx', 'V')
|
||||
# Ny = self.r(self.normals, 'F', 'Fy', 'V')
|
||||
# Tx = self.r(self.tangents, 'E', 'Ex', 'V')
|
||||
# Ty = self.r(self.tangents, 'E', 'Ey', 'V')
|
||||
|
||||
nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
|
||||
nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
|
||||
plt.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
|
||||
plt.plot(nX, nY, 'r-')
|
||||
# ax.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
|
||||
|
||||
nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
|
||||
nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
|
||||
#plt.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
|
||||
plt.plot(nX, nY, 'g-')
|
||||
# nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
|
||||
# ax.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
|
||||
# ax.plot(nX, nY, 'r-')
|
||||
|
||||
tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
|
||||
tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
|
||||
plt.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
|
||||
plt.plot(tX, tY, 'r-')
|
||||
# nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
|
||||
# #ax.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
|
||||
# ax.plot(nX, nY, 'g-')
|
||||
|
||||
nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
|
||||
nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
|
||||
#plt.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
|
||||
plt.plot(nX, nY, 'g-')
|
||||
plt.axis('equal')
|
||||
# tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
|
||||
# tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
|
||||
# ax.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
|
||||
# ax.plot(tX, tY, 'r-')
|
||||
|
||||
# nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
|
||||
# nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
|
||||
# #ax.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
|
||||
# ax.plot(nX, nY, 'g-')
|
||||
|
||||
elif self.dim == 3:
|
||||
fig = plt.figure(3)
|
||||
fig.clf()
|
||||
ax = fig.add_subplot(111, projection='3d')
|
||||
X1 = np.c_[mkvc(NN[0][:-1, :, :]), mkvc(NN[0][1:, :, :]), mkvc(NN[0][:-1, :, :])*np.nan].flatten()
|
||||
Y1 = np.c_[mkvc(NN[1][:-1, :, :]), mkvc(NN[1][1:, :, :]), mkvc(NN[1][:-1, :, :])*np.nan].flatten()
|
||||
Z1 = np.c_[mkvc(NN[2][:-1, :, :]), mkvc(NN[2][1:, :, :]), mkvc(NN[2][:-1, :, :])*np.nan].flatten()
|
||||
@@ -612,16 +634,50 @@ class CurvView(object):
|
||||
Y = np.r_[Y1, Y2, Y3]
|
||||
Z = np.r_[Z1, Z2, Z3]
|
||||
|
||||
plt.plot(X, Y, 'b', zs=Z)
|
||||
ax.plot(X, Y, 'b', zs=Z)
|
||||
ax.set_zlabel('x3')
|
||||
|
||||
ax.grid(True)
|
||||
ax.hold(False)
|
||||
ax.set_xlabel('x1')
|
||||
ax.set_ylabel('x2')
|
||||
|
||||
if showIt: plt.show()
|
||||
|
||||
def plotImage(self, I, ax=None, showIt=False, grid=False, clim=None):
|
||||
if self.dim == 3: raise NotImplementedError('This is not yet done!')
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import matplotlib
|
||||
from mpl_toolkits.mplot3d import Axes3D
|
||||
import matplotlib.colors as colors
|
||||
import matplotlib.cm as cmx
|
||||
|
||||
if ax is None: ax = plt.subplot(111)
|
||||
jet = cm = plt.get_cmap('jet')
|
||||
cNorm = colors.Normalize(
|
||||
vmin=I.min() if clim is None else clim[0],
|
||||
vmax=I.max() if clim is None else clim[1])
|
||||
|
||||
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
|
||||
# ax.set_xlim((self.x0[0], self.h[0].sum()))
|
||||
# ax.set_ylim((self.x0[1], self.h[1].sum()))
|
||||
|
||||
Nx = self.r(self.gridN[:,0],'N','N','M')
|
||||
Ny = self.r(self.gridN[:,1],'N','N','M')
|
||||
cell = self.r(I,'CC','CC','M')
|
||||
|
||||
for ii in range(self.nCx):
|
||||
for jj in range(self.nCy):
|
||||
I = [ii,ii+1,ii+1,ii]
|
||||
J = [jj,jj,jj+1,jj+1]
|
||||
ax.add_patch(plt.Polygon(np.c_[Nx[I,J],Ny[I,J]], facecolor=scalarMap.to_rgba(cell[ii,jj]), edgecolor='k' if grid else 'none'))
|
||||
|
||||
scalarMap._A = [] # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots
|
||||
ax.set_xlabel('x')
|
||||
ax.set_ylabel('y')
|
||||
if showIt: plt.show()
|
||||
return [scalarMap]
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from SimPEG import *
|
||||
|
||||
+24
-6
@@ -131,7 +131,7 @@ class Minimize(object):
|
||||
|
||||
Minimizes the function (evalFunction) starting at the location x0.
|
||||
|
||||
:param def evalFunction: function handle that evaluates: f, g, H = F(x)
|
||||
:param callable 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: numpy.ndarray,bool
|
||||
:return: (xt, passLS)
|
||||
:rtype: tuple
|
||||
:return: (xt, passLS) numpy.ndarray, bool
|
||||
"""
|
||||
# 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: numpy.ndarray,bool
|
||||
:return: (xt, breakCaught)
|
||||
:rtype: tuple
|
||||
:return: (xt, breakCaught) numpy.ndarray, bool
|
||||
"""
|
||||
self.printDone(inLS=True)
|
||||
print 'The linesearch got broken. Boo.'
|
||||
@@ -888,6 +888,8 @@ class ProjectedGNCG(BFGS, Minimize, Remember):
|
||||
maxIterCG = 5
|
||||
tolCG = 1e-1
|
||||
|
||||
stepOffBoundsFact = 0.1 # perturbation of the inactive set off the bounds
|
||||
|
||||
lower = -np.inf
|
||||
upper = np.inf
|
||||
|
||||
@@ -990,4 +992,20 @@ class ProjectedGNCG(BFGS, Minimize, Remember):
|
||||
cgFlag = 1
|
||||
# End CG Iterations
|
||||
|
||||
return delx
|
||||
# Take a gradient step on the active cells if exist
|
||||
if temp != self.xc.size:
|
||||
|
||||
rhs_a = (Active) * -self.g
|
||||
|
||||
dm_i = max( abs( delx ) )
|
||||
dm_a = max( abs(rhs_a) )
|
||||
|
||||
# perturb inactive set off of bounds so that they are included in the step
|
||||
delx = delx + self.stepOffBoundsFact * (rhs_a * dm_i / dm_a)
|
||||
|
||||
|
||||
# Only keep gradients going in the right direction on the active set
|
||||
indx = ((self.xc<=self.lower) & (delx < 0)) | ((self.xc>=self.upper) & (delx > 0))
|
||||
delx[indx] = 0.
|
||||
|
||||
return delx
|
||||
+16
-16
@@ -88,28 +88,28 @@ class BaseProblem(object):
|
||||
return self.survey is not None
|
||||
|
||||
@Utils.timeIt
|
||||
def Jvec(self, m, v, u=None):
|
||||
"""Jvec(m, v, u=None)
|
||||
def Jvec(self, m, v, f=None):
|
||||
"""Jvec(m, v, f=None)
|
||||
|
||||
Effect of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: Jv
|
||||
"""
|
||||
raise NotImplementedError('J is not yet implemented.')
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec(self, m, v, u=None):
|
||||
"""Jtvec(m, v, u=None)
|
||||
def Jtvec(self, m, v, f=None):
|
||||
"""Jtvec(m, v, f=None)
|
||||
|
||||
Effect of transpose of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: JTv
|
||||
"""
|
||||
@@ -117,32 +117,32 @@ class BaseProblem(object):
|
||||
|
||||
|
||||
@Utils.timeIt
|
||||
def Jvec_approx(self, m, v, u=None):
|
||||
"""Jvec_approx(m, v, u=None)
|
||||
def Jvec_approx(self, m, v, f=None):
|
||||
"""Jvec_approx(m, v, f=None)
|
||||
|
||||
Approximate effect of J(m) on a vector v
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: approxJv
|
||||
"""
|
||||
return self.Jvec(m, v, u)
|
||||
return self.Jvec(m, v, f)
|
||||
|
||||
@Utils.timeIt
|
||||
def Jtvec_approx(self, m, v, u=None):
|
||||
"""Jtvec_approx(m, v, u=None)
|
||||
def Jtvec_approx(self, m, v, f=None):
|
||||
"""Jtvec_approx(m, v, f=None)
|
||||
|
||||
Approximate effect of transpose of J(m) on a vector v.
|
||||
|
||||
:param numpy.array m: model
|
||||
:param numpy.array v: vector to multiply
|
||||
:param numpy.array u: fields
|
||||
:param Fields f: fields
|
||||
:rtype: numpy.array
|
||||
:return: JTv
|
||||
"""
|
||||
return self.Jtvec(m, v, u)
|
||||
return self.Jtvec(m, v, f)
|
||||
|
||||
def fields(self, m):
|
||||
"""
|
||||
@@ -224,9 +224,9 @@ class LinearProblem(BaseProblem):
|
||||
def fields(self, m):
|
||||
return self.G.dot(m)
|
||||
|
||||
def Jvec(self, m, v, u=None):
|
||||
def Jvec(self, m, v, f=None):
|
||||
return self.G.dot(v)
|
||||
|
||||
def Jtvec(self, m, v, u=None):
|
||||
def Jtvec(self, m, v, f=None):
|
||||
return self.G.T.dot(v)
|
||||
|
||||
|
||||
+3
-3
@@ -74,7 +74,7 @@ class Property(object):
|
||||
if linkedMap is None:
|
||||
return None
|
||||
linkMap = linkMapClass(None) * linkedMap
|
||||
m = getattr(self, '%s'%linkName)
|
||||
m = getattr(self, '%sModel'%linkName)
|
||||
return linkMap.deriv( m )
|
||||
|
||||
m = getattr(self, '%sModel'%prop.name)
|
||||
@@ -187,7 +187,7 @@ class _PropMapMetaClass(type):
|
||||
attrs[attr + 'Model'] = prop._getModelProperty()
|
||||
attrs[attr + 'Deriv'] = prop._getModelDerivProperty()
|
||||
|
||||
return type(name.replace('PropMap', 'PropModel'), (PropModel, ), attrs)
|
||||
return type('PropModel', (PropModel, ), attrs)
|
||||
|
||||
|
||||
class PropMap(object):
|
||||
@@ -239,7 +239,7 @@ class PropMap(object):
|
||||
setattr(self, '%sMap'%name, mapping)
|
||||
setattr(self, '%sIndex'%name, slices.get(name, slice(nP, nP + mapping.nP)))
|
||||
nP += mapping.nP
|
||||
self.nP = nP
|
||||
self.nP = nP
|
||||
|
||||
@property
|
||||
def defaultInvProp(self):
|
||||
|
||||
+797
-319
File diff suppressed because it is too large
Load Diff
+22
-23
@@ -295,38 +295,37 @@ class BaseSurvey(object):
|
||||
|
||||
@Utils.count
|
||||
@Utils.requires('prob')
|
||||
def dpred(self, m, u=None):
|
||||
"""dpred(m, u=None)
|
||||
def dpred(self, m, f=None):
|
||||
"""dpred(m, f=None)
|
||||
|
||||
Create the projected data from a model.
|
||||
The field, u, (if provided) will be used for the predicted data
|
||||
The fields, f, (if provided) will be used for the predicted data
|
||||
instead of recalculating the fields (which may be expensive!).
|
||||
|
||||
.. math::
|
||||
|
||||
d_\\text{pred} = P(u(m))
|
||||
d_\\text{pred} = P(f(m))
|
||||
|
||||
Where P is a projection of the fields onto the data space.
|
||||
"""
|
||||
if u is None: u = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(u))
|
||||
|
||||
if f is None: f = self.prob.fields(m)
|
||||
return Utils.mkvc(self.eval(f))
|
||||
|
||||
@Utils.count
|
||||
def eval(self, u):
|
||||
"""eval(u)
|
||||
def eval(self, f):
|
||||
"""eval(f)
|
||||
|
||||
This function projects the fields onto the data space.
|
||||
|
||||
.. math::
|
||||
|
||||
d_\\text{pred} = \mathbf{P} u(m)
|
||||
d_\\text{pred} = \mathbf{P} f(m)
|
||||
"""
|
||||
raise NotImplemented('eval is not yet implemented.')
|
||||
raise NotImplementedError('eval is not yet implemented.')
|
||||
|
||||
@Utils.count
|
||||
def evalDeriv(self, u):
|
||||
"""evalDeriv(u)
|
||||
def evalDeriv(self, f):
|
||||
"""evalDeriv(f)
|
||||
|
||||
This function s the derivative of projects the fields onto the data space.
|
||||
|
||||
@@ -334,14 +333,14 @@ class BaseSurvey(object):
|
||||
|
||||
\\frac{\partial d_\\text{pred}}{\partial u} = \mathbf{P}
|
||||
"""
|
||||
raise NotImplemented('eval is not yet implemented.')
|
||||
raise NotImplementedError('eval is not yet implemented.')
|
||||
|
||||
@Utils.count
|
||||
def residual(self, m, u=None):
|
||||
"""residual(m, u=None)
|
||||
def residual(self, m, f=None):
|
||||
"""residual(m, f=None)
|
||||
|
||||
:param numpy.array m: geophysical model
|
||||
:param numpy.array u: fields
|
||||
:param numpy.array f: fields
|
||||
:rtype: numpy.array
|
||||
:return: data residual
|
||||
|
||||
@@ -352,14 +351,14 @@ class BaseSurvey(object):
|
||||
\mu_\\text{data} = \mathbf{d}_\\text{pred} - \mathbf{d}_\\text{obs}
|
||||
|
||||
"""
|
||||
return Utils.mkvc(self.dpred(m, u=u) - self.dobs)
|
||||
return Utils.mkvc(self.dpred(m, f=f) - self.dobs)
|
||||
|
||||
@property
|
||||
def isSynthetic(self):
|
||||
"Check if the data is synthetic."
|
||||
return self.mtrue is not None
|
||||
|
||||
def makeSyntheticData(self, m, std=0.05, u=None, force=False):
|
||||
def makeSyntheticData(self, m, std=0.05, f=None, force=False):
|
||||
"""
|
||||
Make synthetic data given a model, and a standard deviation.
|
||||
|
||||
@@ -372,16 +371,16 @@ class BaseSurvey(object):
|
||||
if getattr(self, 'dobs', None) is not None and not force:
|
||||
raise Exception('Survey already has dobs. You can use force=True to override this exception.')
|
||||
self.mtrue = m
|
||||
self.dtrue = self.dpred(m, u=u)
|
||||
self.dtrue = self.dpred(m, f=f)
|
||||
noise = std*abs(self.dtrue)*np.random.randn(*self.dtrue.shape)
|
||||
self.dobs = self.dtrue+noise
|
||||
self.std = self.dobs*0 + std
|
||||
return self.dobs
|
||||
|
||||
class LinearSurvey(BaseSurvey):
|
||||
def eval(self, u):
|
||||
return u
|
||||
|
||||
def eval(self, f):
|
||||
return f
|
||||
|
||||
@property
|
||||
def nD(self):
|
||||
return self.prob.G.shape[0]
|
||||
|
||||
+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 lambda fctn: function handle
|
||||
:param callable 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
|
||||
"""
|
||||
@@ -88,12 +88,14 @@ def getIndicesBlock(p0,p1,ccMesh):
|
||||
# Return a tuple
|
||||
return ind
|
||||
|
||||
def defineBlock(ccMesh,p0,p1,vals=[0,1]):
|
||||
def defineBlock(ccMesh,p0,p1,vals=None):
|
||||
"""
|
||||
Build a block with the conductivity specified by condVal. Returns an array.
|
||||
vals[0] conductivity of the block
|
||||
vals[1] conductivity of the ground
|
||||
"""
|
||||
if vals is None:
|
||||
vals = [0,1]
|
||||
sigma = np.zeros(ccMesh.shape[0]) + vals[1]
|
||||
ind = getIndicesBlock(p0,p1,ccMesh)
|
||||
|
||||
@@ -101,7 +103,11 @@ def defineBlock(ccMesh,p0,p1,vals=[0,1]):
|
||||
|
||||
return mkvc(sigma)
|
||||
|
||||
def defineElipse(ccMesh, center=[0,0,0], anisotropy=[1,1,1], slope=10., theta=0.):
|
||||
def defineElipse(ccMesh, center=None, anisotropy=None, slope=10., theta=0.):
|
||||
if center is None:
|
||||
center = [0,0,0]
|
||||
if anisotropy is None:
|
||||
anisotropy = [1,1,1]
|
||||
G = ccMesh.copy()
|
||||
dim = ccMesh.shape[1]
|
||||
for i in range(dim):
|
||||
@@ -141,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:
|
||||
@@ -156,7 +162,7 @@ def getIndicesSphere(center,radius,ccMesh):
|
||||
# Return a tuple
|
||||
return ind
|
||||
|
||||
def defineTwoLayers(ccMesh,depth,vals=[0,1]):
|
||||
def defineTwoLayers(ccMesh,depth,vals=None):
|
||||
"""
|
||||
Define a two layered model. Depth of the first layer must be specified.
|
||||
CondVals vector with the conductivity values of the layers. Eg:
|
||||
@@ -167,6 +173,8 @@ def defineTwoLayers(ccMesh,depth,vals=[0,1]):
|
||||
0 depth zf
|
||||
1st layer 2nd layer
|
||||
"""
|
||||
if vals is None:
|
||||
vals = [0,1]
|
||||
sigma = np.zeros(ccMesh.shape[0]) + vals[1]
|
||||
|
||||
dim = np.size(ccMesh[0,:])
|
||||
@@ -214,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
|
||||
@@ -245,21 +253,21 @@ 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
|
||||
|
||||
|
||||
|
||||
def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]):
|
||||
def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=None):
|
||||
"""
|
||||
Create a random model by convolving a kernel with a
|
||||
uniformly distributed model.
|
||||
|
||||
:param int,tuple shape: shape of the model.
|
||||
:param 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,list anisotropy: this is the (3 x n) blurring kernel that is used.
|
||||
:param numpy.ndarray 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
|
||||
@@ -276,6 +284,8 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]):
|
||||
|
||||
|
||||
"""
|
||||
if bounds is None:
|
||||
bounds = [0,1]
|
||||
|
||||
if seed is None:
|
||||
seed = np.random.randint(1e3)
|
||||
|
||||
@@ -13,7 +13,7 @@ def _checkAccuracy(A, b, X, accuracyTol):
|
||||
warnings.warn(msg, RuntimeWarning)
|
||||
|
||||
|
||||
def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6):
|
||||
def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6, name=None):
|
||||
"""
|
||||
Wraps a direct Solver.
|
||||
|
||||
@@ -72,11 +72,11 @@ def SolverWrapD(fun, factorize=True, checkAccuracy=True, accuracyTol=1e-6):
|
||||
if factorize and hasattr(self.solver, 'clean'):
|
||||
return self.solver.clean()
|
||||
|
||||
return type(fun.__name__+'_Wrapped', (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__})
|
||||
return type(name if name is not None else fun.__name__, (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__})
|
||||
|
||||
|
||||
|
||||
def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5):
|
||||
def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5, name=None):
|
||||
"""
|
||||
Wraps an iterative Solver.
|
||||
|
||||
@@ -128,13 +128,13 @@ def SolverWrapI(fun, checkAccuracy=True, accuracyTol=1e-5):
|
||||
def clean(self):
|
||||
pass
|
||||
|
||||
return type(fun.__name__+'_Wrapped', (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__})
|
||||
return type(name if name is not None else fun.__name__, (object,), {"__init__": __init__, "clean": clean, "__mul__": __mul__})
|
||||
|
||||
|
||||
from scipy.sparse import linalg
|
||||
Solver = SolverWrapD(linalg.spsolve, factorize=False)
|
||||
SolverLU = SolverWrapD(linalg.splu, factorize=True)
|
||||
SolverCG = SolverWrapI(linalg.cg)
|
||||
Solver = SolverWrapD(linalg.spsolve, factorize=False, name="Solver")
|
||||
SolverLU = SolverWrapD(linalg.splu, factorize=True, name="SolverLU")
|
||||
SolverCG = SolverWrapI(linalg.cg, name="SolverCG")
|
||||
|
||||
|
||||
class SolverDiag(object):
|
||||
|
||||
@@ -7,3 +7,4 @@ from CounterUtils import *
|
||||
import ModelBuilder
|
||||
import SolverUtils
|
||||
from coordutils import *
|
||||
from modelutils import *
|
||||
|
||||
@@ -55,8 +55,10 @@ def hook(obj, method, name=None, overwrite=False, silent=False):
|
||||
print 'Method '+name+' was not overwritten.'
|
||||
|
||||
|
||||
def setKwargs(obj, ignore=[], **kwargs):
|
||||
def setKwargs(obj, ignore=None, **kwargs):
|
||||
"""Sets key word arguments (kwargs) that are present in the object, throw an error if they don't exist."""
|
||||
if ignore is None:
|
||||
ignore = []
|
||||
for attr in kwargs:
|
||||
if attr in ignore:
|
||||
continue
|
||||
|
||||
@@ -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.csr_matrix
|
||||
:rtype: scipy.sparse.csr_matrix
|
||||
:return: Interpolation matrix
|
||||
|
||||
.. plot::
|
||||
|
||||
@@ -0,0 +1,137 @@
|
||||
from SimPEG import np, Mesh
|
||||
import time as tm
|
||||
import vtk, vtk.util.numpy_support as npsup
|
||||
import re
|
||||
|
||||
def read_GOCAD_ts(tsfile):
|
||||
"""
|
||||
|
||||
Read GOCAD triangulated surface (*.ts) file
|
||||
INPUT:
|
||||
tsfile: Triangulated surface
|
||||
|
||||
OUTPUT:
|
||||
vrts : Array of vertices in XYZ coordinates [n x 3]
|
||||
trgl : Array of index for triangles [m x 3]. The order of the vertices
|
||||
is important and describes the normal
|
||||
n = cross( (P2 - P1 ) , (P3 - P1) )
|
||||
|
||||
Author: @fourndo
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
Remove all attributes from the GoCAD surface before exporting it!
|
||||
|
||||
"""
|
||||
|
||||
|
||||
fid = open(tsfile,'r')
|
||||
line = fid.readline()
|
||||
|
||||
# Skip all the lines until the vertices
|
||||
while re.match('TFACE',line)==None:
|
||||
line = fid.readline()
|
||||
|
||||
line = fid.readline()
|
||||
vrtx = []
|
||||
|
||||
# Run down all the vertices and save in array
|
||||
while re.match('VRTX',line):
|
||||
l_input = re.split('[\s*]',line)
|
||||
temp = np.array(l_input[2:5])
|
||||
vrtx.append(temp.astype(np.float))
|
||||
|
||||
# Read next line
|
||||
line = fid.readline()
|
||||
|
||||
vrtx = np.asarray(vrtx)
|
||||
|
||||
# Skip lines to the triangles
|
||||
while re.match('TRGL',line)==None:
|
||||
line = fid.readline()
|
||||
|
||||
# Run down the list of triangles
|
||||
trgl = []
|
||||
|
||||
# Run down all the vertices and save in array
|
||||
while re.match('TRGL',line):
|
||||
l_input = re.split('[\s*]',line)
|
||||
temp = np.array(l_input[1:4])
|
||||
trgl.append(temp.astype(np.int))
|
||||
|
||||
# Read next line
|
||||
line = fid.readline()
|
||||
|
||||
trgl = np.asarray(trgl)
|
||||
|
||||
return vrtx, trgl
|
||||
|
||||
def surface2inds(vrtx, trgl, mesh, boundaries=True, internal=True):
|
||||
""""
|
||||
Function to read gocad polystructure file and output indexes of mesh with in the structure.
|
||||
|
||||
"""
|
||||
# Adjust the index
|
||||
trgl = trgl - 1
|
||||
|
||||
# Make vtk pts
|
||||
ptsvtk = vtk.vtkPoints()
|
||||
ptsvtk.SetData(npsup.numpy_to_vtk(vrtx,deep=1))
|
||||
|
||||
# Make the polygon connection
|
||||
polys = vtk.vtkCellArray()
|
||||
for face in trgl:
|
||||
poly = vtk.vtkPolygon()
|
||||
poly.GetPointIds().SetNumberOfIds(len(face))
|
||||
for nrv, vert in enumerate(face):
|
||||
poly.GetPointIds().SetId(nrv,vert)
|
||||
polys.InsertNextCell(poly)
|
||||
|
||||
# Make the polydata, structure of connections and vrtx
|
||||
polyData = vtk.vtkPolyData()
|
||||
polyData.SetPoints(ptsvtk)
|
||||
polyData.SetPolys(polys)
|
||||
|
||||
# Make implicit func
|
||||
ImpDistFunc = vtk.vtkImplicitPolyDataDistance()
|
||||
ImpDistFunc.SetInput(polyData)
|
||||
|
||||
# Convert the mesh
|
||||
vtkMesh = vtk.vtkRectilinearGrid()
|
||||
vtkMesh.SetDimensions(mesh.nNx,mesh.nNy,mesh.nNz)
|
||||
vtkMesh.SetXCoordinates(npsup.numpy_to_vtk(mesh.vectorNx, deep=1))
|
||||
vtkMesh.SetYCoordinates(npsup.numpy_to_vtk(mesh.vectorNy, deep=1))
|
||||
vtkMesh.SetZCoordinates(npsup.numpy_to_vtk(mesh.vectorNz, deep=1))
|
||||
# Add indexes
|
||||
vtkInd = npsup.numpy_to_vtk(np.arange(mesh.nC), deep=1)
|
||||
vtkInd.SetName('Index')
|
||||
vtkMesh.GetCellData().AddArray(vtkInd)
|
||||
|
||||
extractImpDistRectGridFilt = vtk.vtkExtractGeometry() # Object constructor
|
||||
extractImpDistRectGridFilt.SetImplicitFunction(ImpDistFunc) #
|
||||
extractImpDistRectGridFilt.SetInputData(vtkMesh)
|
||||
|
||||
if boundaries is True:
|
||||
extractImpDistRectGridFilt.ExtractBoundaryCellsOn()
|
||||
|
||||
else:
|
||||
extractImpDistRectGridFilt.ExtractBoundaryCellsOff()
|
||||
|
||||
if internal is True:
|
||||
extractImpDistRectGridFilt.ExtractInsideOn()
|
||||
|
||||
else:
|
||||
extractImpDistRectGridFilt.ExtractInsideOff()
|
||||
|
||||
print "Extracting indices from grid..."
|
||||
# Executing the pipe
|
||||
extractImpDistRectGridFilt.Update()
|
||||
|
||||
# Get index inside
|
||||
insideGrid = extractImpDistRectGridFilt.GetOutput()
|
||||
insideGrid = npsup.vtk_to_numpy(insideGrid.GetCellData().GetArray('Index'))
|
||||
|
||||
|
||||
# Return the indexes inside
|
||||
return insideGrid
|
||||
@@ -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 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 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 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()
|
||||
|
||||
|
||||
+18
-14
@@ -83,7 +83,7 @@ def closestPoints(mesh, pts, gridLoc='CC'):
|
||||
"""
|
||||
Move a list of points to the closest points on a grid.
|
||||
|
||||
:param simpeg.Mesh.BaseMesh mesh: The mesh
|
||||
:param 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,16 +104,20 @@ def closestPoints(mesh, pts, gridLoc='CC'):
|
||||
|
||||
def ExtractCoreMesh(xyzlim, mesh, meshType='tensor'):
|
||||
"""
|
||||
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
|
||||
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
|
||||
"""
|
||||
from SimPEG import Mesh
|
||||
if mesh.dim ==1:
|
||||
if mesh.dim == 1:
|
||||
xyzlim = xyzlim.flatten()
|
||||
xmin, xmax = xyzlim[0], xyzlim[1]
|
||||
|
||||
@@ -125,11 +129,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]
|
||||
|
||||
@@ -144,12 +148,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]
|
||||
@@ -168,7 +172,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) \
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
from matutils import mkvc, ndgrid
|
||||
import numpy as np
|
||||
|
||||
def surface2ind_topo(mesh, topo, gridLoc='CC'):
|
||||
# def genActiveindfromTopo(mesh, topo):
|
||||
"""
|
||||
Get active indices from topography
|
||||
"""
|
||||
|
||||
|
||||
if mesh.dim == 3:
|
||||
from scipy.interpolate import NearestNDInterpolator
|
||||
Ftopo = NearestNDInterpolator(topo[:,:2], topo[:,2])
|
||||
|
||||
if gridLoc == 'CC':
|
||||
XY = ndgrid(mesh.vectorCCx, mesh.vectorCCy)
|
||||
Zcc = mesh.gridCC[:,2].reshape((np.prod(mesh.vnC[:2]), mesh.nCz), order='F')
|
||||
|
||||
gridTopo = Ftopo(XY)
|
||||
actind = [gridTopo[ixy] <= Zcc[ixy,:] for ixy in range(np.prod(mesh.vnC[0]))]
|
||||
actind = np.hstack(actind)
|
||||
|
||||
elif gridLoc == 'N':
|
||||
|
||||
XY = ndgrid(mesh.vectorNx, mesh.vectorNy)
|
||||
gridTopo = Ftopo(XY).reshape(mesh.vnN[:2], order='F')
|
||||
|
||||
if mesh._meshType not in ['TENSOR', 'CYL', 'BASETENSOR']:
|
||||
raise NotImplementedError('Nodal surface2ind_topo not implemented for %s mesh'%mesh._meshType)
|
||||
|
||||
Nz = mesh.vectorNz[1:] # TODO: this will only work for tensor meshes
|
||||
actind = np.array([False]*mesh.nC).reshape(mesh.vnC, order='F')
|
||||
|
||||
for ii in range(mesh.nCx):
|
||||
for jj in range(mesh.nCy):
|
||||
actind[ii,jj,:] = [np.all(gridTopo[ii:ii+2, jj:jj+2] >= Nz[kk]) for kk in range(len(Nz)) ]
|
||||
|
||||
elif mesh.dim == 2:
|
||||
from scipy.interpolate import interp1d
|
||||
Ftopo = interp1d(topo[:,0], topo[:,1])
|
||||
|
||||
if gridLoc == 'CC':
|
||||
gridTopo = Ftopo(mesh.gridCC[:,0])
|
||||
actind = mesh.gridCC[:,1] <= gridTopo
|
||||
|
||||
elif gridLoc == 'N':
|
||||
|
||||
gridTopo = Ftopo(mesh.vectorNx)
|
||||
if mesh._meshType not in ['TENSOR', 'CYL', 'BASETENSOR']:
|
||||
raise NotImplementedError('Nodal surface2ind_topo not implemented for %s mesh'%mesh._meshType)
|
||||
|
||||
Ny = mesh.vectorNy[1:] # TODO: this will only work for tensor meshes
|
||||
actind = np.array([False]*mesh.nC).reshape(mesh.vnC, order='F')
|
||||
|
||||
for ii in range(mesh.nCx):
|
||||
actind[ii,:] = [np.all(gridTopo[ii:ii+2] > Ny[kk]) for kk in range(len(Ny)) ]
|
||||
|
||||
else:
|
||||
raise NotImplementedError('surface2ind_topo not implemented for 1D mesh')
|
||||
|
||||
return mkvc(actind)
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ import Directives
|
||||
import Inversion
|
||||
import Tests
|
||||
|
||||
__version__ = '0.1.10'
|
||||
__version__ = '0.1.12'
|
||||
__author__ = 'Rowan Cockett'
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright 2014 Rowan Cockett'
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXOPTS = -n -w warnings.txt
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
Vendored
+22
@@ -0,0 +1,22 @@
|
||||
{# 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,19 +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,36 +0,0 @@
|
||||
.. _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:
|
||||
@@ -0,0 +1,95 @@
|
||||
# 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"
|
||||
+45
-6
@@ -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', 'matplotlib.sphinxext.plot_directive']
|
||||
extensions = ['sphinx.ext.todo', 'sphinx.ext.mathjax', 'sphinx.ext.viewcode', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx', '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, SimPEG Developers'
|
||||
copyright = u'2013 - 2016, 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.10'
|
||||
version = '0.1.12'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1.10'
|
||||
release = '0.1.12'
|
||||
|
||||
# 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 = None
|
||||
html_favicon = './images/logo-block.ico'
|
||||
|
||||
# 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 = ['_static']
|
||||
html_static_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
@@ -229,6 +229,12 @@ 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 ------------------------------------------------
|
||||
|
||||
@@ -251,3 +257,36 @@ 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'),
|
||||
]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user