Compare commits

..
232 Commits
Author SHA1 Message Date
Lindsey Heagy 8f1df12252 copy docs badges from readme to docs index 2016-07-21 22:30:49 -07:00
Lindsey Heagy 002554209b listing and remove wildcard inputs from tes_Mixed_boundaryPoisson 2016-07-21 22:28:20 -07:00
Lindsey Heagy 76f140f89b pep8 linting 2016-07-21 21:58:42 -07:00
Lindsey Heagy 5ce26a97ae remove wildcard imports from test_Fields 2016-07-21 21:39:11 -07:00
Lindsey Heagy a087c6e5b1 fix broken link 2016-07-21 21:34:17 -07:00
Lindsey Heagy 44ec0623d6 fixed formatting changes from quantified code, test links in docs 2016-07-21 14:38:05 -07:00
Lindsey Heagy 57d0c84b41 use @property for nodal and cell centered curvi grids 2016-07-21 13:19:23 -07:00
Lindsey Heagy a7befd6783 fix typo in cell grad 2016-07-21 12:38:21 -07:00
Lindsey Heagy 7acf46ddb8 fix typo in faceDivz 2016-07-21 12:32:49 -07:00
Lindsey Heagy b54d2494f5 add codacy to readme 2016-07-21 12:20:58 -07:00
Cody 45f5906554 Migrated % string formating 2016-07-21 12:08:19 -07:00
Lindsey Heagy 8093288391 fix double negative 2016-07-21 11:59:59 -07:00
Lindsey Heagy 7457912d84 avoid double import of numpy 2016-07-21 11:58:52 -07:00
Lindsey Heagy 910d4214b3 remove extra import of unittest 2016-07-21 11:56:49 -07:00
Lindsey Heagy 20e80ed983 use @property decorator in DiffOperators.py 2016-07-21 11:55:14 -07:00
Lindsey Heagy 3e8580f28d update readme 2016-07-21 09:59:43 -07:00
Lindsey Heagy 3ad2c98d43 use @property decorator in curve mesh (see: https://www.quantifiedcode.com/app/project/933aa3decf444538aa432c8817169b6d?groups=code_patterns%3A3bECxdfc%3Af0&tab=basics) 2016-07-21 09:58:14 -07:00
Lindsey Heagy cf34415ae8 Merge pull request #358 from simpeg/feat/codecov
Feat/codecov
2016-07-14 08:51:57 -06:00
Lindsey Heagy 09ec5621ae remove coveralls 2016-07-13 19:46:27 -07:00
Lindsey Heagy 4e583fc566 fix indentation level 2016-07-13 13:40:38 -07:00
Lindsey Heagy ea62998250 use codecov.io 2016-07-13 12:15:15 -07:00
SEOGI KANG 4796b0f91f Merge pull request #357 from simpeg/analytics
Analytics
2016-06-30 00:25:28 -07:00
seogi_macbook 52b25e2dc5 Merge branch 'dev' of https://github.com/simpeg/simpeg into analytics 2016-06-30 00:23:12 -07:00
seogi_macbook a289b656cd Fixes for kwargs variables in FDEMDipolarfields.py 2016-06-29 13:09:11 -07:00
Lindsey Heagy 334cd8e454 Bump version: 0.1.11 → 0.1.12 2016-06-29 09:49:29 -07:00
Lindsey Heagy ecbdd90f63 Merge pull request #354 from simpeg/dev
Two new examples.
2016-06-29 09:46:33 -07:00
dfournier 394dc9106a Merge pull request #332 from simpeg/ref/regularization
Automate the epsilon picking based on percentile of model values for …
2016-06-29 08:39:29 -07:00
seogi_macbook eda2394411 fix bug for omega. 2016-06-27 13:04:30 -07:00
Rowan Cockett 3deca9ed77 Merge pull request #351 from simpeg/example/mesh2mesh
Mesh2Mesh and Combo Map examples.
2016-06-26 21:22:28 -06:00
Rowan Cockett ba173674ec Mesh2Mesh and Combo Map examples.
Also fixed plotting codes to show the plots by default.
2016-06-26 17:07:07 -06:00
Rowan Cockett 303da372aa Merged branch master into dev 2016-06-26 16:31:24 -06:00
Rowan Cockett 6d6e7fc8bd Merge pull request #350 from simpeg/fix/docs-images
Update index.rst
2016-06-26 16:30:29 -06:00
Rowan Cockett 8ed3ec18fa Update README.rst 2016-06-26 16:29:20 -06:00
Rowan Cockett 3960cfc313 Update index.rst 2016-06-26 16:17:30 -06:00
Rowan Cockett 2eba0b841f Merge pull request #338 from simpeg/dev
Dev
2016-06-26 14:01:03 -06:00
sgkang c79bb998cb Merge pull request #348 from simpeg/analytics
fix minor bugs in analytics (just for binder deploy)
2016-06-23 14:14:29 -07:00
seogi_macbook 0763925743 fix minor bugs in analytics 2016-06-23 14:12:49 -07:00
sgkang 1a0b81a206 Merge pull request #341 from simpeg/analytics
Analytics
2016-06-23 11:33:33 -07:00
seogi_macbook 8b44f8d96b change FDEM_fields.py to FDEMDipolarfield.py 2016-06-23 10:14:13 -07:00
seogi_macbook 2bfd01ed7c Merge branch 'dev' of https://github.com/simpeg/simpeg into analytics 2016-06-23 10:09:56 -07:00
seogi_macbook e1ba80883d Incorporate Lindsey's suggestoins 2016-06-23 09:10:50 -07:00
Rowan Cockett a54713f546 Change to NotImplementedError. 2016-06-22 11:32:54 -06:00
Lindsey Heagy ef382aed85 Merge branch 'master' into dev 2016-06-21 18:43:28 -06:00
seogi_macbook 1b33804e5a Merge branch 'dev' of https://github.com/simpeg/simpeg into analytics 2016-06-21 11:15:23 -07:00
seogi_macbook c161c5eab2 Merge branch 'master' of https://github.com/simpeg/simpeg into analytics 2016-06-21 11:14:56 -07:00
micmitch f0944362c8 Silly mistake... needed zero arrays instead of scalars. 2016-06-14 15:22:36 -07:00
micmitch e815ddaec7 Removed d typos from the end of function names. 2016-06-14 15:15:53 -07:00
Lindsey 64b0b4561f Merge pull request #337 from simpeg/feat/docs-gae-travis-deploy
Feat/docs gae travis deploy
2016-06-13 19:16:22 -06:00
micmitch b9d30af4a8 Changed \sigma to \hat{\sigma} = \sigma + i \omega \epsilon in the E field calculations. 2016-06-13 17:47:46 -07:00
micmitch 093f441331 Added functions to split electric field into "galvanic" and "inductive" portions. 2016-06-13 17:35:52 -07:00
seogi_macbook 5e3c1da8e2 add place holder for galvanic and inductive electric fields... 2016-06-13 16:41:59 -07:00
seogi_macbook a3a5c86008 Fix couple bugs in FDEM analytics 2016-06-11 21:58:03 +02:00
Lindsey Heagy 7a82f57367 - doc the simple regularization, sparse regularization and regularization mesh
- typo fix in MT_3D_Forward example - Solver
- use EM.Static.DC for DC example
2016-06-11 08:16:22 -07:00
Lindsey Heagy 845c3c10ab version on travis commit 2016-06-11 07:48:24 -07:00
Lindsey Heagy c4d86b4a29 Merge branch 'dev' into feat/docs-gae-travis-deploy 2016-06-11 07:14:00 -07:00
Lindsey Heagy 3fc855f3c9 only push on master 2016-06-10 20:50:41 -07:00
Lindsey Heagy fea508a507 fix path to app.yaml 2016-06-10 19:39:02 -07:00
Lindsey Heagy 5ca52cf49f linting travis deploy of docs 2016-06-10 19:14:24 -07:00
Lindsey Heagy 7a06453c42 editing travis deploy 2016-06-10 18:54:31 -07:00
Lindsey Heagy 291da78b97 try deploying only from docs branch 2016-06-10 15:16:56 -07:00
D Fournier ef12a3674a Automate the epsilon picking based on percentile of model values for DEFAULT mode. Fix example.
Fix bug with Maps using array of values
2016-06-06 12:28:01 -07:00
Lindsey Heagy 504592c8de travis typo fixes 2016-06-01 08:12:21 -07:00
Lindsey Heagy 75647f8fc3 first pass at gae deploy 2016-06-01 00:00:27 -07:00
Lindsey Heagy e3462666bd working on travis decrypt 2016-05-31 23:27:32 -07:00
Lindsey Heagy fb37bf0fe2 move unpacking of credentials to after success, point credentials to docs folder 2016-05-31 23:15:50 -07:00
Lindsey Heagy b023adbb33 add encrypted credentials for gae site and decrypt on travis 2016-05-31 23:03:55 -07:00
Lindsey Heagy 279bd49b4c Bump version: 0.1.10 → 0.1.11 2016-05-31 15:38:05 -07:00
Lindsey Heagy 3398d5ab4d use templates in conf.py, add google analytics to docs 2016-05-31 15:33:19 -07:00
Lindsey 3e26bb7de9 Merge pull request #277 from simpeg/dev
Dev
2016-05-31 15:11:29 -07:00
Lindsey 382b31bd12 Merge pull request #310 from simpeg/ref/regularization
modularizing regularization
2016-05-31 14:09:54 -07:00
Lindsey Heagy 01e19e4227 start of gae site 2016-05-30 22:01:15 -07:00
Lindsey Heagy 9fbdaaf0a5 fix typo in examples path 2016-05-30 21:12:31 -07:00
Lindsey Heagy 2a159e20b9 update docs for examples to point to the correct path 2016-05-30 20:34:10 -07:00
Lindsey Heagy 5e8d3fbc78 organizing the docs - put the content in a content folder. put the SimPEG core api docs in core_api 2016-05-30 17:06:29 -07:00
Lindsey Heagy 414418a996 Merge branch 'dev' into feat/docs-deploy
# Conflicts:
#	SimPEG/Mesh/View.py
2016-05-30 15:56:24 -07:00
Lindsey 6cc509020a Merge pull request #323 from simpeg/feat/plotImage-curvilinear
plotImage for curvilinear mesh
2016-05-30 08:27:56 -07:00
Rowan Cockett 40f0874dfb Doc testing, I think that is most of them! 2016-05-29 22:18:22 -07:00
Rowan Cockett 231e6dbc93 Suppress image warning. 2016-05-29 19:22:15 -07:00
Rowan Cockett 18f98b2ecd Merge branch 'docs' of https://github.com/simpeg/simpeg into feat/docs-deploy
# Conflicts:
#	SimPEG/Utils/meshutils.py
#	docs/api_Utils.rst
#	docs/conf.py
#	docs/flow/index.rst
2016-05-29 19:18:36 -07:00
Rowan Cockett bc073e49b5 Updates to docs errors. 2016-05-29 18:57:38 -07:00
Rowan Cockett a131383dae Correct solver location. 2016-05-29 18:35:41 -07:00
Rowan Cockett ad4a0240d1 Remove Vertical1DMap from tests. 2016-05-29 18:34:17 -07:00
Rowan Cockett 74f5395573 Surject1D updates. 2016-05-29 18:25:42 -07:00
Rowan Cockett 6f7a0b1279 Rename Vertical1DMap to SurjectVertical1D due to depreciation. 2016-05-29 18:14:42 -07:00
Rowan Cockett e2bb9c8d8e rename flow example. 2016-05-29 18:12:52 -07:00
Rowan Cockett de693adaa7 Minor updates to get it 'working'
There still seems to be a problem with this example:

	- The line search breaks.
	- The plots are not informative.
	- There are a lot of errors in the structured array codes.
2016-05-29 18:04:09 -07:00
Rowan Cockett fc07993006 Spacings in functions. 2016-05-29 18:03:03 -07:00
Rowan Cockett 12a12c7b5a updates to FDEM docs. 2016-05-29 17:51:41 -07:00
Rowan Cockett 0b4215f33e Add DC and IP docs. 2016-05-29 17:45:49 -07:00
Rowan Cockett 5e2a8232a3 Minor updates to titles in examples. 2016-05-29 17:21:37 -07:00
Rowan Cockett feba384911 Add solver parameter to the Casing example. 2016-05-29 17:08:11 -07:00
Rowan Cockett 4844b7230a TOC updates for docs index. 2016-05-29 17:05:42 -07:00
Lindsey Heagy f2e13182bf Merge branch 'dev' into feat/plotImage-curvilinear
# Conflicts:
#	SimPEG/Examples/__init__.py
2016-05-29 16:43:40 -07:00
D Fournier 09cd9c7fa3 Merge branch 'dev' into ref/regularization 2016-05-29 16:26:58 -07:00
Lindsey Heagy 62eb4541cb update example name --> based on mesh 2016-05-29 15:48:15 -07:00
Lindsey 09eb2106ec Merge pull request #307 from simpeg/ref/dev
Ref/dev
2016-05-29 14:50:43 -07:00
D Fournier f8b86abd5a Merge branch 'ref/dev' into ref/regularization 2016-05-29 14:10:46 -07:00
D Fournier e476bf0059 Cleanup Sparse Reg and Directives 2016-05-29 14:09:29 -07:00
Rowan Cockett 825511e9d3 Add a curvilinear plotImage function, update example. 2016-05-29 13:17:22 -07:00
D Fournier 3b4bec9c0b Refactor IRLS iterations, full solves from l2->lp
Adapt Example
2016-05-28 11:27:09 -07:00
micmitch 1960b52dfd First stab at analytic functions for the fields from a harmonic electric dipole source. Not sure about the exception that I try to throw if multiple frequencies and multiple evaluation locations are both specified. 2016-05-27 14:56:48 -07:00
D Fournier 022e1f7660 Update IRLS directive to allow multiple GN iterations.
Remove modifications to the ProjGN solver.
Update IRLS example.
2016-05-27 13:11:31 -07:00
seogi_macbook 28d67e3112 Start of ED !! 2016-05-27 11:26:47 -07:00
D Fournier 406703f1c6 Merge branch 'dev' into ref/dev
Conflicts:
	docs/examples/DC_Forward_PseudoSection.rst
2016-05-27 11:10:39 -07:00
D Fournier 7b72d3a92d Merge branch 'dev' into ref/dev
Conflicts:
	SimPEG/DCIP/DCIPUtils.py
2016-05-27 10:01:28 -07:00
Lindsey cf89f5f6a2 Merge pull request #322 from simpeg/bug/propmap
Bug/propmap
2016-05-26 20:52:42 -07:00
Lindsey Heagy aa1086eba3 use fixed prop map in EM 2016-05-26 18:03:09 -07:00
Lindsey Heagy 1c53129da6 fix bug in prop map linked derivs 2016-05-26 17:58:30 -07:00
sgkang 6fd3be77de Merge pull request #304 from simpeg/dcip/dev
Dcip/dev
2016-05-26 13:27:44 -07:00
seogi_macbook 51d82eee26 Minor fixes to be merged to dev 2016-05-26 09:32:19 -07:00
seogi_macbook f6b49c680a Merge branch 'dev' of https://github.com/simpeg/simpeg into dcip/dev
Conflicts:
	SimPEG/EM/Base.py
	SimPEG/EM/FDEM/SurveyFDEM.py
2016-05-26 09:25:43 -07:00
seogi_macbook 339543b893 Incorporate Lindsey's comments on documenting codes 2016-05-25 23:28:58 -07:00
seogi_macbook 44ad57e90d Merge branch 'dcip/spectralIP' of https://github.com/simpeg/simpeg into dcip/dev
Merge spectral IP stuff, and incorporate Lindsey's comments
2016-05-25 14:22:58 -07:00
Lindsey d98eef2560 Merge pull request #313 from simpeg/em/dev
Em/dev: Naming conventions
2016-05-25 10:53:43 -07:00
seogi_macbook 21d817d9a2 fix bug for adjoint problem 2016-05-24 21:53:18 -07:00
seogi_macbook f20fcb4504 Minor type error based upon numpy version
Cross gradient?
2016-05-24 08:45:12 -07:00
Lindsey Heagy 2c87a50d29 add kwargs to raw vec e,m 2016-05-23 12:21:29 -07:00
Lindsey Heagy beca0203df typo fix 2016-05-23 12:11:03 -07:00
Lindsey Heagy e25b496ab0 allow kwarg input of primary fields 2016-05-23 12:07:14 -07:00
Lindsey e5ec512517 Merge pull request #319 from simpeg/targetmisfit
Target Misfit
2016-05-22 12:36:21 -07:00
Lindsey 342414bd25 Merge pull request #302 from simpeg/fix/numpyDependency
Installation (i.e., setup.py) is no longer dependent on Numpy
2016-05-22 12:03:37 -07:00
Lindsey Heagy 8936fa4021 use phi_d_star, chifact in defining target misfit 2016-05-22 11:42:23 -07:00
seogi_macbook 0179631fe3 Starting Cross gradient ... 2016-05-20 01:57:40 -07:00
seogi_macbook c4c97ae054 Ad MultiRegularization for inverting multiple parameters 2016-05-20 00:04:20 -07:00
seogi_macbook e8bd78f63d Working Spectral IP:
- Fwd
	- Jvec
	- Jtvec
2016-05-19 02:09:48 +09:00
Lindsey d0a65dda1b Merge pull request #317 from simpeg/em/ref/dev-cleanup
em/dev cleanup
2016-05-18 08:13:06 -07:00
Lindsey Heagy a506d5c6be Merge branch 'em/dev' into em/ref/dev-cleanup 2016-05-18 07:31:15 -07:00
Lindsey Heagy 10c8791514 update base MT to import ProblemFDEM 2016-05-18 00:33:30 -07:00
Lindsey Heagy c88263234b rename FDEM --> ProblemFDEM 2016-05-17 23:56:06 -07:00
Lindsey Heagy d5219be3d8 Merge branch 'dev' into dcip/dev
# Conflicts:
#	SimPEG/DCIP/DCIPUtils.py
2016-05-17 23:26:17 -07:00
D Fournier fd3bde787f Propose change to the Projected_GNCG solver. Add inner GN iterations. Nice improvement to the convergence of IRLS 2016-05-12 14:58:16 -07:00
D Fournier 3cc46131a3 Temporary change ... comment out W and Wsmooth 2016-05-12 08:31:01 -07:00
D Fournier cd2360b815 Stash the regularization between each beta 2016-05-11 23:04:14 -07:00
Lindsey Heagy 029171fb1d use .format for strings 2016-05-11 09:09:26 -07:00
Lindsey Heagy a690cab131 simple field receivers are Point receivers 2016-05-11 09:05:13 -07:00
D Fournier e10d6878fb Remove Wsmooth from def W and replace by parts 2016-05-11 07:58:06 -07:00
Lindsey Heagy 3dd9ecc9cd fix tikhonov 2Deriv 2016-05-10 22:10:19 -07:00
Lindsey Heagy 90a3030796 fixed 2 deriv 2016-05-10 21:39:15 -07:00
Lindsey Heagy c1b1c2467f import from ProblemFDEM in baseMT, fixed a missed real_or_imag --> component 2016-05-10 19:57:16 -07:00
Lindsey Heagy 11e6b452c9 renamed FDEM.py to ProblemFDEM.py, changed real_or_imag to component 2016-05-10 17:26:16 -07:00
D Fournier 7964ebce50 Update directive to None the Wsmooth after iteration. 2016-05-10 17:20:46 -07:00
Lindsey Heagy 955bd54019 notation cleanup in Regularization 2016-05-10 16:46:11 -07:00
Lindsey Heagy 2a802c1aa3 weights --> cell_weights, removed vol term from simple regularization 2016-05-10 16:39:47 -07:00
Lindsey Heagy 3f0c89f10b remove extra Ws 2016-05-10 14:53:43 -07:00
Lindsey Heagy eaa37f42e4 remove duplicate evalSmall 2016-05-10 14:51:56 -07:00
D Fournier fb5434695f Alpha_s default to 1.0 2016-05-10 14:31:45 -07:00
D Fournier e037597ecd Merge branch 'feat/sparse-regularization' into ref/regularization 2016-05-10 13:37:16 -07:00
Lindsey Heagy 73c219ff5c updated Problem naming in casing example 2016-05-09 12:29:52 -07:00
Lindsey Heagy abd919e862 Merge branch 'dev' into em/dev 2016-05-09 11:32:59 -07:00
Lindsey 6e00b4c2fe Merge pull request #312 from simpeg/em/ref/fdem_cleanup
Em/ref/fdem cleanup
2016-05-09 08:25:39 -07:00
seogi_macbook 8803956d83 Working on SIP 2016-05-09 19:58:56 +09:00
Lindsey Heagy 0a714663d3 update Jtvec to work with Rx classes 2016-05-08 13:12:37 -07:00
Lindsey Heagy cb042ac938 cleanup imports, docstrings 2016-05-08 13:00:29 -07:00
Lindsey Heagy f7c46ed83b Rx classes for FDEM 2016-05-08 12:41:06 -07:00
Lindsey Heagy 52747c0926 update example 2016-05-08 11:35:28 -07:00
Lindsey Heagy d8eeb7cd05 use Problem3D_assumption, Fields3D_assumption 2016-05-08 11:18:36 -07:00
D Fournier b4ab60c260 Add model mapping to sparse regularization 2016-05-05 11:55:56 -07:00
Lindsey Heagy fbb8cf2731 modularizing regularization 2016-05-04 23:17:01 -07:00
Lindsey Heagy 0379df2bf2 attempt to clean up docs in DCIP utils 2016-05-04 22:27:02 -07:00
Lindsey Heagy 66440b0478 add depreciation warnings to DCIP utils for activeind from topo 2016-05-04 22:14:41 -07:00
Lindsey Heagy dbdcc3cefb use sigma in MfRhoDeriv - due to propmap bug 2016-05-04 22:06:32 -07:00
seogi_macbook c488dabf9a working on IP 2016-05-04 12:48:29 -07:00
seogi_macbook 69ec374415 minor changes 2016-05-03 19:03:41 -07:00
sgkang 224105364d df_dmT + du_dmT has dtype('o')
This seems making problem depending on which machine you are using .... or numpy version. 

We may need to clarify what is sparse and dense for arrays!!
2016-05-03 17:39:07 -07:00
seogi_macbook a7f89131b4 Playing with 2.5D DC inversion
TODOs:

     Parallelize ky ... (currently pretty slow)
2016-05-03 11:26:28 -07:00
seogi_macbook 6e12bdc57a Moving Dom's DCutils ... 2016-05-03 09:20:58 -07:00
seogi_macbook 354e57f24e Problem3D_CC and _N for IP are all tested
a) fwd
b) jvec, jtvec
c) adjoint
2016-05-02 16:47:16 -07:00
seogi_macbook ddb11096c8 Working on IP 2016-05-02 15:05:31 -07:00
seogi_macbook fa6033c438 Working 3D IP problem (CC and N). 2016-05-02 12:00:39 -07:00
Lindsey Heagy dd45a6a085 name updates in DC_Forward_PseudoSection, DC_Utils, example for Utils_surface2ind_topo 2016-05-02 11:40:02 -07:00
seogi_macbook bd63e67161 working on IP
fix bug in RhoDeriv!!
2016-05-02 10:03:01 -07:00
seogi_macbook d350dc258d minor fix for Fields_N and started IP problem. 2016-05-02 08:55:29 -07:00
seogi_macbook 350818d802 add analytic test for 2D dc problems. 2016-05-01 13:21:48 -07:00
Lindsey Heagy ba8f270b3a start of surface2ind_topo 2016-05-01 13:17:16 -07:00
seogi_macbook 4df6f340d3 Add _e, _j, _charge for field objects
Now it is possible to gram three of them from phiSolution
2016-05-01 13:13:20 -07:00
seogi_macbook 9b2eec0ea3 Working 2.5D nodal discretization (Jvec and Jtvec) 2016-05-01 12:33:39 -07:00
Lindsey Heagy 4257ea77b3 remove InjectActiveCellsTopo. you should use InjectActiveCells 2016-04-29 15:09:04 -07:00
Lindsey Heagy a0174e4f30 kwarg name updates 2016-04-29 12:52:45 -07:00
Lindsey ace9cad016 Merge pull request #303 from simpeg/dcip/ref
Dcip/ref
2016-04-29 10:49:50 -07:00
seogi_macbook 38aef03f9d Working 2.5D fwd (nodal discretization)
On going Jvec and Jtvec
2016-04-29 09:35:03 -07:00
seogi_macbook ef602eaab1 working Jtvec 2016-04-28 18:13:18 -07:00
seogi_macbook 0610289fdf Working Jvec for 2.5D DC code 2016-04-28 11:18:37 -07:00
seogi_macbook d14cd444ac working 2.5D fwd problem. 2016-04-27 23:04:28 -07:00
seogi_macbook 92e2fd67de minor fixes. 2016-04-27 15:25:40 -07:00
seogi_macbook 6a064c5f96 Minor changes 2016-04-25 11:00:32 -07:00
seogi_macbook f944f9b76b 1. Add distributed source for nodal discretization
2. Add Analytic tests
3. Fix simple bug in PlotSlice for nodal variable
4. Add more analytic function (sphere)
2016-04-25 10:58:54 -07:00
seogi_macbook dcd4fbf973 Implemented mixed B.C. to CC problem.
Fix bugs in get fuction getxBCyBC_CC
2016-04-24 15:23:14 -07:00
seogi_macbook edc2c5feb6 Merge branch 'dcip/BC' of https://github.com/simpeg/simpeg into dcip/ref 2016-04-24 13:57:01 -07:00
seogi_macbook 1936a04683 Working on implementing mixed BC to DC problem 2016-04-24 13:56:37 -07:00
seogi_macbook fcc2b8b22a Handling null space of A 2016-04-24 13:32:44 -07:00
seogi_macbook eeee594f09 Problem3D_N is tested! 2016-04-24 13:29:38 -07:00
seogi_macbook a48224ed8b no message 2016-04-24 13:18:36 -07:00
seogi_macbook 0bb001973c workking nodal discretizations 2016-04-24 13:01:03 -07:00
Brendan Smithyman f55d9573a6 Installation (i.e., setup.py) is no longer dependent on Numpy already being present. 2016-04-24 13:21:49 -04:00
seogi_macbook 0e16645b67 working Jtvec 2016-04-23 11:06:24 -07:00
seogi_macbook 8cac166fba Working Jvec:
Getting closer to understand how modular EM code is working ...
2016-04-23 10:40:47 -07:00
seogi_macbook 73001abfc5 fix bug 2016-04-23 01:24:31 -07:00
seogi_macbook a9362bd38e Merge branch 'dcip/ref' of https://github.com/simpeg/simpeg into dcip/ref
Conflicts:
	SimPEG/EM/Static/DC/ProblemDC.py

Confused about ...  this line

self.mesh.getFaceInnerProduct(self.curModel.rho)(u)
2016-04-23 00:37:06 -07:00
seogi_macbook 64b94861a0 working on DC problem CC and N 2016-04-22 23:09:31 -07:00
Lindsey Heagy 8775364d8f start of the sketch of Jvec (not to be trusted yet!) 2016-04-22 17:48:26 -07:00
Lindsey Heagy 5ec6e79a39 MfRhoIDeriv 2016-04-22 17:47:36 -07:00
seogi_macbook 2c09be9fc1 Working Mixed boundary conditions and testing ... 2016-04-21 14:44:37 -07:00
Lindsey Heagy cd5339322e sketch of DC 2016-04-21 11:00:20 -07:00
seogi_macbook 28005dde45 change minor bug for meshIO 2016-04-15 17:17:18 -07:00
seogi_macbook 8739ba0f20 working dc fwd 2016-04-15 16:53:43 -07:00
Lindsey Heagy 119bc801c7 start of DC refactor in EM/Static 2016-04-15 14:51:19 -07:00
seogi_macbook 35bac38c8b working on mixed BC 2016-04-14 22:41:47 -07:00
seogi_macbook 05e3b02b3a Merge branch 'dcip/dev' of https://github.com/simpeg/simpeg into dcip/dev 2016-04-13 16:52:44 -07:00
seogi_macbook fb1ff4e867 Merge branch 'dev' of https://github.com/simpeg/simpeg into dcip/dev 2016-04-05 21:50:03 -07:00
seogi_macbook a31319b46e Merge branch 'master' of https://github.com/simpeg/simpeg into dcip/dev 2016-04-05 21:49:38 -07:00
Lindsey Heagy 756b738ef2 Merge branch 'dev' into docs 2016-04-05 17:47:17 -07:00
Lindsey Heagy f59cfa9481 Merge branch 'dev' into em/dev 2016-04-02 08:35:09 -07:00
Lindsey a220c75d78 Merge pull request #273 from simpeg/em/patch/srcIntegration
make integrate = False default for all sources
2016-03-31 11:17:54 -07:00
Lindsey Heagy 021e7c794c Merge branch 'master' into docs
# Conflicts:
#	SimPEG/Mesh/TensorMesh.py
2016-03-29 22:53:16 -07:00
Lindsey Heagy 936a7aaadc make integrate = False default for all sources 2016-03-29 21:32:08 -07:00
Lindsey Heagy b5b70390cb Merge branch 'dev' into docs 2016-03-06 21:50:27 -08:00
Lindsey Heagy 6acaa81faf fixed merge conflicts in FDEM docs that I missed 2016-02-09 09:03:20 -08:00
Lindsey Heagy 312b5d79c5 resolved merge conflicts in TensorMesh 2016-02-09 08:53:01 -08:00
Lindsey Heagy 999a37547e Merge branch 'dev' into docs
# Conflicts:
#	.travis.yml
#	SimPEG/EM/FDEM/FDEM.py
#	SimPEG/Mesh/TensorMesh.py
2016-02-09 08:32:41 -08:00
Lindsey Heagy cbe8758465 corrected scipy.sparse.csr_matrix, move size descriptions to :return: instead of :type: 2016-02-01 08:22:00 -08:00
Lindsey Heagy 6b359f49b5 docs clean-up (using autoclass is more stable than automodule) 2016-01-31 15:21:46 -08:00
Lindsey Heagy 2254eedbac indentations clean up in FDEM.py 2016-01-31 13:54:39 -08:00
Lindsey Heagy 012d2cadf1 use intersphinx mapping to get numpy, scipy, matplotlib, python inventories 2016-01-31 13:54:24 -08:00
Lindsey Heagy 841ba61006 clean up the html build 2016-01-31 13:22:36 -08:00
Lindsey Heagy 2874e204ee exclude _static from warnings 2016-01-31 12:52:42 -08:00
Lindsey Heagy adca273565 ignore nonlocal images in sphinx build 2016-01-31 12:46:24 -08:00
Lindsey Heagy d9d6f70958 better description of paths in test_docs 2016-01-31 12:45:51 -08:00
Lindsey Heagy f4ef767764 seperate out docs test so it runs independently (not on every test) 2016-01-31 12:08:29 -08:00
Lindsey Heagy e314bdb740 add sphinx to travis conda install 2016-01-31 11:06:47 -08:00
Lindsey Heagy e005ed8f5f use cd to get into docs directories for testing 2016-01-31 10:51:55 -08:00
Lindsey Heagy ac2e38e89d test docs first 2016-01-31 10:47:00 -08:00
Lindsey Heagy ade37fb493 add travis to docs. nit-picky testing on html, latex, link check 2016-01-31 09:51:57 -08:00
189 changed files with 9374 additions and 5152 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
[bumpversion]
current_version = 0.1.10
current_version = 0.1.12
files = setup.py SimPEG/__init__.py docs/conf.py
+2
View File
@@ -39,3 +39,5 @@ nosetests.xml
*.sublime-workspace
docs/_build/
Makefile
docs/warnings.txt
.DS_Store
+26 -4
View File
@@ -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,11 +53,26 @@ 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
- bash <(curl -s https://codecov.io/bash)
- 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:
+13 -6
View File
@@ -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
======
@@ -21,14 +21,21 @@ SimPEG
:target: https://travis-ci.org/simpeg/simpeg
:alt: Travis CI build status
.. image:: https://img.shields.io/coveralls/simpeg/simpeg.svg
: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
.. image:: https://codecov.io/gh/simpeg/simpeg/branch/master/graph/badge.svg
   :target: https://codecov.io/gh/simpeg/simpeg
.. image:: https://www.quantifiedcode.com/api/v1/project/933aa3decf444538aa432c8817169b6d/badge.svg
:target: https://www.quantifiedcode.com/app/project/933aa3decf444538aa432c8817169b6d
:alt: Code issues
.. image:: https://api.codacy.com/project/badge/Grade/4fc959a5294a418fa21fc7bc3b3aa078
:target: https://www.codacy.com/app/lindseyheagy/simpeg?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=simpeg/simpeg&amp;utm_campaign=Badge_Grade
:alt: codacy
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:
+2 -2
View File
@@ -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::
+1 -1
View File
@@ -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::
+164 -203
View File
@@ -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,23 +169,19 @@ def readUBC_DC2DModel(fileName):
return model
def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None, cblabel=True, axlabel = True, colorbar = True, contour = None):
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)
:switch dtype=-> Either 'appr' (app. res) | 'appc' (app. con) | 'volt' (potential)
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
@@ -218,39 +214,39 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None, cbl
Cmid = (Tx[0][0] + Tx[1][0])/2
Pmid = (Rx[0][:,0] + Rx[1][:,0])/2
# Change output for dtype
if dtype == 'volt':
# Change output for unitType
if unitType == 'volt':
rho = np.hstack([rho,data])
else:
# Compute pant leg of apparent rho
if stype == 'pdp':
if surveyType == 'pole-dipole':
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
elif stype == 'dpdp':
elif surveyType == 'dipole-dipole':
leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA )
else:
print """dtype must be 'pdp'(pole-dipole) | 'dpdp' (dipole-dipole) """
print """unitType must be 'pole-dipole' | 'dipole-dipole' """
break
if dtype == 'appc':
if unitType == 'appConductivity':
leg = np.log10(abs(1./leg))
rho = np.hstack([rho,leg])
elif dtype == 'appr':
elif unitType == 'appResistivity':
leg = np.log10(abs(leg))
rho = np.hstack([rho,leg])
else:
print """dtype must be 'appr' | 'appc' | 'volt' """
print """unitType must be 'appResistivity' | 'appConductivity' | 'volt' """
break
midx = np.hstack([midx, ( Cmid + Pmid )/2 ])
@@ -259,7 +255,7 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None, cbl
# 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()
@@ -268,36 +264,37 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None, cbl
# Plot data
grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho)
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 dtype == 'volt':
if unitType == 'volt':
cbar = plt.colorbar(ph, ax = axs, format="%4.1f",fraction=0.04,orientation="horizontal")
else:
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 cblabel:
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)
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:
@@ -310,27 +307,24 @@ def plot_pseudoSection(DCsurvey, axs, stype='dpdp', dtype="appc", clim=None, cbl
return ph
def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
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
@@ -346,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]
@@ -366,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,:]])
@@ -382,33 +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 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
@@ -416,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)
@@ -441,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]
@@ -455,44 +449,38 @@ 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='3D', stype='SURFACE', iptype = 0):
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('! ' + surveyType + ' FORMAT\n')
if iptype!=0:
fid.write('IPTYPE=%i\n'%iptype)
fid.write('IPTYPE={0:d}\n'.format(iptype))
else:
fid.write('! ' + stype + ' FORMAT\n')
count = 0
for ii in range(DCsurvey.nSrc):
@@ -506,65 +494,65 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype='3D', stype='SURFACE', iptype = 0):
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)
B = np.repeat(tx[0,1],M.shape[0],axis=0)
M = M[:,0]
N = N[:,0]
np.savetxt(fid, np.c_[A, B, M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n')
else:
if stype == 'SURFACE':
if surveyType == 'SURFACE':
fid.writelines("%f " % ii for ii in mkvc(tx[0,:]))
fid.writelines("{0:f} ".format(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,:]))
fid.writelines("{0:e} ".format(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)
fid.write('{0:d}\n'.format(nD))
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,:]))
fid.writelines("{0:e} ".format(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[0:3,:]))
fid.writelines("{0:e} ".format(ii) for ii in mkvc(tx[0:3,:]))
fid.write('%i\n'% nD)
fid.write('{0:d}\n'.format(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, flag = 'local'):
def convertObs_DC3D_to_2D(DCsurvey, lineID, flag='local'):
"""
Read DC survey and projects the coordinate system
according to the flag = 'Xloc' | 'Yloc' | 'local' (default)
@@ -573,15 +561,9 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'):
The Z value is preserved, but Y coordinates zeroed.
Input:
:param survey3D
Output:
:figure survey2D
Edited April 6th, 2016
@author: dominiquef
:param DC.Survey survey3D: 3D simpeg DC survey
:rtype: DC.Survey
:return: survey2D
"""
from SimPEG import np
@@ -666,39 +648,34 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID, flag = 'local'):
DCsurvey2D.std = np.asarray(DCsurvey.std)
return DCsurvey2D
def readUBC_DC3Dobs(fileName, dtype = 'DC'):
def readUBC_DC3Dobs(fileName, rtype = 'DC'):
"""
Read UBC GIF IP 3D observation file and generate survey
Input:
:param fileName, path to the UBC GIF 3D obs file
Output:
:param IPsurvey
:return
@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
if dtype == 'IP':
if rtype == 'IP':
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='IPTYPE')
elif dtype == 'DC':
elif rtype == 'DC':
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
else:
print "dtype must be 'DC'(default) | 'IP'"
print "rtype must be 'DC'(default) | 'IP'"
# Pre-allocate
srcLists = []
Rx = []
d = []
wd = []
# Countdown for number of obs/tx
count = 0
@@ -717,7 +694,7 @@ def readUBC_DC3Dobs(fileName, dtype = 'DC'):
# Check if z value is provided, if False -> nan
if len(temp)==5:
tx = np.r_[temp[0:2],np.nan,temp[2:4],np.nan]
zflag = False # Pass on the flag to the receiver loc
else:
@@ -729,12 +706,12 @@ def readUBC_DC3Dobs(fileName, dtype = 'DC'):
temp = np.fromstring(obsfile[ii], dtype=float,sep=' ') # Get the string
# Filter out negative IP
# if temp[-2] < 0:
# if temp[-2] < 0:
# count = count -1
# print "Negative!"
#
#
# else:
# If the Z-location is provided, otherwise put nan
if zflag:
@@ -772,17 +749,9 @@ 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
@@ -822,11 +791,9 @@ def readUBC_DC2Dpre(fileName):
Read UBC GIF DCIP 2D observation file and generate arrays for tx-rx location
Input:
:param fileName, path to the UBC GIF 3D obs file
Output:
DCsurvey
:return
: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 !! >>
@@ -888,12 +855,9 @@ 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
@@ -959,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
+153 -74
View File
@@ -15,7 +15,7 @@ class InversionDirective(object):
@inversion.setter
def inversion(self, i):
if getattr(self,'_inversion',None) is not None:
print 'Warning: InversionDirective %s has switched to a new inversion.' % self.__name__
print 'Warning: InversionDirective {0!s} has switched to a new inversion.'.format(self.__name__)
self._inversion = i
@property
@@ -47,7 +47,7 @@ class DirectiveList(object):
def __init__(self, *directives, **kwargs):
self.dList = []
for d in directives:
assert isinstance(d, InversionDirective), 'All directives must be InversionDirectives not %s' % d.__name__
assert isinstance(d, InversionDirective), 'All directives must be InversionDirectives not {0!s}'.format(d.__name__)
self.dList.append(d)
Utils.setKwargs(self, **kwargs)
@@ -68,7 +68,7 @@ class DirectiveList(object):
def inversion(self, i):
if self.inversion is i: return
if getattr(self,'_inversion',None) is not None:
print 'Warning: %s has switched to a new inversion.' % self.__name__
print 'Warning: {0!s} has switched to a new inversion.'.format(self.__name__)
for d in self.dList:
d.inversion = i
self._inversion = i
@@ -79,7 +79,7 @@ class DirectiveList(object):
return
directives = ['initialize', 'endIter', 'finish']
assert ruleType in directives, 'Directive type must be in ["%s"]' % '", "'.join(directives)
assert ruleType in directives, 'Directive type must be in ["{0!s}"]'.format('", "'.join(directives))
for r in self.dList:
getattr(r, ruleType)()
@@ -141,15 +141,21 @@ class BetaSchedule(InversionDirective):
def endIter(self):
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
if self.debug: print 'BetaSchedule is cooling Beta. Iteration: {0:d}'.format(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:
@@ -175,42 +181,42 @@ class _SaveEveryIteration(InversionDirective):
def fileName(self):
if getattr(self, '_fileName', None) is None:
from datetime import datetime
self._fileName = '%s-%s'%(self.name, datetime.now().strftime('%Y-%m-%d-%H-%M'))
self._fileName = '{0!s}-{1!s}'.format(self.name, datetime.now().strftime('%Y-%m-%d-%H-%M'))
return self._fileName
@fileName.setter
def fileName(self, value):
self._fileName = value
class SaveModelEveryIteration(_SaveEveryIteration):
class SaveModelEveryIteration(SaveEveryIteration):
"""SaveModelEveryIteration"""
def initialize(self):
print "SimPEG.SaveModelEveryIteration will save your models as: '###-%s.npy'"%self.fileName
print "SimPEG.SaveModelEveryIteration will save your models as: '###-{0!s}.npy'".format(self.fileName)
def endIter(self):
np.save('%03d-%s' % (self.opt.iter, self.fileName), self.opt.xc)
np.save('{0:03d}-{1!s}'.format(self.opt.iter, self.fileName), self.opt.xc)
class SaveOutputEveryIteration(_SaveEveryIteration):
class SaveOutputEveryIteration(SaveEveryIteration):
"""SaveModelEveryIteration"""
def initialize(self):
print "SimPEG.SaveOutputEveryIteration will save your inversion progress as: '###-%s.txt'"%self.fileName
print "SimPEG.SaveOutputEveryIteration will save your inversion progress as: '###-{0!s}.txt'".format(self.fileName)
f = open(self.fileName+'.txt', 'w')
f.write(" # beta phi_d phi_m f\n")
f.close()
def endIter(self):
f = open(self.fileName+'.txt', 'a')
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.write(' {0:3d} {1:1.4e} {2:1.4e} {3:1.4e} {4:1.4e}\n'.format(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):
print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '###-%s.npz'"%self.fileName
print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '###-{0!s}.npz'".format(self.fileName)
def endIter(self):
# Save the data.
@@ -237,12 +243,6 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration):
# Save the file as a npz
np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred)
# class UpdateReferenceModel(Parameter):
# mref0 = None
# def nextIter(self):
# mref = getattr(self, 'm_prev', None)
# if mref is None:
# if self.debug: print 'UpdateReferenceModel is using mref0'
@@ -253,76 +253,171 @@ class SaveOutputDictEveryIteration(_SaveEveryIteration):
class Update_IRLS(InversionDirective):
eps_min = None
eps = None
norms = [2.,2.,2.,2.]
factor = None
gamma = None
phi_m_last = None
phi_d_last = None
f_old = None
f_min_change = 1e-2
beta_tol = 5e-2
prctile = 95
# Solving parameter for IRLS (mode:2)
IRLSiter = 0
minGNiter = 5
maxIRLSiter = 10
iterStart = 0
# Beta schedule
coolingFactor = 2.
coolingRate = 1
mode = 1
@property
def target(self):
if getattr(self, '_target', None) is None:
self._target = self.survey.nD*0.5
return self._target
@target.setter
def target(self, val):
self._target = val
def initialize(self):
# Scale the regularization for changes in norm
if getattr(self, 'phi_m_last', None) is not None:
self.reg.curModel = self.invProb.curModel
self.reg.gamma = 1.
phim_new = self.reg.eval(self.invProb.curModel)
self.gamma = self.phi_m_last / phim_new
self.reg.curModel = self.invProb.curModel
self.reg.gamma = self.gamma
if getattr(self, 'phi_d_last', None) is None:
self.phi_d_last = self.invProb.phi_d
if self.mode == 1:
self.reg.norms = [2., 2., 2., 2.]
def endIter(self):
# 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])
# 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: {0:d}'.format(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: {0:6.3e}".format((self.f_change))
# Check for maximum number of IRLS cycles
if self.IRLSiter == self.maxIRLSiter:
print "Reach maximum number of IRLS cycles: {0:d}".format(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.reg.eps = eps
self.f_old = phim_new
# Get phi_m at the end of current iteration
self.phi_m_last = self.invProb.phi_m_last
# # 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
# Update the model used for the IRLS weights
self.reg.curModel = self.invProb.curModel
# Get phi_m at the end of current iteration
self.phi_m_last = self.invProb.phi_m_last
# Temporarely set gamma to 1. to get raw phi_m
self.reg.gamma = 1.
# 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
# Compute new model objective function value
phim_new = self.reg.eval(self.invProb.curModel)
# Update the model used for the IRLS weights
self.reg.curModel = self.invProb.curModel
# Update gamma to scale the regularization between IRLS iterations
self.reg.gamma = self.phi_m_last / phim_new
# Temporarely set gamma to 1. to get raw phi_m
self.reg.gamma = 1.
# Set the weighting matrix to None so that it is recomputed next time
# it is called in the inversion
self.reg._W = None
# 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.
@@ -355,19 +450,3 @@ class Update_Wj(InversionDirective):
JtJdiag = JtJdiag / max(JtJdiag)
self.reg.wght = JtJdiag
class Scale_Beta(InversionDirective):
"""
Instead of a linear cooling schedule, beta is allowed to change based
on the ratio between the target misfit and the current data misfit. The
update is done only if the misfit is outside some threshold bounds.
"""
tol = 0.05
def endIter(self):
# Check if misfit is within the tolerance, otherwise adjust beta
val = self.invProb.phi_d / (self.survey.nD*0.5)
if np.abs(1.-val) > self.tol:
self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d
+118
View File
@@ -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
+302
View File
@@ -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
+2
View File
@@ -1,3 +1,5 @@
from TDEM import hzAnalyticDipoleT
from FDEM import hzAnalyticDipoleF
from FDEMcasing import *
from DC import DCAnalyticHalf, DCAnalyticSphere
from FDEMDipolarfields import *
+37 -14
View File
@@ -1,6 +1,7 @@
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)
@@ -19,10 +20,10 @@ class BaseEMProblem(Problem.BaseProblem):
Problem.BaseProblem.__init__(self, mesh, **kwargs)
surveyPair = Survey.BaseSurvey
dataPair = Survey.Data
surveyPair = Survey.BaseSurvey #: The survey to pair with.
dataPair = Survey.Data #: The data to pair with.
PropMap = EMPropMap
PropMap = EMPropMap #: The property mapping
Solver = SimpegSolver
solverOpts = {}
@@ -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,6 +80,20 @@ 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
@property
def Vol(self):
if getattr(self, '_Vol', None) is None:
self._Vol = Utils.sdiag(self.mesh.vol)
return self._Vol
# ----- Magnetic Permeability ----- #
@property
@@ -127,7 +151,6 @@ class BaseEMProblem(Problem.BaseProblem):
"""
return self.mesh.getEdgeInnerProductDeriv(self.curModel.sigma)(u) * self.curModel.sigmaDeriv
@property
def MeSigmaI(self):
"""
@@ -146,10 +169,7 @@ class BaseEMProblem(Problem.BaseProblem):
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):
@@ -165,8 +185,7 @@ class BaseEMProblem(Problem.BaseProblem):
"""
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):
@@ -183,7 +202,10 @@ class BaseEMProblem(Problem.BaseProblem):
"""
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):
@@ -192,9 +214,10 @@ class BaseEMSurvey(Survey.BaseSurvey):
self.srcList = srcList
Survey.BaseSurvey.__init__(self, **kwargs)
def eval(self, u):
def eval(self, f):
"""
Project fields to receiver locations
:param Fields u: fields object
:rtype: numpy.ndarray
:return: data
@@ -202,8 +225,8 @@ class BaseEMSurvey(Survey.BaseSurvey):
data = Survey.Data(self)
for src in self.srcList:
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 Receivers to project fields deriv.')
+30 -42
View File
@@ -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
@@ -42,7 +42,7 @@ class Fields(SimPEG.Problem.Fields):
:return: total electric field
"""
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])
raise NotImplementedError ('Getting e from {0!s} is not implemented'.format(self.knownFields.keys()[0]))
return self._ePrimary(solution,srcList) + self._eSecondary(solution,srcList)
@@ -56,7 +56,7 @@ class Fields(SimPEG.Problem.Fields):
:return: total magnetic flux density
"""
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])
raise NotImplementedError ('Getting b from {0!s} is not implemented'.format(self.knownFields.keys()[0]))
return self._bPrimary(solution, srcList) + self._bSecondary(solution, srcList)
@@ -70,7 +70,7 @@ class Fields(SimPEG.Problem.Fields):
:return: total magnetic field
"""
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])
raise NotImplementedError ('Getting h from {0!s} is not implemented'.format(self.knownFields.keys()[0]))
return self._hPrimary(solution, srcList) + self._hSecondary(solution, srcList)
@@ -84,7 +84,7 @@ class Fields(SimPEG.Problem.Fields):
:return: total current density
"""
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])
raise NotImplementedError ('Getting j from {0!s} is not implemented'.format(self.knownFields.keys()[0]))
return self._jPrimary(solution, srcList) + self._jSecondary(solution, srcList)
@@ -92,7 +92,7 @@ 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?
@@ -100,7 +100,7 @@ class Fields(SimPEG.Problem.Fields):
: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:
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
raise NotImplementedError ('Getting eDerivs from {0!s} is not implemented'.format(self.knownFields.keys()[0]))
if adjoint:
return self._eDeriv_u(src, v, adjoint), self._eDeriv_m(src, v, adjoint)
@@ -110,7 +110,7 @@ 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?
@@ -118,7 +118,7 @@ class Fields(SimPEG.Problem.Fields):
: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:
raise NotImplementedError ('Getting bDerivs from %s is not implemented' %self.knownFields.keys()[0])
raise NotImplementedError ('Getting bDerivs from {0!s} is not implemented'.format(self.knownFields.keys()[0]))
if adjoint:
return self._bDeriv_u(src, v, adjoint), self._bDeriv_m(src, v, adjoint)
@@ -128,7 +128,7 @@ class Fields(SimPEG.Problem.Fields):
"""
Total derivative of h with respect to the inversion model. Returns :math:`d\mathbf{h}/d\mathbf{m}` for forward and (:math:`d\mathbf{h}/d\mathbf{u}`, :math:`d\mathb{u}/d\mathbf{m}`) for the adjoint
:param 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?
@@ -136,7 +136,7 @@ class Fields(SimPEG.Problem.Fields):
: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:
raise NotImplementedError ('Getting hDerivs from %s is not implemented' %self.knownFields.keys()[0])
raise NotImplementedError ('Getting hDerivs from {0!s} is not implemented'.format(self.knownFields.keys()[0]))
if adjoint:
return self._hDeriv_u(src, v, adjoint), self._hDeriv_m(src, v, adjoint)
@@ -146,7 +146,7 @@ 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?
@@ -154,18 +154,18 @@ class Fields(SimPEG.Problem.Fields):
: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:
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
raise NotImplementedError ('Getting jDerivs from {0!s} is not implemented'.format(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
@@ -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
@@ -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
@@ -988,12 +979,12 @@ class Fields_j(Fields):
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
@@ -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,8 +17,8 @@ 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
\\\(\\\mathbf{h}\\\) and current density \\\(\\\mathbf{j}\\\)
@@ -28,13 +28,14 @@ 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):
"""
@@ -64,7 +65,7 @@ class BaseFDEMProblem(BaseEMProblem):
:param numpy.array m: inversion model (nP,)
:param numpy.array v: vector which we take sensitivity product with (nP,)
:param SimPEG.EM.FDEM.Fields u: fields object
:param SimPEG.EM.FDEM.FieldsFDEM.FieldsFDEM u: fields object
:rtype numpy.array:
:return: Jv (ndata,)
"""
@@ -87,7 +88,7 @@ class BaseFDEMProblem(BaseEMProblem):
du_dm_v = Ainv * ( - dA_dm_v + dRHS_dm_v )
for rx in src.rxList:
df_dmFun = getattr(f, '_%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, f, df_dm_v)
Ainv.clean()
@@ -99,7 +100,7 @@ class BaseFDEMProblem(BaseEMProblem):
:param numpy.array m: inversion model (nP,)
:param numpy.array v: vector which we take adjoint product with (nP,)
:param SimPEG.EM.FDEM.Fields u: fields object
:param SimPEG.EM.FDEM.FieldsFDEM.FieldsFDEM u: fields object
:rtype numpy.array:
:return: Jv (ndata,)
"""
@@ -125,7 +126,7 @@ class BaseFDEMProblem(BaseEMProblem):
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_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,10 +138,9 @@ 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')
@@ -154,8 +154,8 @@ class BaseFDEMProblem(BaseEMProblem):
Evaluates the sources for a given frequency and puts them in matrix form
:param float freq: Frequency
:rtype: (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':
@@ -167,6 +167,7 @@ class BaseFDEMProblem(BaseEMProblem):
for i, src in enumerate(Srcs):
smi, sei = src.eval(self)
#Why are you adding?
s_m[:,i] = s_m[:,i] + smi
s_e[:,i] = s_e[:,i] + sei
@@ -177,7 +178,7 @@ class BaseFDEMProblem(BaseEMProblem):
################################ 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)
@@ -269,7 +270,7 @@ class Problem_e(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
@@ -288,7 +289,7 @@ class Problem_e(BaseFDEMProblem):
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)
@@ -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
@@ -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)
@@ -529,8 +531,8 @@ class Problem_j(BaseFDEMProblem):
\mathbf{RHS} = \mathbf{C} \mathbf{M_{\mu}^e}^{-1}\mathbf{s_m} -i\omega \mathbf{s_e}
:param float freq: Frequency
:rtype: numpy.ndarray (nE, nSrc)
:return: RHS
:rtype: numpy.ndarray
:return: RHS (nE, nSrc)
"""
s_m, s_e = self.getSourceTerm(freq)
@@ -549,7 +551,7 @@ class Problem_j(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
@@ -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
@@ -653,6 +657,7 @@ class Problem_h(BaseFDEMProblem):
:param float freq: Frequency
:rtype: numpy.ndarray
:return: RHS (nE, nSrc)
"""
s_m, s_e = self.getSourceTerm(freq)
@@ -666,7 +671,7 @@ class Problem_h(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
+126
View File
@@ -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 {0!s} not known. Orientation must be in 'x', 'y', 'z'. Arbitrary orientations have not yet been implemented.".format(orientation)
assert(component in ['real', 'imag']), "'component' must be 'real' or 'imag', not {0!s}".format(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)
+59 -50
View File
@@ -9,17 +9,22 @@ 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
: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)
@@ -32,10 +37,10 @@ class BaseSrc(Survey.BaseSrc):
- :code:`s_mDeriv` : derivative of the magnetic source term
- :code:`s_eDeriv` : derivative of the electric source term
:param 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:
@@ -47,47 +52,55 @@ class BaseSrc(Survey.BaseSrc):
"""
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):
"""
Magnetic source term
:param Problem prob: FDEM Problem
:param BaseFDEMProblem prob: FDEM Problem
:rtype: numpy.ndarray
:return: magnetic source term on mesh
"""
@@ -97,7 +110,7 @@ class BaseSrc(Survey.BaseSrc):
"""
Electric source term
:param Problem prob: FDEM Problem
:param BaseFDEMProblem prob: FDEM Problem
:rtype: numpy.ndarray
:return: electric source term on mesh
"""
@@ -107,7 +120,7 @@ class BaseSrc(Survey.BaseSrc):
"""
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
@@ -120,7 +133,7 @@ class BaseSrc(Survey.BaseSrc):
"""
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
@@ -136,21 +149,20 @@ class RawVec_e(BaseSrc):
: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 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):
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):
"""
Electric source term
:param Problem prob: FDEM Problem
:param BaseFDEMProblem prob: FDEM Problem
:rtype: numpy.ndarray
:return: electric source term on mesh
"""
@@ -166,21 +178,20 @@ class RawVec_m(BaseSrc):
: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 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()):
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):
"""
Magnetic source term
:param Problem prob: FDEM Problem
:param BaseFDEMProblem prob: FDEM Problem
:rtype: numpy.ndarray
:return: magnetic source term on mesh
"""
@@ -197,20 +208,19 @@ class RawVec(BaseSrc):
: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 bool integrate: Integrate the source term (multiply by Me) [False]
"""
def __init__(self, rxList, freq, s_m, s_e, integrate=True):
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):
"""
Magnetic source term
:param Problem prob: FDEM Problem
:param BaseFDEMProblem prob: FDEM Problem
:rtype: numpy.ndarray
:return: magnetic source term on mesh
"""
@@ -222,7 +232,7 @@ class RawVec(BaseSrc):
"""
Electric source term
:param Problem prob: FDEM Problem
:param BaseFDEMProblem prob: FDEM Problem
:rtype: numpy.ndarray
:return: electric source term on mesh
"""
@@ -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,7 +339,7 @@ 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
"""
@@ -341,7 +350,7 @@ class MagDipole(BaseSrc):
"""
The magnetic source term
:param Problem prob: FDEM problem
:param BaseFDEMProblem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
@@ -355,7 +364,7 @@ class MagDipole(BaseSrc):
"""
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,7 +455,7 @@ 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
"""
@@ -457,7 +466,7 @@ class MagDipole_Bfield(BaseSrc):
"""
The magnetic source term
:param Problem prob: FDEM problem
:param BaseFDEMProblem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
@@ -470,7 +479,7 @@ class MagDipole_Bfield(BaseSrc):
"""
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,7 +567,7 @@ 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
"""
@@ -569,7 +578,7 @@ class CircularLoop(BaseSrc):
"""
The magnetic source term
:param Problem prob: FDEM problem
:param BaseFDEMProblem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
@@ -582,7 +591,7 @@ class CircularLoop(BaseSrc):
"""
The electric source term
:param Problem prob: FDEM problem
:param BaseFDEMProblem prob: FDEM problem
:rtype: numpy.ndarray
:return: primary magnetic field
"""
+2 -119
View File
@@ -4,126 +4,9 @@ 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, f):
"""
Project fields to recievers to get data.
:param Source src: FDEM source
:param Mesh mesh: mesh used
:param Fields f: fields object
:rtype: numpy.ndarray
:return: fields projected to recievers
"""
# projGLoc = u._GLoc(self.knownRxTypes[self.rxType][0])
# projGLoc += self.knownRxTypes[self.rxType][1]
P = self.getP(mesh, self.projGLoc(f))
f_part_complex = f[src, self.projField]
# get the real or imag component
real_or_imag = self.projComp
f_part = getattr(f_part_complex, real_or_imag)
return P*f_part
def evalDeriv(self, src, mesh, f, v, adjoint=False):
"""
Derivative of projected fields with respect to the inversion model times a vector.
:param Source src: FDEM source
:param Mesh mesh: mesh used
:param Fields f: fields object
:param numpy.ndarray v: vector to multiply
:rtype: numpy.ndarray
:return: fields projected to recievers
"""
P = self.getP(mesh, self.projGLoc(f))
if not adjoint:
Pv_complex = P * v
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(BaseEMSurvey):
"""
Frequency domain electromagnetic survey
@@ -132,7 +15,7 @@ class Survey(BaseEMSurvey):
"""
srcPair = Src.BaseSrc
rxPair = Rx
rxPair = Rx.BaseRx
def __init__(self, srcList, **kwargs):
# Sort these by frequency
+5 -3
View File
@@ -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
+160
View File
@@ -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
+148
View File
@@ -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 {0!s} is not implemented'.format(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 {0!s} is not implemented'.format(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 {0!s} is not implemented'.format(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))
+146
View File
@@ -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 {0!s} is not implemented'.format(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 {0!s} is not implemented'.format(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 {0!s} is not implemented'.format(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
+296
View File
@@ -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, '_{0!s}Deriv'.format(rx.projField), None)
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
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, '_{0!s}Deriv'.format(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()
+349
View File
@@ -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, '_{0!s}Deriv'.format(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, '_{0!s}Deriv'.format(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()
+129
View File
@@ -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
+86
View File
@@ -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
+38
View File
@@ -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
+38
View File
@@ -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
+8
View File
@@ -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
+372
View File
@@ -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, '_{0!s}Deriv'.format(rx.projField), None)
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
# 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, '_{0!s}Deriv'.format(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)
+23
View File
@@ -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)
+2
View File
@@ -0,0 +1,2 @@
from ProblemIP import Problem3D_CC, Problem3D_N
from SurveyIP import Survey
+445
View File
@@ -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, '_{0!s}Deriv'.format(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, '_{0!s}Deriv'.format(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, '_{0!s}Deriv'.format(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)
+204
View File
@@ -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) ) )
+88
View File
@@ -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
+64
View File
@@ -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
+102
View File
@@ -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
+5
View File
@@ -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
+317
View File
@@ -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
+1
View File
@@ -0,0 +1 @@
from StaticUtils import *
+3
View File
@@ -0,0 +1,3 @@
import DC
import IP
import SIP
+13 -13
View File
@@ -47,7 +47,7 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
self.waveformType = "GENERAL"
def fields(self, m):
if self.verbose: print '%s\nCalculating fields(m)\n%s'%('*'*50,'*'*50)
if self.verbose: print '{0!s}\nCalculating fields(m)\n{1!s}'.format('*'*50, '*'*50)
self.curModel = m
# Create a fields storage object
F = self._FieldsForward_pair(self.mesh, self.survey)
@@ -55,7 +55,7 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
# Set the initial conditions
F[src,:,0] = src.getInitialFields(self.mesh)
F = self.forward(m, self.getRHS, F=F)
if self.verbose: print '%s\nDone calculating fields(m)\n%s'%('*'*50,'*'*50)
if self.verbose: print '{0!s}\nDone calculating fields(m)\n{1!s}'.format('*'*50, '*'*50)
return F
def forward(self, m, RHS, F=None):
@@ -70,11 +70,11 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
if Ainv is not None:
Ainv.clean()
A = self.getA(tInd)
if self.verbose: print 'Factoring... (dt = %e)'%dt
if self.verbose: print 'Factoring... (dt = {0:e})'.format(dt)
Ainv = self.Solver(A, **self.solverOpts)
if self.verbose: print 'Done'
rhs = RHS(tInd, F)
if self.verbose: print ' Solving... (tInd = %d)'%tInd
if self.verbose: print ' Solving... (tInd = {0:d})'.format(tInd)
sol = Ainv * rhs
if self.verbose: print ' Done...'
if sol.ndim == 1:
@@ -95,11 +95,11 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
if Ainv is not None:
Ainv.clean()
A = self.getA(tInd)
if self.verbose: print 'Factoring (Adjoint)... (dt = %e)'%dt
if self.verbose: print 'Factoring (Adjoint)... (dt = {0:e})'.format(dt)
Ainv = self.Solver(A, **self.solverOpts)
if self.verbose: print 'Done'
rhs = RHS(tInd, F)
if self.verbose: print ' Solving (Adjoint)... (tInd = %d)'%tInd
if self.verbose: print ' Solving (Adjoint)... (tInd = {0:d})'.format(tInd)
sol = Ainv * rhs
if self.verbose: print ' Done...'
if sol.ndim == 1:
@@ -112,7 +112,7 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
"""
:param numpy.array m: Conductivity model
:param numpy.ndarray v: vector (model object)
:param simpegEM.TDEM.FieldsTDEM f: Fields resulting from m
:param FieldsTDEM f: Fields resulting from m
:rtype: numpy.ndarray
:return: w (data object)
@@ -123,21 +123,21 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
* Compute \\\(\\\\vec{w} = -\\\mathbf{Q} \\\\vec{y}\\\)
"""
if self.verbose: print '%s\nCalculating J(v)\n%s'%('*'*50,'*'*50)
if self.verbose: print '{0!s}\nCalculating J(v)\n{1!s}'.format('*'*50, '*'*50)
self.curModel = m
if f is None:
f = self.fields(m)
p = self.Gvec(m, v, f)
y = self.solveAh(m, p)
Jv = self.survey.evalDeriv(f, v=y)
if self.verbose: print '%s\nDone calculating J(v)\n%s'%('*'*50,'*'*50)
if self.verbose: print '{0!s}\nDone calculating J(v)\n{1!s}'.format('*'*50, '*'*50)
return - mkvc(Jv)
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)
@@ -148,7 +148,7 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
* Compute \\\(\\\\vec{w} = -\\\mathbf{G}^\\\\top y\\\)
"""
if self.verbose: print '%s\nCalculating J^T(v)\n%s'%('*'*50,'*'*50)
if self.verbose: print '{0!s}\nCalculating J^T(v)\n{1!s}'.format('*'*50, '*'*50)
self.curModel = m
if f is None:
f = self.fields(m)
@@ -159,6 +159,6 @@ class BaseTDEMProblem(BaseTimeProblem, BaseEMProblem):
p = self.survey.evalDeriv(f, v=v, adjoint=True)
y = self.solveAht(m, p)
w = self.Gtvec(m, y, f)
if self.verbose: print '%s\nDone calculating J^T(v)\n%s'%('*'*50,'*'*50)
if self.verbose: print '{0!s}\nDone calculating J^T(v)\n{1!s}'.format('*'*50, '*'*50)
return - mkvc(w)
+6 -6
View File
@@ -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
View File
@@ -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
+19 -14
View File
@@ -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)
print ' Fetching {0!s} problem'.format((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()
@@ -89,8 +94,8 @@ 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)
print 'Cross Checking Forward: {0!s}, {1!s} formulations - {2!s}'.format(fdemType1, fdemType2, comp)
logsig = np.log(np.ones(mesh.nC)*CONDUCTIVITY)
mu = np.ones(mesh.nC)*MU
+1
View File
@@ -1,5 +1,6 @@
import TDEM
import FDEM
import Static
import Base
import Analytics
import Utils
+7 -7
View File
@@ -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()
+15 -17
View File
@@ -2,7 +2,7 @@ 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', dtype='appc', plotIt=True):
def run(loc=None, sig=None, radi=None, param=None, surveyType='dipole-dipole', unitType='appConductivity', plotIt=True):
"""
DC Forward Simulation
=====================
@@ -15,14 +15,14 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p
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]
stype = survey type "pdp" (pole dipole) or "dpdp" (dipole dipole)
dtype = Data type "appr" (app res) | "appc" (app cond) | "volt" (potential)
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 dtype in ['appr', 'appc', 'volt'], "Data type (dtype) must be appr (app res) or appc (app cond) or volt (potential)"
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.]]
@@ -73,8 +73,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p
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) )
@@ -118,8 +118,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p
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
@@ -157,12 +157,12 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p
fig = plt.figure(figsize=(7,7))
ax = plt.subplot(2,1,1, aspect='equal')
# 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)
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',
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')
@@ -188,15 +188,13 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', dtype='appc', p
ax2 = plt.subplot(2,1,2, aspect='equal')
# 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)
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
dat = DC.plot_pseudoSection(survey2D,ax2,stype=stype, dtype = dtype)
# 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')
ax2.set_title('Apparent Conductivity data')
+3 -3
View File
@@ -42,8 +42,8 @@ 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.])
@@ -51,7 +51,7 @@ def run(plotIt=True):
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
@@ -19,10 +19,13 @@ def run(plotIt=True):
Morrison Casing Model, and the results are used in a 2016 SEG abstract by
Yang et al.
- Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686.
.. 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
@@ -107,7 +110,7 @@ def run(plotIt=True):
# 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 'Mesh Extent xmax: {0:f},: zmin: {1:f}, zmax: {2:f}'.format(mesh.vectorCCx.max(), mesh.vectorCCz.min(), mesh.vectorCCz.max())
print 'Number of cells', mesh.nC
if plotIt is True:
@@ -215,7 +218,7 @@ def run(plotIt=True):
# ------------ Problem and Survey ---------------
survey = FDEM.Survey(sg_p + dg_p)
mapping = [('sigma', Maps.IdentityMap(mesh))]
problem = FDEM.Problem_h(mesh, mapping=mapping)
problem = FDEM.Problem3D_h(mesh, mapping=mapping, Solver=solver)
problem.pair(survey)
# ------------- Solve ---------------------------
+16 -46
View File
@@ -1,7 +1,7 @@
from SimPEG import *
def run(N=200, plotIt=True):
def run(N=100, plotIt=True):
"""
Inversion: Linear Problem
=========================
@@ -18,6 +18,8 @@ def run(N=200, plotIt=True):
mesh = Mesh.TensorMesh([N])
m0 = np.ones(mesh.nC) * 1e-4
mref = np.zeros(mesh.nC)
nk = 10
jk = np.linspace(1.,nk,nk)
p = -2.
@@ -40,67 +42,35 @@ def run(N=200, plotIt=True):
survey = Survey.LinearSurvey()
survey.pair(prob)
survey.dobs = prob.fields(mtrue) + std_noise * np.random.randn(nk)
#survey.makeSyntheticData(mtrue, std=std_noise)
wd = np.ones(nk) * std_noise
#print survey.std[0]
#M = prob.mesh
# Distance weighting
wr = np.sum(prob.G**2.,axis=0)**0.5
wr = ( wr/np.max(wr) )
reg = Regularization.Simple(mesh)
reg.wght = wr
dmis = DataMisfit.l2_DataMisfit(survey)
dmis.Wd = 1./wd
opt = Optimization.ProjectedGNCG(maxIter=30,lower=-2.,upper=2., maxIterCG= 20, tolCG = 1e-4)
invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
invProb.curModel = m0
beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1)
target = Directives.TargetMisfit()
betaest = Directives.BetaEstimate_ByEig()
inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target])
mrec = inv.run(m0)
ml2 = mrec
print "Final misfit:" + str(invProb.dmisfit.eval(mrec))
# Switch regularization to sparse
phim = invProb.phi_m_last
phid = invProb.phi_d
reg = Regularization.Sparse(mesh)
reg.mref = mref
reg.cell_weights = wr
#==============================================================================
# fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2))
# dmdx = reg.mesh.cellDiffxStencil * mrec
# plt.plot(np.sort(dmdx))
#==============================================================================
#reg.recModel = mrec
reg.wght = np.ones(mesh.nC)
reg.mref = np.zeros(mesh.nC)
reg.eps_p = 5e-2
reg.eps_q = 1e-2
reg.norms = [0., 0., 2., 2.]
reg.wght = wr
opt = Optimization.ProjectedGNCG(maxIter=10 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 20, tolCG = 1e-3)
invProb = InvProblem.BaseInvProblem(dmis, reg, opt, beta = invProb.beta*2.)
beta = Directives.BetaSchedule(coolingFactor=1, coolingRate=1)
#betaest = Directives.BetaEstimate_ByEig()
target = Directives.TargetMisfit()
IRLS =Directives.Update_IRLS( phi_m_last = phim, phi_d_last = phid )
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=[beta,IRLS])
m0 = mrec
inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest,update_Jacobi])
# Run inversion
mrec = inv.run(m0)
@@ -117,7 +87,7 @@ def run(N=200, plotIt=True):
axes[0].set_title('Columns of matrix G')
axes[1].plot(mesh.vectorCCx, mtrue, 'b-')
axes[1].plot(mesh.vectorCCx, ml2, 'r-')
axes[1].plot(mesh.vectorCCx, reg.l2model, 'r-')
#axes[1].legend(('True Model', 'Recovered Model'))
axes[1].set_ylim(-1.0,1.25)
+3 -3
View File
@@ -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')
@@ -1,427 +0,0 @@
from scipy.constants import epsilon_0, mu_0
import matplotlib.pyplot as plt
import numpy as np
from SimPEG.EM.Utils import k, omega
"""
MT1D: n layered earth problem
*****************************
Author: Thibaut Astic
Contact: thast@eos.ubc.ca
This code compute the analytic response of a n-layered Earth to a plane wave (Magneto-Tellurics).
We start by looking at Maxwell's equations in the electric
field \\\(\\\mathbf{E}\\) and the magnetic flux
\\\(\\\mathbf{H}\\) to write the wave equations
\\(\\ \nabla ^2 \mathbf{E_x} + k^2 \mathbf{E_x} = 0 \\) &
\\(\\ \nabla ^2 \mathbf{H_y} + k^2 \mathbf{H_y} = 0 \\)
Then solving the equations in each layer "j" between z_{j-1} and z_j in the form of
\\(\\ E_{x,j} (z) = U_j e^{i k (z-z_{j-1})} + D_j e^{-i k (z-z_{j-1})} \\)
\\(\\ H_{y,j} (z) = \frac{1}{Z_j} (D_j e^{-i k (z-z_{j-1})} - U_j e^{i k (z-z_{j-1})}) \\)
With U and D the Up and Down components of the E-field.
The iteration from one layer to another is ensure by:
\\(\\ \left(\begin{matrix} E_{x,j} \\ H_{y,j} \end{matrix} \right) =
P_j T_j P^{-1}_J \left(\begin{matrix} E_{x,j+1} \\ H_{y,j+1} \end{matrix} \right) \\)
And the Boundary Condition is set for the E-field in the last layer, with no Up component (=0)
and only a down component (=1 then normalized by the highest amplitude to ensure numeric stability)
The layer 0 is assumed to be the air layer.
"""
#Define a frquency range for a survey
frange = lambda minfreq, maxfreq, step: np.logspace(minfreq,maxfreq,num = step, base = 10.)
#Functions to create random physical Properties for a n-layered earth
thick = lambda minthick, maxthick, nlayer: np.append(np.array([1.2*10.**5]),
np.ndarray.round(minthick + (maxthick-minthick)* np.random.rand(nlayer-1,1)
,decimals =1))
sig = lambda minsig, maxsig, nlayer: np.append(np.array([0.]),
np.ndarray.round(10.**minsig + (10.**maxsig-10.**minsig)* np.random.rand(nlayer,1)
,decimals=3))
mu = lambda minmu, maxmu, nlayer: np.append(np.array([1.]),
np.ndarray.round(minmu + (maxmu-minmu)* np.random.rand(nlayer,1)
,decimals=1))
eps = lambda mineps, maxeps, nlayer: np.append(np.array([1.]),
np.ndarray.round(mineps + (maxeps-mineps)* np.random.rand(nlayer,1)
,decimals=1))
#Evaluate Impedance Z of a layer
ImpZ = lambda f, mu, k: omega(f)*mu*mu_0/k
#Complex Cole-Cole Conductivity - EM utils
PCC= lambda siginf,m,t,c,f: siginf*(1.-(m/(1.+(1j*omega(f)*t)**c)))
#Converted thickness array into top of layer array
top = lambda thick: np.cumsum(thick)
#Propagation Matrix and theirs inverses
#matrix T for transition of Up and Down components accross a layer
T = lambda h,k: np.matrix([[np.exp(1j*k*h),0.],[0.,np.exp(-1j*k*h)]],dtype='complex_')
Tinv = lambda h,k: np.matrix([[np.exp(-1j*k*h),0.],[0.,np.exp(1j*k*h)]],dtype='complex_')
#transition of Up and Down components accross a layer
UD_Z = lambda UD,z,zj,k : T((z-zj),k)*UD
#matrix P relating Up and Down components with E and H fields
P = lambda z: np.matrix([[1.,1,],[-1./z,1./z]],dtype='complex_')
Pinv = lambda z: np.matrix([[1.,-z],[1.,z]],dtype='complex_')/2.
#Time Variation of E and H
E_ZT = lambda U,D,f,t : np.exp(1j*omega(f)*t)*(U+D)
H_ZT = lambda U,D,Z,f,t : (1./Z)*np.exp(1j*omega(f)*t)*(D-U)
#Plot the configuration of the problem
def PlotConfiguration(thick,sig,eps,mu,ax,widthg,z):
topn = top(thick)
widthn = np.arange(-widthg,widthg+widthg/10.,widthg/10.)
ax.set_ylim([z.min(),z.max()])
ax.set_xlim([-widthg,widthg])
ax.set_ylabel("Depth (m)", fontsize=16.)
ax.yaxis.tick_right()
ax.yaxis.set_label_position("right")
#define filling for the different layers
hatches=['/' , '+', 'x', '|' , '\\', '-' , 'o' , 'O' , '.' , '*' ]
#Write the physical properties of air
ax.annotate(("Air, $\sigma$ =%1.0f mS/m")%(sig[0]*10**(3)),
xy=(-widthg/2., -np.abs(z.max())/2.), xycoords='data',
xytext=(-widthg/2., -np.abs(z.max())/2.), textcoords='data',
fontsize=14.)
ax.annotate(("$\epsilon_r$= %1i")%(eps[0]),
xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data',
xytext=(-widthg/2., -np.abs(z.max())/3.), textcoords='data',
fontsize=14.)
ax.annotate(("$\mu_r$= %1i")%(mu[0]),
xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data',
xytext=(0, -np.abs(z.max())/3.), textcoords='data',
fontsize=14.)
#Write the physical properties of the differents layers up to the (n-1)-th and fill it with pattern
for i in range(1,len(topn)-1,1):
if topn[i] == topn[i+1]:
pass
else:
ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[i]*10**(3)),
xy=(0., (2.*topn[i]+topn[i+1])/3), xycoords='data',
xytext=(0., (2.*topn[i]+topn[i+1])/3), textcoords='data',
fontsize=14.)
ax.annotate(("$\epsilon_r$= %1i")%(eps[i]),
xy=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), xycoords='data',
xytext=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), textcoords='data',
fontsize=14.)
ax.annotate(("$\mu_r$= %1.2f")%(mu[i]),
xy=(-widthg/2., (2.*topn[i]+topn[i+1])/3), xycoords='data',
xytext=(-widthg/2., (2.*topn[i]+topn[i+1])/3), textcoords='data',
fontsize=14.)
ax.plot(widthn,topn[i]*np.ones_like(widthn),color='black')
ax.fill_between(widthn,topn[i],topn[i+1],alpha=0.3,color="none",edgecolor='black', hatch=hatches[(i-1)%10])
#Write the physical properties of the n-th layer and fill it with pattern
ax.plot(widthn,topn[-1]*np.ones_like(widthn),color='black')
ax.fill_between(widthn,topn[-1],z.max(),alpha=0.3,color="none",edgecolor='black', hatch=hatches[(len(topn)-2)%10])
ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[-1]*10**(3)),
xy=(0., (2.*topn[-1]+z.max())/3), xycoords='data',
xytext=(0., (2.*topn[-1]+z.max())/3), textcoords='data',
fontsize=14.)
ax.annotate(("$\epsilon_r$= %1i")%(eps[-1]),
xy=(-widthg/1.1, (2.*topn[-1]+z.max())/3), xycoords='data',
xytext=(-widthg/1.1, (2.*topn[-1]+z.max())/3), textcoords='data',
fontsize=14.)
ax.annotate(("$\mu_r$= %1.2f")%(mu[-1]),
xy=(-widthg/2., (2.*topn[-1]+z.max())/3), xycoords='data',
xytext=(-widthg/2., (2.*topn[-1]+z.max())/3), textcoords='data',
fontsize=14.)
#plot Trees!
ax.annotate("",
xy=(widthg/2., -1.*z.max()/5.), xycoords='data',
xytext=(widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
)
ax.annotate("",
xy=(widthg/2., -3./4.*z.max()/5.), xycoords='data',
xytext=(widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
)
ax.annotate("",
xy=(widthg/2., -1./2.*z.max()/5.), xycoords='data',
xytext=(widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.2*widthg/2., -1.*z.max()/5.), xycoords='data',
xytext=(1.2*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.2*widthg/2., -3./4.*z.max()/5.), xycoords='data',
xytext=(1.2*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.2*widthg/2., -1./2.*z.max()/5.), xycoords='data',
xytext=(1.2*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.5*widthg/2., -1.*z.max()/5.), xycoords='data',
xytext=(1.5*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.5*widthg/2., -3./4.*z.max()/5.), xycoords='data',
xytext=(1.5*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.5*widthg/2., -1./2.*z.max()/5.), xycoords='data',
xytext=(1.5*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
)
ax.invert_yaxis()
return ax
#Propagate Up and Down component for a certain frequency & evaluate E and H field
def Propagate(f,H,sig,chg,taux,c,mu,eps,n):
sigcm = np.zeros_like(sig,dtype='complex_')
for j in range(1,len(sig)):
sigcm[j]=PCC(sig[j],chg[j],taux[j],c[j],f)
K = k(f, sigcm, mu, eps)
Z = ImpZ(f,mu,K)
EH = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_')
UD = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_')
UD[1,-1] = 1.
for i in range(-2,-(n+2),-1):
UD[:,i] = Tinv(H[i+1],K[i])*Pinv(Z[i])*P(Z[i+1])*UD[:,i+1]
UD = UD/((np.abs(UD[0,:]+UD[1,:])).max())
for j in range(0,n+1):
EH[:,j] = np.matrix([[1.,1,],[-1./Z[j],1./Z[j]]])*UD[:,j]
return UD, EH, Z ,K
#Evaluate the apparent resistivity and phase for a frequency range
def appres(F,H,sig,chg,taux,c,mu,eps,n):
Res = np.zeros_like(F)
Phase = np.zeros_like(F)
App_ImpZ= np.zeros_like(F,dtype='complex_')
for i in range(0,len(F)):
UD,EH,Z ,K = Propagate(F[i],H,sig,chg,taux,c,mu,eps,n)
App_ImpZ[i] = EH[0,1]/EH[1,1]
Res[i] = np.abs(App_ImpZ[i])**2./(mu_0*omega(F[i]))
Phase[i] = np.angle(App_ImpZ[i], deg = True)
return Res,Phase
#Evaluate Up, Down components, E and H field, for a frequency range,
#a discretized depth range and a time range (use to calculate envelope)
def calculateEHzt(F,H,sig,chg,taux,c,mu,eps,n,zsample,tsample):
topc = top(H)
layer = np.zeros(len(zsample),dtype=np.int)-1
Exzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
Hyzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
Uz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
Dz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
UDaux = np.matrix(np.zeros((2,len(zsample)),dtype = 'complex_'),dtype = 'complex_')
for i in range(0,n+1,1):
layer = layer+(zsample>=topc[i])*1
for j in range(0,len(F)):
UD,EH,Z ,K = Propagate(F[j],H,sig,chg,taux,c,mu,eps,n)
for p in range(0,len(zsample)):
UDaux[:,p] = UD_Z(UD[:,layer[p]],zsample[p],topc[layer[p]],K[layer[p]])
for q in range(0,len(tsample)):
Exzt[p,q] = Exzt[p,q] + E_ZT(UDaux[0,p],UDaux[1,p],F[j],tsample[q])/len(F)
Hyzt[p,q] = Hyzt[p,q] + H_ZT(UDaux[0,p],UDaux[1,p],Z[layer[p]],F[j],tsample[q])/len(F)
Uz[p,q] = Uz[p,q] + UDaux[0,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F)
Dz[p,q] = Dz[p,q] + UDaux[1,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F)
return Exzt,Hyzt,Uz,Dz,UDaux,layer
#Function to Plot Apparent Resistivity and Phase
def PlotAppRes(F,H,sig,chg,taux,c,mu,eps,n,fenvelope,PlotEnvelope):
Res, Phase = appres(F,H,sig,chg,taux,c,mu,eps,n)
fig,ax = plt.subplots(1,2,figsize=(16,10))
ax[0].scatter(Res,F,color='black')
ax[0].set_xscale('Log')
ax[0].set_yscale('Log')
ax[0].set_xlim([10.**(np.log10(Res.min())-1.),10.**(np.log10(Res.max())+1.)])
ax[0].set_ylim([F.min(),F.max()])
ax[0].set_xlabel('Apparent Resistivity (Ohm*m)',fontsize=16.,color="black")
ax[0].set_ylabel('Frequency (Hz)',fontsize=16.)
ax[0].grid(which='major')
ax0 = ax[0].twiny()
ax0.set_xlim([0.,90.])
ax0.set_ylim([F.min(),F.max()])
ax0.scatter(Phase,F,color='purple')
ax0.set_xlabel('Phase (Degrees)',fontsize=16.,color="purple")
zc=np.arange(-(H[1:].max()+10)*n,(H[1:].max()+10)*n,10.)
ax[0].tick_params(labelsize=16)
ax[1].tick_params(labelsize=16)
ax0.tick_params(labelsize=16)
if PlotEnvelope:
widthn=np.logspace(np.log10(Res.min())-1., np.log10(Res.max())+1., num=100, endpoint=True, base=10.0)
fenvelope1n=np.ones(100)*fenvelope
ax[0].plot(widthn,fenvelope1n,linestyle='dashed',color='black')
tc=np.arange(0.,1./fenvelope,0.01/(fenvelope))
Exzt,Hyzt,Uz,Dz,UDaux,layer = calculateEHzt(np.array([fenvelope]),H,sig,chg,taux,c,mu,eps,n,zc,tc)
ax1=ax[1].twiny()
ax[1].tick_params(labelsize=16)
ax1.tick_params(labelsize=16)
ax[1].set_xlabel('Amplitude Electric Field E (V/m)',color='blue',fontsize=16)
ax1.set_xlabel('Amplitude Magnetic Field H (A/m)',color='red',fontsize=16)
ax[1].fill_betweenx(zc,np.squeeze(np.asarray(np.real(Exzt.min(axis=1)))),
np.squeeze(np.asarray(np.real(Exzt.max(axis=1)))),
color='blue', alpha=0.1)
ax1.fill_betweenx(zc,np.squeeze(np.asarray(np.real(Hyzt.min(axis=1)))),
np.squeeze(np.asarray(np.real(Hyzt.max(axis=1)))),
color='red', alpha=0.1)
ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],(1.5*np.abs(Exzt).max()),zc)
ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()])
ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()])
else:
print 'No envelop (if True, might be slow)'
ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],1.,zc)
ax[1].get_xaxis().set_ticks([])
plt.show()
#Interactive MT for Notebook
def PlotAppRes3LayersInteract(h1,h2,sigl1,sigl2,sigl3,mul1,mul2,mul3,epsl1,epsl2,epsl3,PlotEnvelope,F_Envelope):
frangn=frange(-5,5,100.)
sig3= np.array([0.,0.001,0.1, 0.001])
thick3 = np.array([120000.,50.,50.])
eps3=np.array([1.,1.,1.,1])
mu3=np.array([1.,1.,1.,1])
chg3=np.array([0.,0.1,0.,0.2])
chg3_0=np.array([0.,0.1,0.,0.])
taux3=np.array([0.,0.1,0.,0.1])
c3=np.array([1.,1.,1.,1.])
sig3[1]=sigl1
sig3[1]=10.**sig3[1]
sig3[2]=sigl2
sig3[2]=10.**sig3[2]
sig3[3]=sigl3
sig3[3]=10.**sig3[3]
mu3[1]=mul1
mu3[2]=mul2
mu3[3]=mul3
eps3[1]=epsl1
eps3[2]=epsl2
eps3[3]=epsl3
thick3[1]=h1
thick3[2]=h2
PlotAppRes(frangn,thick3,sig3,chg3_0,taux3,c3,mu3,eps3,3,F_Envelope,PlotEnvelope)
def run(plotIt=True, n=3):
# something to make a plot
F = frange(-5.,5.,20)
H = thick(50.,100.,n)
sign = sig(-5.,0.,n)
mun = mu(1.,2.,n)
epsn = eps(1.,9.,n)
chg = np.zeros_like(sign)
taux = np.zeros_like(sign)
c = np.zeros_like(sign)
Res, Phase = appres(F,H,sign,chg,taux,c,mun,epsn,n)
if plotIt:
PlotAppRes(F, H, sign, chg, taux, c, mun, epsn, n, fenvelope=1000., PlotEnvelope=True)
return Res, Phase
if __name__ == '__main__':
run(plotIt=True)
+3 -4
View File
@@ -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
+62
View File
@@ -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()
+41
View File
@@ -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()
@@ -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()
@@ -98,7 +98,7 @@ def run(plotIt=True, n=60):
ii = int(ii)
out = M.plotImage(PHIS[ii][1],ax=ax)
ax.axis('off')
ax.set_title('Elapsed Time: %4.1f'%PHIS[ii][0])
ax.set_title('Elapsed Time: {0:4.1f}'.format(PHIS[ii][0]))
plt.show()
if __name__ == '__main__':
+3 -3
View File
@@ -29,15 +29,15 @@ def run(plotIt=True, n=60):
axes[0].set_ylim([-1,17])
for ii, loc in zip(range(M.nC),M.gridCC):
axes[0].text(loc[0]+0.2,loc[1],'%d'%ii, color='r')
axes[0].text(loc[0]+0.2,loc[1],'{0:d}'.format(ii), color='r')
axes[0].plot(M.gridFx[:,0],M.gridFx[:,1], 'g>')
for ii, loc in zip(range(M.nFx),M.gridFx):
axes[0].text(loc[0]+0.2,loc[1],'%d'%ii, color='g')
axes[0].text(loc[0]+0.2,loc[1],'{0:d}'.format(ii), color='g')
axes[0].plot(M.gridFy[:,0],M.gridFy[:,1], 'm^')
for ii, loc in zip(range(M.nFy),M.gridFy):
axes[0].text(loc[0]+0.2,loc[1]+0.2,'%d'%(ii+M.nFx), color='m')
axes[0].text(loc[0]+0.2,loc[1]+0.2,'{0:d}'.format((ii+M.nFx)), color='m')
axes[1].spy(M.faceDiv)
axes[1].set_title('Face Divergence')
+43
View File
@@ -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)
+15 -14
View File
@@ -8,9 +8,11 @@ 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,12 +20,11 @@ import Mesh_QuadTree_Creation
import Mesh_QuadTree_FaceDiv
import Mesh_QuadTree_HangingNodes
import Mesh_Tensor_Creation
import MT_1D_analytic_nlayer_Earth
import MT_1D_ForwardAndInversion
import MT_3D_Foward
import sphereElectrostatic_example
import Utils_surface2ind_topo
__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_Schenkel_Morrison_Casing", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_IRLS", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_analytic_nlayer_Earth", "MT_1D_ForwardAndInversion", "MT_3D_Foward", "sphereElectrostatic_example"]
__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 #####
@@ -39,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)
@@ -58,7 +59,7 @@ if __name__ == '__main__':
if line == "##### AUTOIMPORTS #####\n":
inimports = not inimports
if inimports:
out += '\n'.join(["import %s"%_ for _ in exfiles])
out += '\n'.join(["import {0!s}".format(_) for _ in exfiles])
out += '\n\n__examples__ = ["' + '", "'.join(exfiles)+ '"]\n'
out += '\n##### AUTOIMPORTS #####\n'
f.close()
@@ -75,11 +76,11 @@ if __name__ == '__main__':
docstr = runFunction.__doc__
if docstr is None:
doc = '%s\n%s'%(name.replace('_',' '),'='*len(name))
doc = '{0!s}\n{1!s}'.format(name.replace('_',' '), '='*len(name))
else:
doc = '\n'.join([_[8:].rstrip() for _ in docstr.split('\n')])
out = """.. _examples_%s:
out = """.. _examples_{0!s}:
.. --------------------------------- ..
.. ..
@@ -89,21 +90,21 @@ if __name__ == '__main__':
.. ..
.. --------------------------------- ..
%s
{1!s}
.. plot::
from SimPEG import Examples
Examples.%s.run()
Examples.{2!s}.run()
.. literalinclude:: ../../SimPEG/Examples/%s.py
.. literalinclude:: ../../../SimPEG/Examples/{3!s}.py
:language: python
:linenos:
"""%(name,doc,name,name)
""".format(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
print 'Creating: {0!s}.rst'.format(name)
f = open(rst, 'w')
f.write(out)
f.close()
@@ -1,785 +0,0 @@
from scipy.constants import epsilon_0
import matplotlib.pyplot as plt
import matplotlib.colors as colors
import numpy as np
from SimPEG.Utils import ndgrid, mkvc
'''
Authors: Thibaut Astic, Lindsey Heagy, Sanna Tyrvainen, Ronghua Peng
This code defines function to resolve analytically the electrostatic sphere problem.
We first define a problem configuration, with a conductive or resistive sphere in a
wholespace background.
We then calculate the potential, then the electric field, then the current density and
finally the charges accumulation.
Several plotting functions are defined for data visualisation.
'''
# Plot options
ftsize_title = 18 #font size for titles
ftsize_axis = 14 #font size for axis ticks
ftsize_label = 14 #font size for axis labels
# Radius function, useful sigma ratio, and log scale converter
r = lambda x,y,z: np.sqrt(x**2.+y**2.+z**2.)
sigf = lambda sig0,sig1: (sig1-sig0)/(sig1+2.*sig0)
#tools to convert log conductivity in conductivity
def conductivity_log_wrapper(log_sig0,log_sig1):
sig0 = 10.**log_sig0
sig1 = 10.**log_sig1
return sig0,sig1
# Examples
#Plot the configuration. Label=False is used to generate a general case figure
def get_Setup(XYZ,sig0,sig1,R,E0,ax,label,colorsphere):
'''
XYZ: ndgrid
sig0: conductivity of the background
sig1: conductivity of the sphere
R: radius of the sphere
E0: Amplitude of the uniform electrostatic field
ax: ax where to plot the configuration
label: True: plot real values, False: plot general case
colorsphere: color of the sphere, format [x,x,x]
'''
xplt = np.linspace(-R, R, num=100)
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
dx = xr[1]-xr[0]
top = np.sqrt(R**2-xplt**2)
bot = -np.sqrt(R**2-xplt**2)
if R != 0:
ax.plot(xplt, top, xplt, bot, color=colorsphere,linewidth=1.5)
ax.fill_between(xplt,bot,top,color=colorsphere,alpha=0.5 )
ax.arrow(0.,0.,np.sqrt(2.)*R/2.,np.sqrt(2.)*R/2.,head_width=0.,head_length=0.)
if label:
ax.annotate(("$\sigma_1$=%3.3f mS/m")%(sig1*10.**(3.)),
xy=(0.,-R/2.), xycoords='data',
xytext=(0.,-R/2.), textcoords='data',
fontsize=14.)
ax.annotate(("$\sigma_0$= %3.3f mS/m")%(sig0*10.**(3.)),
xy=(0.,-1.5*R), xycoords='data',
xytext=(0.,-1.5*R), textcoords='data',
fontsize=14.)
ax.annotate(('$\mathbf{E_0} = %1i \mathbf{\hat{x}}$ V/m')%(E0),
xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data',
xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data',
fontsize=14.)
ax.annotate(('$R$ = %1i m')%(R),
xy=(R/4.+(xr[1]-xr[0]),R/4.), xycoords='data',
xytext=(R/4.+(xr[1]-xr[0]),R/4.), textcoords='data',
fontsize=14.)
ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label)
ax.tick_params(labelsize=ftsize_axis)
else:
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.text(-1.,-np.sqrt(R)/2.-10.,'$\sigma_1$',fontsize=14)
ax.text(-0.05,-R-10,'$\sigma_0$',fontsize=14)
ax.annotate(('$\mathbf{E_0} = E_0 \mathbf{\hat{x}}$ V/m'),
xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data',
xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data',
fontsize=14.)
ax.annotate(('$R$'),
xy=(R/4.+(xr[1]-xr[0]),R/4.), xycoords='data',
xytext=(R/4.+(xr[1]-xr[0]),R/4.), textcoords='data',
fontsize=14.)
ax.set_xlabel('x',fontsize=12)
ax.set_ylabel('y',fontsize=12)
else:
if label:
ax.annotate(("$\sigma_0$= %3.3f mS/m")%(sig0*10.**(3.)),
xy=(0.,-1.5*R), xycoords='data',
xytext=(0.,-1.5*R), textcoords='data',
fontsize=14.)
ax.annotate(('$\mathbf{E_0} = %1i \mathbf{\hat{x}}$ V/m')%(E0),
xy=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), xycoords='data',
xytext=(xr.min()+np.abs(xr.max()-xr.min())/20.,0), textcoords='data',
fontsize=14.)
ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label)
ax.tick_params(labelsize=ftsize_axis)
else:
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.text(-0.05,-10,'$\sigma_0$',fontsize=14)
ax.text(xr.min()+np.abs(xr.max()-xr.min())/20., 0, '$\mathbf{E_0} = E_0 \mathbf{\hat{x}}$ V/m', fontsize=14)
ax.set_xlabel('x',fontsize=12)
ax.set_ylabel('y',fontsize=12)
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
[ax.arrow(xr.min(),_,np.abs(xr.max()-xr.min())/20.,0.,head_width=5.,head_length=2.,color='k') for _ in np.linspace(yr.min(),yr.max(),num=10)]
ax.patch.set_facecolor([0.4,0.7,0.4])
ax.patch.set_alpha(0.2)
ax.set_aspect('equal')
return ax
def get_Conductivity(XYZ,sig0,sig1,R):
'''
Define the conductivity for each point of the space
'''
x,y,z = XYZ[:,0],XYZ[:,1],XYZ[:,2]
r_view=r(x,y,z)
ind0= (r_view>R)
ind1= (r_view<=R)
assert (ind0 + ind1).all(), 'Some indicies not included'
Sigma = np.zeros_like(x)
Sigma[ind0] = sig0
Sigma[ind1] = sig1
return Sigma
def get_Potential(XYZ,sig0,sig1,R,E0):
'''
Function that returns the total, the primary and the secondary potentials, assumes an x-oriented inducing field and that the sphere is at the origin
:input: grid, outer sigma, inner sigma, radius of the sphere, strength of the electric field
'''
x,y,z = XYZ[:,0],XYZ[:,1],XYZ[:,2]
sig_cur = sigf(sig0,sig1)
r_cur = r(x,y,z) # current radius
ind0 = (r_cur > R)
ind1 = (r_cur <= R)
assert (ind0 + ind1).all(), 'Some indicies not included'
Vt = np.zeros_like(x)
Vp = np.zeros_like(x)
Vs = np.zeros_like(x)
Vt[ind0] = -E0*x[ind0]*(1.-sig_cur*R**3./r_cur[ind0]**3.) # total potential outside the sphere
Vt[ind1] = -E0*x[ind1]*3.*sig0/(sig1+2.*sig0) # inside the sphere
Vp = - E0*x # primary potential
Vs = Vt - Vp # secondary potential
return Vt,Vp,Vs
#plot the primary potential on ax
def Plot_Primary_Potential(XYZ,Vp,R,ax):
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
xcirc = xr[np.abs(xr) <= R]
Pplot = ax.pcolor(xr,yr,Vp.reshape(xr.size,yr.size))
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.set_title('Primary Potential',fontsize=ftsize_title)
cb = plt.colorbar(Pplot,ax=ax)
cb.set_label(label= 'Potential ($V$)',size=ftsize_label)
cb.ax.tick_params(labelsize=ftsize_axis)
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label)
ax.set_aspect('equal')
ax.tick_params(labelsize=ftsize_axis)
return ax
#plot the total potential on ax
def Plot_Total_Potential(XYZ,Vt,R,ax):
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
xcirc = xr[np.abs(xr) <= R]
Pplot = ax.pcolor(xr,yr,Vt.reshape(xr.size,yr.size))
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.set_title('Total Potential',fontsize=ftsize_title)
cb = plt.colorbar(Pplot,ax=ax)
cb.set_label(label= 'Potential ($V$)',size=ftsize_label)
cb.ax.tick_params(labelsize=ftsize_axis)
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label)
ax.set_aspect('equal')
ax.tick_params(labelsize=ftsize_axis)
return ax
#plot the secondary potential on ax
def Plot_Secondary_Potential(XYZ,Vs,R,ax):
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
xcirc = xr[np.abs(xr) <= R]
Pplot = ax.pcolor(xr,yr,Vs.reshape(xr.size,yr.size))
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.set_title('Secondary Potential',fontsize=ftsize_title)
cb = plt.colorbar(Pplot,ax=ax)
cb.set_label(label= 'Potential ($V$)',size=ftsize_label)
cb.ax.tick_params(labelsize=ftsize_axis)
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label)
ax.set_aspect('equal')
ax.tick_params(labelsize=ftsize_axis)
return ax
def get_ElectricField(XYZ,sig0,sig1,R,E0):
'''
Function that returns the total, the primary and the secondary electric fields,
input: grid, outer sigma, inner sigma, radius of the sphere, strength of the electric field
'''
x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2]
r_cur=r(x,y,z) # current radius
ind0= (r_cur>R)
ind1= (r_cur<=R)
assert (ind0 + ind1).all(), 'Some indicies not included'
Ep = np.zeros(shape=(len(x),3))
Ep[:,0] = E0
Et = np.zeros(shape=(len(x),3))
Et[ind0,0] = E0 + E0*R**3./(r_cur[ind0]**5.)*sigf(sig0,sig1)*(2.*x[ind0]**2.-y[ind0]**2.-z[ind0]**2.);
Et[ind0,1] = E0*R**3./(r_cur[ind0]**5.)*3.*x[ind0]*y[ind0]*sigf(sig0,sig1);
Et[ind0,2] = E0*R**3./(r_cur[ind0]**5.)*3.*x[ind0]*z[ind0]*sigf(sig0,sig1);
Et[ind1,0] = 3.*sig0/(sig1+2.*sig0)*E0;
Et[ind1,1] = 0.;
Et[ind1,2] = 0.;
Es = Et - Ep
return Et, Ep, Es
#plot the total electric field on ax
def Plot_Total_ElectricField(XYZ,Et,R,ax):
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
xcirc = xr[np.abs(xr) <= R]
EtXr = Et[:,0].reshape(xr.size, yr.size)
EtYr = Et[:,1].reshape(xr.size, yr.size)
EtAmp = np.sqrt(Et[:,0]**2+Et[:,1]**2 + Et[:,2]**2).reshape(xr.size, yr.size)
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label)
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.tick_params(labelsize=ftsize_axis)
ax.set_aspect('equal')
Eplot = ax.pcolor(xr,yr,EtAmp)
cb = plt.colorbar(Eplot,ax=ax)
cb.set_label(label= 'Amplitude ($V/m$)',size=ftsize_label) #weight='bold')
cb.ax.tick_params(labelsize=ftsize_axis)
ax.streamplot(xr,yr,EtXr,EtYr,color='gray',linewidth=2.,density=0.75)#angles='xy',scale_units='xy',scale=0.05)
ax.set_title('Total Field',fontsize=ftsize_title)
return ax
#plot the secondary electric field on ax
def Plot_Secondary_ElectricField(XYZ,Es,R,ax):
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
xcirc = xr[np.abs(xr) <= R]
EsXr = Es[:,0].reshape(xr.size, yr.size)
EsYr = Es[:,1].reshape(xr.size, yr.size)
EsAmp = np.sqrt(Es[:,0]**2+Es[:,1]**2+Es[:,2]**2).reshape(xr.size, yr.size)
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
ax.set_ylabel('Y coordinate ($m$)',fontsize = ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize = ftsize_label)
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.tick_params(labelsize=ftsize_axis)
ax.set_aspect('equal')
Eplot = ax.pcolor(xr,yr,EsAmp)
cb = plt.colorbar(Eplot,ax=ax)
cb.set_label(label= 'Amplitude ($V/m$)',size=ftsize_label) #weight='bold')
cb.ax.tick_params(labelsize=ftsize_axis)
ax.streamplot(xr,yr,EsXr,EsYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=0.05)
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.set_title('Secondary Field',fontsize=ftsize_title)
return ax
def get_Current(XYZ,sig0,sig1,R,Et,Ep,Es):
'''
Function that returns the total, the primary and the secondary current densities,
:input: grid, outer sigma, inner sigma, radius of the sphere, total, the primary and the seconadry electric fields,
'''
x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2]
r_cur=r(x,y,z)
ind0= (r_cur>R)
ind1= (r_cur<=R)
assert (ind0 + ind1).all(), 'Some indicies not included'
Jt = np.zeros(shape=(len(x),3))
J0 = np.zeros(shape=(len(x),3))
Js = np.zeros(shape=(len(x),3))
Jp = sig0*Ep
Jt[ind0,:] = sig0*Et[ind0,:]
Jt[ind1,:] = sig1*Et[ind1,:]
Js[ind0,:] = sig0*(Et[ind0,:]-Ep[ind0,:])
Js[ind1,:] = sig1*Et[ind1,:]-sig0*Ep[ind1,:]
return Jt,Jp,Js
#plot the total currents density on ax
def Plot_Total_Currents(XYZ,Jt,R,ax):
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
xcirc = xr[np.abs(xr) <= R]
JtXr = Jt[:,0].reshape(xr.size, yr.size)
JtYr = Jt[:,1].reshape(xr.size, yr.size)
JtAmp = np.sqrt(Jt[:,0]**2+Jt[:,1]**2+Jt[:,2]**2).reshape(xr.size, yr.size)
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label)
ax.tick_params(labelsize=ftsize_axis)
ax.set_aspect('equal')
Jplot = ax.pcolor(xr,yr,JtAmp.reshape(xr.size,yr.size))
cb = plt.colorbar(Jplot,ax=ax)
cb.set_label(label= 'Current Density ($A/m^2$)',size=ftsize_label) #weight='bold')
cb.ax.tick_params(labelsize=ftsize_axis)
ax.streamplot(xr,yr,JtXr,JtYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=1)
ax.set_title('Total Current Density',fontsize=ftsize_title)
return ax
#plot the secondary currents density on ax
def Plot_Secondary_Currents(XYZ,Js,R,ax):
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
xcirc = xr[np.abs(xr) <= R]
JsXr = Js[:,0].reshape(xr.size, yr.size)
JsYr = Js[:,1].reshape(xr.size, yr.size)
JsAmp = np.sqrt(Js[:,1]**2+Js[:,0]**2+Js[:,2]**2).reshape(xr.size,yr.size)
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label)
ax.tick_params(labelsize=ftsize_axis)
ax.set_aspect('equal')
Jplot = ax.pcolor(xr,yr,JsAmp.reshape(xr.size,yr.size))
cb = plt.colorbar(Jplot,ax=ax)
cb.set_label(label= 'Current Density ($A/m^2$)',size=ftsize_label) #weight='bold')
cb.ax.tick_params(labelsize=ftsize_axis)
ax.streamplot(xr,yr,JsXr,JsYr,color='gray',linewidth=2.,density=0.75)#,angles='xy',scale_units='xy',scale=1)
ax.set_title('Secondary Current Density',fontsize=ftsize_title)
return ax
def get_ChargesDensity(XYZ,sig0,sig1,R,Ep):
'''
Function that returns the charges accumulation at the background/sphere interface,
:input: grid, outer sigma, inner sigma, radius of the sphere, total and the primary electric fields,
'''
x,y,z= XYZ[:,0], XYZ[:,1], XYZ[:,2]
dx = x[1]-x[0]
r_cur=r(x,y,z)
ind0 = (r_cur > R)
ind1 = (r_cur < R)
ind2 = ((r_cur < (R+dx/2)) & (r_cur > (R-dx/2)) )
assert (ind0 + ind1 + ind2).all(), 'Some indicies not included'
rho = np.zeros_like(x)
rho[ind0] = 0
rho[ind1] = 0
rho[ind2] = epsilon_0*3.*Ep[ind2,0]*sigf(sig0,sig1)*x[ind2]/(np.sqrt(x[ind2]**2.+y[ind2]**2.))
return rho
#Plot charges density on ax
def Plot_ChargesDensity(XYZ,rho,R,ax):
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
xcirc = xr[np.abs(xr) <= R]
ax.set_xlim([xr.min(),xr.max()])
ax.set_ylim([yr.min(),yr.max()])
ax.set_aspect('equal')
Cplot = ax.pcolor(xr,yr,rho.reshape(xr.size, yr.size))
cb1 = plt.colorbar(Cplot,ax=ax)
cb1.set_label(label= 'Charge Density ($C/m^2$)',size=ftsize_label) #weight='bold')
cb1.ax.tick_params(labelsize=ftsize_axis)
ax.plot(xcirc,np.sqrt(R**2-xcirc**2),'--k',xcirc,-np.sqrt(R**2-xcirc**2),'--k')
ax.set_ylabel('Y coordinate ($m$)',fontsize=ftsize_label)
ax.set_xlabel('X coordinate ($m$)',fontsize=ftsize_label)
ax.tick_params(labelsize=ftsize_axis)
ax.set_title('Charges Density', fontsize=ftsize_title)
return ax
def MN_Potential_total(sig0,sig1,R,E0,start,end,nbmp,mn):
'''
Function that return array of midpoints electrodes, electrodes positions,
potentials differences for total and secondary potentials fields, unormalized and
normalized to electrodes distances.
sig0: background conductivity
sig1: sphere conductivity
R: Sphere's radius
E0: uniform E field value
start: start point for the profile start.shape = (2,)
end: end point for the profile end.shape = (2,)
nbmp: number of dipoles
mn: Space between the M and N electrodes
'''
#D: total distance from start to end
D = np.sqrt((start[0]-end[0])**2.+(start[1]-end[1])**2.)
#MP: dipoles'midpoint positions (x,y)
MP = np.zeros(shape=(nbmp,2))
MP[:,0] = np.linspace(start[0],end[0],nbmp)
MP[:,1] = np.linspace(start[1],end[1],nbmp)
#Dipoles'Electrodes positions around each midpoints
EL = np.zeros(shape=(2*nbmp,2))
for n in range(0,len(EL),2):
EL[n,0] = MP[n/2,0] - ((end[0]-start[0])/D)*mn/2.
EL[n+1,0] = MP[n/2,0] + ((end[0]-start[0])/D)*mn/2.
EL[n,1] = MP[n/2,1] - ((end[1]-start[1])/D)*mn/2.
EL[n+1,1] = MP[n/2,1] + ((end[1]-start[1])/D)*mn/2.
VtEL = np.zeros(2*nbmp) #Total Potential (Vt-) at each electrode (-EL)
VsEL = np.zeros(2*nbmp) #Secondary Potential (Vt-) at each electrode (-EL)
dVtMP = np.zeros(nbmp) #Diffence (d-) of Total Potential (Vt-) at each dipole (-MP)
dVtMPn = np.zeros(nbmp) #Diffence (d-) of Total Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n)
dVsMP = np.zeros(nbmp) #Diffence (d-) of Secondaty Potential (Vt-) at each dipole (-MP)
dVsMPn = np.zeros(nbmp) #Diffence (d-) of Secondary Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n)
dVpMP = np.zeros(nbmp) #Diffence (d-) of Primary Potential (Vt-) at each dipole (-MP)
dVpMPn = np.zeros(nbmp) #Diffence (d-) of Primary Potential (Vt-) at each dipole (-MP) normalized for the mn spacing (n)
#Computing VtEL
for m in range(0,2*nbmp):
if (r(EL[m,0],EL[m,1],0) > R):
VtEL[m] = -E0*EL[m,0]*(1.-sigf(sig0,sig1)*R**3./r(EL[m,0],EL[m,1],0)**3.)
else:
VtEL[m] = -E0*EL[m,0]*3.*sig0/(sig1+2.*sig0)
#Computing VsEL
VsEL = VtEL + E0*EL[:,0]
#Computing dVtMP, dVsMP
for p in range(0,nbmp):
dVtMP[p] = VtEL[2*p]-VtEL[2*p+1]
dVtMPn[p] = dVtMP[p]/mn
dVsMP[p] = VsEL[2*p]-VsEL[2*p+1]
dVsMPn[p] = dVsMP[p]/mn
return MP,EL,dVtMP,dVtMPn,dVsMP,dVsMPn
#Compare the DC response of two configurations
def two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,nb_dipole,electrode_spacing,PlotOpt):#,linearcolor):
#Define the mesh
xr,yr,zr = np.unique(XYZ[:,0]),np.unique(XYZ[:,1]),np.unique(XYZ[:,2])
#Defining the Profile
start = np.array([xstart,ystart])
end = np.array([xend,yend])
#Calculating the data from the defined survey line for Configuration 0 and 1
MP0,EL0,VtdMP0,VtdMPn0,VsdMP0,VsdMPn0 = MN_Potential_total(sig0,sig1,R0,E0,start,end,nb_dipole,electrode_spacing)
MP1,EL1,VtdMP1,VtdMPn1,VsdMP1,VsdMPn1 = MN_Potential_total(sig0,sig2,R1,E0,start,end,nb_dipole,electrode_spacing)
# Initializing the figure
fig = plt.figure(figsize=(20,20))
ax0 = plt.subplot2grid((20,12), (0, 0),colspan=6,rowspan=6)
ax1 = plt.subplot2grid((20,12), (0, 6),colspan=6,rowspan=6)
ax2 = plt.subplot2grid((20,12), (16, 2), colspan=9,rowspan=4)
ax3 = plt.subplot2grid((20,12), (8, 0),colspan=6,rowspan=6)
ax4 = plt.subplot2grid((20,12), (8, 6),colspan=6,rowspan=6)
#Plotting the Configuration 0
ax0 = get_Setup(XYZ,sig0,sig1,R0,E0,ax0,True,[0.6,0.1,0.1])
#Plotting the Configuration 1
ax1 = get_Setup(XYZ,sig0,sig2,R1,E0,ax1,True,[0.1,0.1,0.6])
#Plotting the Data (Legends)
ax2.set_title('Potential Differences',fontsize=ftsize_title)
ax2.set_ylabel('Potential difference ($V$)',fontsize=ftsize_label)
ax2.set_xlabel('Distance from start point ($m$)',fontsize=ftsize_label)
ax2.tick_params(labelsize=ftsize_axis)
ax2.grid()
#Calculating the potential
Vt0,Vp0,Vs0 = get_Potential(XYZ,sig0,sig1,R0,E0)
Vt1,Vp1,Vs1 = get_Potential(XYZ,sig0,sig2,R1,E0)
if PlotOpt == 'Total':
ax3= Plot_Total_Potential(XYZ,Vt0,R0,ax3)
ax4= Plot_Total_Potential(XYZ,Vt1,R1,ax4)
#Plot the Data (from Configuration 0)
gphy0 = ax2.plot(np.sqrt((MP0[0,0]-MP0[:,0])**2+(MP0[:,1]-MP0[0,1])**2),VtdMP0
,marker='o',color='blue',linewidth=3.,label ='Left Model Response' )
#Plot the Data (from Configuration 1)
gphy1 = ax2.plot(np.sqrt((MP1[0,0]-MP1[:,0])**2+(MP1[:,1]-MP1[0,1])**2),VtdMP1
,marker='o',color='red',linewidth=2.,label ='Right Model Response' )
ax2.legend(('Left Model Response','Right Model Response'),loc=4)
elif PlotOpt == 'Secondary':
#plot the secondary potentials
ax3= Plot_Secondary_Potential(XYZ,Vt0,R0,ax3)
ax4= Plot_Secondary_Potential(XYZ,Vt1,R1,ax3)
#Plot the data(from configuration 0)
gphy0 = ax2.plot(np.sqrt((MP0[0,0]-MP0[:,0])**2+(MP0[:,1]-MP0[0,1])**2),VsdMP0,color='blue'
,marker='o',linewidth=3.,label ='Left Model Response' )
#Plot the Data (from Configuration 1)
gphy1 = ax2.plot(np.sqrt((MP1[0,0]-MP1[:,0])**2+(MP1[:,1]-MP1[0,1])**2),VsdMP1
,marker='o',color='red',linewidth=2.,label ='Right Model Response' )
ax2.legend(('Left Model Response','Right Model Response'),loc=4 )
else:
print('What dont you get? Total or Secondary?')
#Legends
ax3.plot(MP0[:,0],MP0[:,1],color='gray')
Dip_Midpoint0 = ax3.scatter(MP0[:,0],MP0[:,1],color='black')
Electrodes0 = ax3.scatter(EL0[:,0],EL0[:,1],color='red')
ax3.legend([Dip_Midpoint0,Electrodes0], ["Dipole Midpoint", "Electrodes"],scatterpoints=1)
ax4.plot(MP1[:,0],MP1[:,1],color='gray')
Dip_Midpoint1 = ax4.scatter(MP1[:,0],MP1[:,1],color='black')
Electrodes1 = ax4.scatter(EL1[:,0],EL1[:,1],color='red')
ax4.legend([Dip_Midpoint1,Electrodes1], ["Dipole Midpoint", "Electrodes"],scatterpoints=1)
return fig
#Function to visualise and compare any two meaningful plots for the sphere in a uniform backgound with an unifom Electric Field
def interact_conductiveSphere(R,log_sig0,log_sig1,Figure1a,Figure1b,Figure2a,Figure2b):
sig0,sig1 = conductivity_log_wrapper(log_sig0,log_sig1)
E0 = 1. # inducing field strength in V/m
n = 100 #level of discretisation
xr = np.linspace(-200., 200., n) # X-axis discretization
yr = xr.copy() # Y-axis discretization
zr = np.r_[0] # identical to saying `zr = np.array([0])`
XYZ = ndgrid(xr,yr,zr) # Space Definition
Et,Ep,Es = get_ElectricField(XYZ,sig0,sig1,R,E0)
fig, ax = plt.subplots(1,2,figsize=(18,6))
#Setup figure 1 with options Configuration, Total or Secondary,
#then Potential, ElectricField, Current Density or Charges Density
if Figure1a == 'Configuration':
ax[0] = get_Setup(XYZ,sig0,sig1,R,E0,ax[0],True,[0.1,0.1,0.6])
elif Figure1a == 'Total':
if Figure1b == 'Potential':
Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0)
ax[0] = Plot_Total_Potential(XYZ,Vt,R,ax[0])
elif Figure1b == 'ElectricField':
ax[0] = Plot_Total_ElectricField(XYZ,Et,R,ax[0])
elif Figure1b == 'CurrentDensity':
Jt,Jp,Js, = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es)
ax[0] = Plot_Total_Currents(XYZ,Jt,R,ax[0])
elif Figure1b == 'ChargesDensity':
rho = get_ChargesDensity(XYZ,sig0,sig1,R,Ep)
ax[0] = Plot_ChargesDensity(XYZ,rho,R,ax[0])
elif Figure1a == 'Secondary':
if Figure1b == 'Potential':
Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0)
ax[0] = Plot_Secondary_Potential(XYZ,Vs,R,ax[0])
elif Figure1b == 'ElectricField':
ax[0] = Plot_Secondary_ElectricField(XYZ,Es,R,ax[0])
elif Figure1b == 'CurrentDensity':
Jt,Jp,Js, = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es)
ax[0] = Plot_Secondary_Currents(XYZ,Js,R,ax[0])
elif Figure1b == 'ChargesDensity':
rho = get_ChargesDensity(XYZ,sig0,sig1,R,Ep)
ax[0] = Plot_ChargesDensity(XYZ,rho,R,ax[0])
if Figure1a== 'Configuration':
Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0)
ax[1] = Plot_Primary_Potential(XYZ,Vp,R,ax[1])
print 'While figure1 is plotting Configuration, figure2 plots the primary field'
elif Figure2a == 'Total':
if Figure2b == 'Potential':
Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0)
ax[0] = Plot_Total_Potential(XYZ,Vt,R,ax[1])
elif Figure2b == 'ElectricField':
ax[0] = Plot_Total_ElectricField(XYZ,Et,R,ax[1])
elif Figure2b == 'CurrentDensity':
Jt,Jp,Js, = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es)
ax[0] = Plot_Total_Currents(XYZ,Jt,R,ax[1])
elif Figure2b == 'ChargesDensity':
rho = get_ChargesDensity(XYZ,sig0,sig1,R,Ep)
ax[0] = Plot_ChargesDensity(XYZ,rho,R,ax[1])
elif Figure2a == 'Secondary':
if Figure2b == 'Potential':
Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0)
ax[0] = Plot_Secondary_Potential(XYZ,Vs,R,ax[1])
elif Figure2b == 'ElectricField':
ax[0] = Plot_Secondary_ElectricField(XYZ,Es,R,ax[1])
elif Figure2b == 'CurrentDensity':
Jt,Jp,Js, = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es)
ax[0] = Plot_Secondary_Currents(XYZ,Js,R,ax[1])
elif Figure2b == 'ChargesDensity':
rho = get_ChargesDensity(XYZ,sig0,sig1,R,Ep)
ax[0] = Plot_ChargesDensity(XYZ,rho,R,ax[1])
plt.tight_layout(True)
plt.show()
#Interactive Visualisation of the responses of two configurations to a (pseudo) DC resistivity survey
def interactive_two_configurations_comparison(log_sig0,log_sig1,log_sig2,R0,R1,xstart,ystart,xend,yend,dipole_number,electrode_spacing,matching_spheres_example):
sig0,sig1 = conductivity_log_wrapper(log_sig0,log_sig1)
sig2 = 10.**log_sig2
E0 = 1. # inducing field strength in V/m
n = 100 #level of discretisation
xr = np.linspace(-200., 200., n) # X-axis discretization
yr = xr.copy() # Y-axis discretization
zr = np.r_[0] # identical to saying `zr = np.array([0])`
XYZ = ndgrid(xr,yr,zr) # Space Definition
PlotOpt = 'Total'
if matching_spheres_example:
sig0 = 10.**(-3)
sig1 = 10.**(-2)
sig2 = 1.310344828 * 10**(-3)
R0 = 20.
R1 = 40.
two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,dipole_number,electrode_spacing,PlotOpt)
else:
two_configurations_comparison(XYZ,sig0,sig1,sig2,R0,R1,E0,xstart,ystart,xend,yend,dipole_number,electrode_spacing,PlotOpt)
plt.tight_layout(True)
plt.show()
def run(plotIt=True):
sig0 = -3. # conductivity of the wholespace
sig1 = -1. # conductivity of the sphere
sig0, sig1 = conductivity_log_wrapper(sig0,sig1)
R = 50. # radius of the sphere
E0 = 1. # inducing field strength
n = 100 #level of discretisation
xr = np.linspace(-2.*R, 2.*R, n) # X-axis discretization
yr = xr.copy() # Y-axis discretization
zr = np.r_[0] # identical to saying `zr = np.array([0])`
XYZ = ndgrid(xr,yr,zr) # Space Definition
Vt,Vp,Vs = get_Potential(XYZ,sig0,sig1,R,E0)
Et,Ep,Es = get_ElectricField(XYZ,sig0,sig1,R,E0)
Jt,Jp,Js, = get_Current(XYZ,sig0,sig1,R,Et,Ep,Es)
rho = get_ChargesDensity(XYZ,sig0,sig1,R,Ep)
if plotIt:
fig, ax = plt.subplots(2,5,figsize=(50,10))
ax[0,0] = get_Setup(XYZ,sig0,sig1,R,E0,ax[0,0],True,[0.6,0.1,0.1])
ax[1,0] = Plot_Primary_Potential(XYZ,Vp,R,ax[1,0])
ax[0,1] = Plot_Total_Potential(XYZ,Vt,R,ax[0,1])
ax[1,1] = Plot_Secondary_Potential(XYZ,Vs,R,ax[1,1])
ax[0,2] = Plot_Total_ElectricField(XYZ,Et,R,ax[0,2])
ax[1,2] = Plot_Secondary_ElectricField(XYZ,Es,R,ax[1,2])
ax[0,3] = Plot_Total_Currents(XYZ,Jt,R,ax[0,3])
ax[1,3] = Plot_Secondary_Currents(XYZ,Js,R,ax[1,3])
ax[0,4] = Plot_Primary_Potential(XYZ,Vp,R,ax[0,4])
ax[1,4] = Plot_ChargesDensity(XYZ,rho,R,ax[1,4])
plt.show()
if __name__ == '__main__':
run()
+3 -3
View File
@@ -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.
@@ -116,7 +116,7 @@ class RichardsMap(object):
ax.semilogx(self.k(h, m), h)
def _assertMatchesPair(self, pair):
assert isinstance(self, pair), "Mapping object must be an instance of a %s class."%(pair.__name__)
assert isinstance(self, pair), "Mapping object must be an instance of a {0!s} class.".format((pair.__name__))
+1 -1
View File
@@ -140,7 +140,7 @@ class RichardsProblem(Problem.BaseTimeProblem):
for ii, dt in enumerate(self.timeSteps):
bc = self.getBoundaryConditions(ii, u[ii])
u[ii+1] = self.rootFinder.root(lambda hn1m, return_g=True: self.getResidual(m, u[ii], hn1m, dt, bc, return_g=return_g), u[ii])
if self.debug: print "Solving Fields (%4d/%d - %3.1f%% Done) %d Iterations, %4.2f seconds"%(ii+1, self.nT, 100.0*(ii+1)/self.nT, self.rootFinder.iter, time.time() - tic)
if self.debug: print "Solving Fields ({0:4d}/{1:d} - {2:3.1f}% Done) {3:d} Iterations, {4:4.2f} seconds".format(ii+1, self.nT, 100.0*(ii+1)/self.nT, self.rootFinder.iter, time.time() - tic)
return u
@Utils.timeIt
+4 -4
View File
@@ -37,7 +37,7 @@ class Fields(object):
for f in self.knownFields:
loc =self.knownFields[f]
sz += np.array(self._storageShape(loc)).prod()*8.0/(1024**2)
return "%e MB"%sz
return "{0:e} MB".format(sz)
def _storageShape(self, loc):
nSrc = self.survey.nSrc
@@ -84,12 +84,12 @@ class Fields(object):
return
if accessType=='set' and name not in self.knownFields:
if name in self.aliasFields:
raise KeyError("Invalid field name (%s) for setter, you can't set an aliased property"%name)
raise KeyError("Invalid field name ({0!s}) for setter, you can't set an aliased property".format(name))
else:
raise KeyError('Invalid field name (%s) for setter'%name)
raise KeyError('Invalid field name ({0!s}) for setter'.format(name))
elif accessType=='get' and (name not in self.knownFields and name not in self.aliasFields):
raise KeyError('Invalid field name (%s) for getter'%name)
raise KeyError('Invalid field name ({0!s}) for getter'.format(name))
return name
def _indexAndNameFromKey(self, key, accessType):
+1 -1
View File
@@ -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
+2 -2
View File
@@ -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)
+6 -6
View File
@@ -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
+16 -91
View File
@@ -41,8 +41,8 @@ class IdentityMap(object):
If this is a meshless mapping (i.e. nP is defined independently)
the shape will be the the shape (nP,nP).
:rtype: (int,int)
:return: shape of the operator as a tuple
:rtype: tuple
:return: shape of the operator as a tuple (int,int)
"""
if self._nP is not None:
return (self.nP, self.nP)
@@ -86,7 +86,7 @@ class IdentityMap(object):
The derivative of the transformation.
:param numpy.array m: model
:rtype: scipy.csr_matrix
:rtype: scipy.sparse.csr_matrix
:return: derivative of transformed model
"""
@@ -101,7 +101,7 @@ class IdentityMap(object):
:return: passed the test?
"""
print 'Testing %s' % str(self)
print 'Testing {0!s}'.format(str(self))
if m is None:
m = abs(np.random.rand(self.nP))
if 'plotIt' not in kwargs:
@@ -111,21 +111,21 @@ class IdentityMap(object):
def _assertMatchesPair(self, pair):
assert (isinstance(self, pair) or
isinstance(self, ComboMap) and isinstance(self.maps[0], pair)
), "Mapping object must be an instance of a %s class."%(pair.__name__)
), "Mapping object must be an instance of a {0!s} class.".format((pair.__name__))
def __mul__(self, val):
if isinstance(val, IdentityMap):
if not (self.shape[1] == '*' or val.shape[0] == '*') and not self.shape[1] == val.shape[0]:
raise ValueError('Dimension mismatch in %s and %s.' % (str(self), str(val)))
raise ValueError('Dimension mismatch in {0!s} and {1!s}.'.format(str(self), str(val)))
return ComboMap([self, val])
elif isinstance(val, np.ndarray):
if not self.shape[1] == '*' and not self.shape[1] == val.shape[0]:
raise ValueError('Dimension mismatch in %s and np.ndarray%s.' % (str(self), str(val.shape)))
raise ValueError('Dimension mismatch in {0!s} and np.ndarray{1!s}.'.format(str(self), str(val.shape)))
return self._transform(val)
raise Exception('Unrecognized data type to multiply. Try a map or a numpy.ndarray!')
def __str__(self):
return "%s(%s,%s)" % (self.__class__.__name__, self.shape[0], self.shape[1])
return "{0!s}({1!s},{2!s})".format(self.__class__.__name__, self.shape[0], self.shape[1])
class ComboMap(IdentityMap):
@@ -140,7 +140,7 @@ class ComboMap(IdentityMap):
if ii > 0 and not (self.shape[1] == '*' or m.shape[0] == '*') and not self.shape[1] == m.shape[0]:
prev = self.maps[-1]
errArgs = (prev.__class__.__name__, prev.shape[0], prev.shape[1], m.__class__.__name__, m.shape[0], m.shape[1])
raise ValueError('Dimension mismatch in map[%s] (%s, %s) and map[%s] (%s, %s).' % errArgs)
raise ValueError('Dimension mismatch in map[{0!s}] ({1!s}, {2!s}) and map[{3!s}] ({4!s}, {5!s}).'.format(*errArgs))
if isinstance(m, ComboMap):
self.maps += m.maps
@@ -173,7 +173,7 @@ class ComboMap(IdentityMap):
return deriv
def __str__(self):
return 'ComboMap[%s](%s,%s)' % (' * '.join([m.__str__() for m in self.maps]), self.shape[0], self.shape[1])
return 'ComboMap[{0!s}]({1!s},{2!s})'.format(' * '.join([m.__str__() for m in self.maps]), self.shape[0], self.shape[1])
class ExpMap(IdentityMap):
@@ -216,7 +216,7 @@ class ExpMap(IdentityMap):
def deriv(self, m):
"""
: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.
@@ -366,7 +366,7 @@ class SurjectVertical1D(IdentityMap):
def deriv(self, m):
"""
:param numpy.array m: model
:rtype: scipy.csr_matrix
:rtype: scipy.sparse.csr_matrix
:return: derivative of transformed model
"""
repNum = self.mesh.vnC[:self.mesh.dim-1].prod()
@@ -427,7 +427,7 @@ class Surject2Dto3D(IdentityMap):
def deriv(self, m):
"""
:param numpy.array m: model
:rtype: scipy.csr_matrix
:rtype: scipy.sparse.csr_matrix
:return: derivative of transformed model
"""
inds = self * np.arange(self.nP)
@@ -502,7 +502,9 @@ class InjectActiveCells(IdentityMap):
if Utils.isScalar(valInactive):
self.valInactive = np.ones(self.nC)*float(valInactive)
else:
self.valInactive = valInactive.copy()
self.valInactive = np.ones(self.nC)
self.valInactive[self.indInactive] = valInactive.copy()
self.valInactive[self.indActive] = 0
inds = np.nonzero(self.indActive)[0]
@@ -533,83 +535,6 @@ class ActiveCells(InjectActiveCells):
FutureWarning)
InjectActiveCells.__init__(self, mesh, indActive, valInactive, nC)
class InjectActiveCellsTopo(IdentityMap):
"""
Active model parameters. Extend for cells on topography to air cell (only works for tensor mesh)
"""
indActive = None #: Active Cells
valInactive = None #: Values of inactive Cells
nC = None #: Number of cells in the full model
def __init__(self, mesh, indActive, nC=None):
self.mesh = mesh
self.nC = nC or mesh.nC
if indActive.dtype is not bool:
z = np.zeros(self.nC,dtype=bool)
z[indActive] = True
indActive = z
self.indActive = indActive
self.indInactive = np.logical_not(indActive)
inds = np.nonzero(self.indActive)[0]
self.P = sp.csr_matrix((np.ones(inds.size),(inds, range(inds.size))), shape=(self.nC, self.nP))
@property
def shape(self):
return (self.nC, self.nP)
@property
def nP(self):
"""Number of parameters in the model."""
return self.indActive.sum()
def _transform(self, m):
val_temp = np.zeros(self.mesh.nC)
val_temp[self.indActive] = m
valInactive = np.zeros(self.mesh.nC)
#1D
if self.mesh.dim == 1:
z_temp = self.mesh.gridCC
val_temp[~self.indActive] = val_temp[np.argmax(z_temp[self.indActive])]
#2D
elif self.mesh.dim == 2:
act_temp = self.indActive.reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
val_temp = val_temp.reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
y_temp = self.mesh.gridCC[:,1].reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
for i in range(self.mesh.nCx):
act_tempx = act_temp[i,:] == 1
val_temp[i,~act_tempx] = val_temp[i,np.argmax(y_temp[i,act_tempx])]
valInactive[~self.indActive] = Utils.mkvc(val_temp)[~self.indActive]
#3D
elif self.mesh.dim == 3:
act_temp = self.indActive.reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
val_temp = val_temp.reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
z_temp = self.mesh.gridCC[:,2].reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
for i in range(self.mesh.nCx*self.mesh.nCy):
act_tempxy = act_temp[i,:] == 1
val_temp[i,~act_tempxy] = val_temp[i,np.argmax(z_temp[i,act_tempxy])]
valInactive[~self.indActive] = Utils.mkvc(val_temp)[~self.indActive]
self.valInactive = valInactive
return self.P*m + self.valInactive
def inverse(self, D):
return self.P.T*D
def deriv(self, m):
return self.P
class ActiveCellsTopo(InjectActiveCellsTopo):
def __init__(self, mesh, indActive, valInactive, nC=None):
warnings.warn(
"`ActiveCellsTopo` is deprecated and will be removed in future versions. Use `InjectActiveCellsTopo` instead",
FutureWarning)
InjectActiveCellsTopo.__init__(self, mesh, indActive, valInactive, nC)
class Weighting(IdentityMap):
"""
+27 -25
View File
@@ -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])
@@ -520,7 +522,7 @@ class BaseRectangularMesh(BaseMesh):
assert xType in outType, 'You cannot change type of components.'
if type(x) == list:
for i, xi in enumerate(x):
assert isinstance(x, np.ndarray), "x[%i] must be a numpy array" % i
assert isinstance(x, np.ndarray), "x[{0:d}] must be a numpy array".format(i)
assert xi.size == x[0].size, "Number of elements in list must not change."
x_array = np.ones((x.size, len(x)))
+255 -318
View File
@@ -2,15 +2,30 @@ 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
length3D = lambda x: (x[:, 0]**2 + x[:, 1]**2 + x[:, 2]**2)**0.5
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))
def length2D(x):
return (x[:, 0]**2 + x[:, 1]**2)**0.5
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
def length3D(x):
return (x[:, 0]**2 + x[:, 1]**2 + x[:, 2]**2)**0.5
def normalize2D(x):
return x/np.kron(np.ones((1, 2)), Utils.mkvc(length2D(x), 2))
def normalize3D(x):
return x/np.kron(np.ones((1, 3)), Utils.mkvc(length3D(x), 2))
# Curvi Mesh
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts,
CurvView):
"""
CurvilinearMesh is a mesh class that deals with curvilinear meshes.
@@ -30,12 +45,16 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
_meshType = 'Curv'
def __init__(self, nodes):
assert type(nodes) == list, "'nodes' variable must be a list of np.ndarray"
assert type(nodes) == list, ("'nodes' variable must be a list of "
"np.ndarray")
assert len(nodes) > 1, "len(node) must be greater than 1"
for i, nodes_i in enumerate(nodes):
assert isinstance(nodes_i, np.ndarray), ("nodes[%i] is not a numpy array." % i)
assert nodes_i.shape == nodes[0].shape, ("nodes[%i] is not the same shape as nodes[0]" % i)
assert isinstance(nodes_i, np.ndarray), ("nodes[{0:d}] is not a"
"numpy array.".format(i))
assert nodes_i.shape == nodes[0].shape, ("nodes[{0:d}] is not the "
"same shape as nodes[0]"
.format(i))
assert len(nodes[0].shape) == len(nodes), "Dimension mismatch"
assert len(nodes[0].shape) > 1, "Not worth using Curv for a 1D mesh."
@@ -47,121 +66,113 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
for i, node_i in enumerate(nodes):
self._gridN[:, i] = Utils.mkvc(node_i.astype(float))
def gridCC():
doc = "Cell-centered grid."
@property
def gridCC(self):
"""
Cell-centered grid
"""
if getattr(self, '_gridCC', None) is None:
self._gridCC = np.concatenate([self.aveN2CC*self.gridN[:, i]
for i in range(self.dim)]).reshape(
(-1, self.dim), order='F')
return self._gridCC
def fget(self):
if self._gridCC is None:
self._gridCC = np.concatenate([self.aveN2CC*self.gridN[:,i] for i in range(self.dim)]).reshape((-1,self.dim), order='F')
return self._gridCC
return locals()
_gridCC = None # Store grid by default
gridCC = property(**gridCC())
@property
def gridN(self):
"""
Nodal grid.
"""
if getattr(self, '_gridN', None) is None:
raise Exception("Someone deleted this. I blame you.")
return self._gridN
def gridN():
doc = "Nodal grid."
@property
def gridFx(self):
"""
Face staggered grid in the x direction.
"""
def fget(self):
if self._gridN is None:
raise Exception("Someone deleted this. I blame you.")
return self._gridN
return locals()
_gridN = None # Store grid by default
gridN = property(**gridN())
if getattr(self, '_gridFx', None) is None:
N = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
XY = [Utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N]
self._gridFx = np.c_[XY[0], XY[1]]
elif self.dim == 3:
XYZ = [Utils.mkvc(0.25 * (n[:, :-1, :-1] + n[:, :-1, 1:] +
n[:, 1:, :-1] + n[:, 1:, 1:])) for n in N]
self._gridFx = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridFx
def gridFx():
doc = "Face staggered grid in the x direction."
@property
def gridFy(self):
"""
Face staggered grid in the y direction.
"""
def fget(self):
if self._gridFx is None:
N = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
XY = [Utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N]
self._gridFx = np.c_[XY[0], XY[1]]
elif self.dim == 3:
XYZ = [Utils.mkvc(0.25 * (n[:, :-1, :-1] + n[:, :-1, 1:] + n[:, 1:, :-1] + n[:, 1:, 1:])) for n in N]
self._gridFx = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridFx
return locals()
_gridFx = None # Store grid by default
gridFx = property(**gridFx())
if getattr(self, '_gridFy', None) is None:
N = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
XY = [Utils.mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N]
self._gridFy = np.c_[XY[0], XY[1]]
elif self.dim == 3:
XYZ = [Utils.mkvc(0.25 * (n[:-1, :, :-1] + n[:-1, :, 1:] +
n[1:, :, :-1] + n[1:, :, 1:])) for n in N]
self._gridFy = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridFy
def gridFy():
doc = "Face staggered grid in the y direction."
@property
def gridFz(self):
"""
Face staggered grid in the y direction.
"""
def fget(self):
if self._gridFy is None:
N = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
XY = [Utils.mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N]
self._gridFy = np.c_[XY[0], XY[1]]
elif self.dim == 3:
XYZ = [Utils.mkvc(0.25 * (n[:-1, :, :-1] + n[:-1, :, 1:] + n[1:, :, :-1] + n[1:, :, 1:])) for n in N]
self._gridFy = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridFy
return locals()
_gridFy = None # Store grid by default
gridFy = property(**gridFy())
if getattr(self, '_gridFz', None) is None:
N = self.r(self.gridN, 'N', 'N', 'M')
XYZ = [Utils.mkvc(0.25 * (n[:-1, :-1, :] + n[:-1, 1:, :] +
n[1:, :-1, :] + n[1:, 1:, :])) for n in N]
self._gridFz = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridFz
def gridFz():
doc = "Face staggered grid in the z direction."
@property
def gridEx(self):
"""
Edge staggered grid in the x direction.
"""
if getattr(self, '_gridEx', None) is None:
N = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
XY = [Utils.mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N]
self._gridEx = np.c_[XY[0], XY[1]]
elif self.dim == 3:
XYZ = [Utils.mkvc(0.5 * (n[:-1, :, :] + n[1:, :, :])) for n in N]
self._gridEx = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridEx
def fget(self):
if self._gridFz is None and self.dim == 3:
N = self.r(self.gridN, 'N', 'N', 'M')
XYZ = [Utils.mkvc(0.25 * (n[:-1, :-1, :] + n[:-1, 1:, :] + n[1:, :-1, :] + n[1:, 1:, :])) for n in N]
self._gridFz = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridFz
return locals()
_gridFz = None # Store grid by default
gridFz = property(**gridFz())
@property
def gridEy(self):
"""
Edge staggered grid in the y direction.
"""
if getattr(self, '_gridEy', None) is None:
N = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
XY = [Utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N]
self._gridEy = np.c_[XY[0], XY[1]]
elif self.dim == 3:
XYZ = [Utils.mkvc(0.5 * (n[:, :-1, :] + n[:, 1:, :])) for n in N]
self._gridEy = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridEy
def gridEx():
doc = "Edge staggered grid in the x direction."
def fget(self):
if self._gridEx is None:
N = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
XY = [Utils.mkvc(0.5 * (n[:-1, :] + n[1:, :])) for n in N]
self._gridEx = np.c_[XY[0], XY[1]]
elif self.dim == 3:
XYZ = [Utils.mkvc(0.5 * (n[:-1, :, :] + n[1:, :, :])) for n in N]
self._gridEx = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridEx
return locals()
_gridEx = None # Store grid by default
gridEx = property(**gridEx())
def gridEy():
doc = "Edge staggered grid in the y direction."
def fget(self):
if self._gridEy is None:
N = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
XY = [Utils.mkvc(0.5 * (n[:, :-1] + n[:, 1:])) for n in N]
self._gridEy = np.c_[XY[0], XY[1]]
elif self.dim == 3:
XYZ = [Utils.mkvc(0.5 * (n[:, :-1, :] + n[:, 1:, :])) for n in N]
self._gridEy = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridEy
return locals()
_gridEy = None # Store grid by default
gridEy = property(**gridEy())
def gridEz():
doc = "Edge staggered grid in the z direction."
def fget(self):
if self._gridEz is None and self.dim == 3:
N = self.r(self.gridN, 'N', 'N', 'M')
XYZ = [Utils.mkvc(0.5 * (n[:, :, :-1] + n[:, :, 1:])) for n in N]
self._gridEz = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridEz
return locals()
_gridEz = None # Store grid by default
gridEz = property(**gridEz())
@property
def gridEz(self):
"""
Edge staggered grid in the z direction.
"""
if getattr(self, '_gridEz', None) is None and self.dim == 3:
N = self.r(self.gridN, 'N', 'N', 'M')
XYZ = [Utils.mkvc(0.5 * (n[:, :, :-1] + n[:, :, 1:])) for n in N]
self._gridEz = np.c_[XYZ[0], XYZ[1], XYZ[2]]
return self._gridEz
# --------------- Geometries ---------------------
#
@@ -193,78 +204,94 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
# | / | /
# D -------------- C
# node(i+1,j,k) node(i+1,j+1,k)
def vol():
doc = "Construct cell volumes of the 3D model as 1d array."
def fget(self):
if(self._vol is None):
if self.dim == 2:
A, B, C, D = Utils.indexCube('ABCD', self.vnC+1)
normal, area = Utils.faceInfo(np.c_[self.gridN, np.zeros((self.nN, 1))], A, B, C, D)
self._vol = area
elif self.dim == 3:
# Each polyhedron can be decomposed into 5 tetrahedrons
# However, this presents a choice so we may as well divide in two ways and average.
A, B, C, D, E, F, G, H = Utils.indexCube('ABCDEFGH', self.vnC+1)
@property
def vol(self):
"""
Construct cell volumes of the 3D model as 1d array
"""
vol1 = (Utils.volTetra(self.gridN, A, B, D, E) + # cutted edge top
Utils.volTetra(self.gridN, B, E, F, G) + # cutted edge top
Utils.volTetra(self.gridN, B, D, E, G) + # middle
Utils.volTetra(self.gridN, B, C, D, G) + # cutted edge bottom
Utils.volTetra(self.gridN, D, E, G, H)) # cutted edge bottom
if getattr(self, '_vol', None) is None:
if self.dim == 2:
A, B, C, D = Utils.indexCube('ABCD', self.vnC+1)
normal, area = Utils.faceInfo(np.c_[self.gridN, np.zeros(
(self.nN, 1))], A, B, C, D)
self._vol = area
elif self.dim == 3:
# Each polyhedron can be decomposed into 5 tetrahedrons
# However, this presents a choice so we may as well divide in
# two ways and average.
A, B, C, D, E, F, G, H = Utils.indexCube('ABCDEFGH', self.vnC +
1)
vol2 = (Utils.volTetra(self.gridN, A, F, B, C) + # cutted edge top
Utils.volTetra(self.gridN, A, E, F, H) + # cutted edge top
Utils.volTetra(self.gridN, A, H, F, C) + # middle
Utils.volTetra(self.gridN, C, H, D, A) + # cutted edge bottom
Utils.volTetra(self.gridN, C, G, H, F)) # cutted edge bottom
vol1 = (Utils.volTetra(self.gridN, A, B, D, E) + # cutted edge top
Utils.volTetra(self.gridN, B, E, F, G) + # cutted edge top
Utils.volTetra(self.gridN, B, D, E, G) + # middle
Utils.volTetra(self.gridN, B, C, D, G) + # cutted edge bottom
Utils.volTetra(self.gridN, D, E, G, H)) # cutted edge bottom
self._vol = (vol1 + vol2)/2
return self._vol
return locals()
_vol = None
vol = property(**vol())
vol2 = (Utils.volTetra(self.gridN, A, F, B, C) + # cutted edge top
Utils.volTetra(self.gridN, A, E, F, H) + # cutted edge top
Utils.volTetra(self.gridN, A, H, F, C) + # middle
Utils.volTetra(self.gridN, C, H, D, A) + # cutted edge bottom
Utils.volTetra(self.gridN, C, G, H, F)) # cutted edge bottom
def area():
doc = "Face areas."
self._vol = (vol1 + vol2)/2
return self._vol
def fget(self):
if(self._area is None or self._normals is None):
# Compute areas of cell faces
if(self.dim == 2):
xy = self.gridN
A, B = Utils.indexCube('AB', self.vnC+1, np.array([self.nNx, self.nCy]))
edge1 = xy[B, :] - xy[A, :]
normal1 = np.c_[edge1[:, 1], -edge1[:, 0]]
area1 = length2D(edge1)
A, D = Utils.indexCube('AD', self.vnC+1, np.array([self.nCx, self.nNy]))
# Note that we are doing A-D to make sure the normal points the right way.
# Think about it. Look at the picture. Normal points towards C iff you do this.
edge2 = xy[A, :] - xy[D, :]
normal2 = np.c_[edge2[:, 1], -edge2[:, 0]]
area2 = length2D(edge2)
self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2)]
self._normals = [normalize2D(normal1), normalize2D(normal2)]
elif(self.dim == 3):
@property
def area(self):
if (getattr(self, '_area', None) is None or
getattr(self, '_normals', None) is None):
# Compute areas of cell faces
if(self.dim == 2):
xy = self.gridN
A, B = Utils.indexCube('AB', self.vnC+1, np.array([self.nNx,
self.nCy]))
edge1 = xy[B, :] - xy[A, :]
normal1 = np.c_[edge1[:, 1], -edge1[:, 0]]
area1 = length2D(edge1)
A, D = Utils.indexCube('AD', self.vnC+1, np.array([self.nCx,
self.nNy]))
# Note that we are doing A-D to make sure the normal points the
# right way.
# Think about it. Look at the picture. Normal points towards C
# iff you do this.
edge2 = xy[A, :] - xy[D, :]
normal2 = np.c_[edge2[:, 1], -edge2[:, 0]]
area2 = length2D(edge2)
self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2)]
self._normals = [normalize2D(normal1), normalize2D(normal2)]
A, E, F, B = Utils.indexCube('AEFB', self.vnC+1, np.array([self.nNx, self.nCy, self.nCz]))
normal1, area1 = Utils.faceInfo(self.gridN, A, E, F, B, average=False, normalizeNormals=False)
elif(self.dim == 3):
A, D, H, E = Utils.indexCube('ADHE', self.vnC+1, np.array([self.nCx, self.nNy, self.nCz]))
normal2, area2 = Utils.faceInfo(self.gridN, A, D, H, E, average=False, normalizeNormals=False)
A, E, F, B = Utils.indexCube('AEFB', self.vnC+1, np.array(
[self.nNx, self.nCy, self.nCz]))
normal1, area1 = Utils.faceInfo(self.gridN, A, E, F, B,
average=False,
normalizeNormals=False)
A, B, C, D = Utils.indexCube('ABCD', self.vnC+1, np.array([self.nCx, self.nCy, self.nNz]))
normal3, area3 = Utils.faceInfo(self.gridN, A, B, C, D, average=False, normalizeNormals=False)
A, D, H, E = Utils.indexCube('ADHE', self.vnC+1, np.array(
[self.nCx, self.nNy, self.nCz]))
normal2, area2 = Utils.faceInfo(self.gridN, A, D, H, E,
average=False,
normalizeNormals=False)
self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2), Utils.mkvc(area3)]
self._normals = [normal1, normal2, normal3]
return self._area
return locals()
_area = None
area = property(**area())
A, B, C, D = Utils.indexCube('ABCD', self.vnC+1, np.array(
[self.nCx, self.nCy, self.nNz]))
normal3, area3 = Utils.faceInfo(self.gridN, A, B, C, D,
average=False,
normalizeNormals=False)
def normals():
doc = """Face normals: calling this will average
self._area = np.r_[Utils.mkvc(area1), Utils.mkvc(area2),
Utils.mkvc(area3)]
self._normals = [normal1, normal2, normal3]
return self._area
@property
def normals(self):
"""
Face normals: calling this will average
the computed normals so that there is one
per face. This is especially relevant in
3D, as there are up to 4 different normals
@@ -275,155 +302,65 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
NyX, NyY, NyZ = M.r(M.normals, 'F', 'Fy', 'M')
"""
def fget(self):
if(self._normals is None):
self.area # calling .area will create the face normals
if self.dim == 2:
return normalize2D(np.r_[self._normals[0], self._normals[1]])
elif self.dim == 3:
normal1 = (self._normals[0][0] + self._normals[0][1] + self._normals[0][2] + self._normals[0][3])/4
normal2 = (self._normals[1][0] + self._normals[1][1] + self._normals[1][2] + self._normals[1][3])/4
normal3 = (self._normals[2][0] + self._normals[2][1] + self._normals[2][2] + self._normals[2][3])/4
return normalize3D(np.r_[normal1, normal2, normal3])
return locals()
_normals = None
normals = property(**normals())
def edge():
doc = "Edge legnths."
def fget(self):
if(self._edge is None or self._tangents is None):
if(self.dim == 2):
xy = self.gridN
A, D = Utils.indexCube('AD', self.vnC+1, np.array([self.nCx, self.nNy]))
edge1 = xy[D, :] - xy[A, :]
A, B = Utils.indexCube('AB', self.vnC+1, np.array([self.nNx, self.nCy]))
edge2 = xy[B, :] - xy[A, :]
self._edge = np.r_[Utils.mkvc(length2D(edge1)), Utils.mkvc(length2D(edge2))]
self._tangents = np.r_[edge1, edge2]/np.c_[self._edge, self._edge]
elif(self.dim == 3):
xyz = self.gridN
A, D = Utils.indexCube('AD', self.vnC+1, np.array([self.nCx, self.nNy, self.nNz]))
edge1 = xyz[D, :] - xyz[A, :]
A, B = Utils.indexCube('AB', self.vnC+1, np.array([self.nNx, self.nCy, self.nNz]))
edge2 = xyz[B, :] - xyz[A, :]
A, E = Utils.indexCube('AE', self.vnC+1, np.array([self.nNx, self.nNy, self.nCz]))
edge3 = xyz[E, :] - xyz[A, :]
self._edge = np.r_[Utils.mkvc(length3D(edge1)), Utils.mkvc(length3D(edge2)), Utils.mkvc(length3D(edge3))]
self._tangents = np.r_[edge1, edge2, edge3]/np.c_[self._edge, self._edge, self._edge]
return self._edge
return locals()
_edge = None
edge = property(**edge())
def tangents():
doc = "Edge tangents."
def fget(self):
if(self._tangents is None):
self.edge # calling .edge will create the tangents
return self._tangents
return locals()
_tangents = None
tangents = property(**tangents())
#############################################
# 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 getattr(self, '_normals', None) is None:
self.area # calling .area will create the face normals
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-')
return normalize2D(np.r_[self._normals[0], self._normals[1]])
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()
normal1 = (self._normals[0][0] + self._normals[0][1] + self._normals[0][2] + self._normals[0][3])/4
normal2 = (self._normals[1][0] + self._normals[1][1] + self._normals[1][2] + self._normals[1][3])/4
normal3 = (self._normals[2][0] + self._normals[2][1] + self._normals[2][2] + self._normals[2][3])/4
return normalize3D(np.r_[normal1, normal2, normal3])
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()
@property
def edge(self):
"""
Edge lengths
"""
if getattr(self, '_edge', None) is None:
if(self.dim == 2):
xy = self.gridN
A, D = Utils.indexCube('AD', self.vnC+1, np.array([self.nCx,
self.nNy]))
edge1 = xy[D, :] - xy[A, :]
A, B = Utils.indexCube('AB', self.vnC+1, np.array([self.nNx,
self.nCy]))
edge2 = xy[B, :] - xy[A, :]
self._edge = np.r_[Utils.mkvc(length2D(edge1)),
Utils.mkvc(length2D(edge2))]
self._tangents = np.r_[edge1, edge2]/np.c_[self._edge,
self._edge]
elif(self.dim == 3):
xyz = self.gridN
A, D = Utils.indexCube('AD', self.vnC+1, np.array([self.nCx,
self.nNy,
self.nNz]))
edge1 = xyz[D, :] - xyz[A, :]
A, B = Utils.indexCube('AB', self.vnC+1, np.array([self.nNx,
self.nCy,
self.nNz]))
edge2 = xyz[B, :] - xyz[A, :]
A, E = Utils.indexCube('AE', self.vnC+1, np.array([self.nNx,
self.nNy,
self.nCz]))
edge3 = xyz[E, :] - xyz[A, :]
self._edge = np.r_[Utils.mkvc(length3D(edge1)),
Utils.mkvc(length3D(edge2)),
Utils.mkvc(length3D(edge3))]
self._tangents = (np.r_[edge1, edge2, edge3] /
np.c_[self._edge, self._edge, self._edge])
return self._edge
return self._edge
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()
@property
def tangents(self):
"""
Edge tangents
"""
if getattr(self, '_tangents', None) is None:
self.edge # calling .edge will create the tangents
return self._tangents
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__':
+6 -6
View File
@@ -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]
File diff suppressed because it is too large Load Diff
+9 -10
View File
@@ -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"
@@ -422,7 +421,7 @@ class InnerProducts(object):
def _getEdgePx(M):
"""Returns a function for creating projection matrices"""
def Px(xEdge):
assert xEdge == 'eX0', 'xEdge = %s, not eX0' % xEdge
assert xEdge == 'eX0', 'xEdge = {0!s}, not eX0'.format(xEdge)
return sp.identity(M.nC)
return Px
+24 -37
View File
@@ -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.
@@ -48,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
@@ -102,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
@@ -162,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()))
@@ -183,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
"""
@@ -201,17 +192,17 @@ 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
s = ''
s += '%i %i %i\n' %tuple(mesh.vnC)
s += '{0:d} {1:d} {2:d}\n'.format(*tuple(mesh.vnC))
origin = mesh.x0 + np.array([0,0,mesh.hz.sum()]) # Have to it in the same operation or use mesh.x0.copy(), otherwise the mesh.x0 is updated.
origin.dtype = float
s += '%.2f %.2f %.2f\n' %tuple(origin)
s += '{0:.2f} {1:.2f} {2:.2f}\n'.format(*tuple(origin))
s += ('%.2f '*mesh.nCx+'\n')%tuple(mesh.hx)
s += ('%.2f '*mesh.nCy+'\n')%tuple(mesh.hy)
s += ('%.2f '*mesh.nCz+'\n')%tuple(mesh.hz[::-1])
@@ -231,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.
@@ -286,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
@@ -335,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:
+8 -8
View File
@@ -23,8 +23,8 @@ class BaseTensorMesh(BaseMesh):
h_i = self._unitDimensions[i] * np.ones(int(h_i))/int(h_i)
elif type(h_i) is list:
h_i = Utils.meshTensor(h_i)
assert isinstance(h_i, np.ndarray), ("h[%i] is not a numpy array." % i)
assert len(h_i.shape) == 1, ("h[%i] must be a 1D numpy array." % i)
assert isinstance(h_i, np.ndarray), ("h[{0:d}] is not a numpy array.".format(i))
assert len(h_i.shape) == 1, ("h[{0:d}] must be a 1D numpy array.".format(i))
h[i] = h_i[:] # make a copy.
x0 = np.zeros(len(h))
@@ -41,7 +41,7 @@ class BaseTensorMesh(BaseMesh):
elif x_i == 'N':
x0[i] = -h_i.sum()
else:
raise Exception("x0[%i] must be a scalar or '0' to be zero, 'C' to center, or 'N' to be negative." % i)
raise Exception("x0[{0:d}] must be a scalar or '0' to be zero, 'C' to center, or 'N' to be negative.".format(i))
if isinstance(self, BaseRectangularMesh):
BaseRectangularMesh.__init__(self, np.array([x.size for x in h]), x0)
@@ -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::
@@ -239,7 +239,7 @@ class BaseTensorMesh(BaseMesh):
'CCVz' -> z-component of vector field defined on cell centers
"""
if self._meshType == 'CYL' and self.isSymmetric and locType in ['Ex','Ez','Fy']:
raise Exception('Symmetric CylMesh does not support %s interpolation, as this variable does not exist.' % locType)
raise Exception('Symmetric CylMesh does not support {0!s} interpolation, as this variable does not exist.'.format(locType))
loc = Utils.asArray_N_x_Dim(loc, self.dim)
@@ -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"
+5 -5
View File
@@ -177,7 +177,7 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO):
return l
def __str__(self):
outStr = ' ---- %sTreeMesh ---- '%('Oc' if self.dim == 3 else 'Quad')
outStr = ' ---- {0!s}TreeMesh ---- '.format(('Oc' if self.dim == 3 else 'Quad'))
def printH(hx, outStr=''):
i = -1
while True:
@@ -213,7 +213,7 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO):
outStr += printH(self.hy, outStr='\n hy:')
outStr += printH(self.hz, outStr='\n hz:')
outStr += '\n nC: {0:d}'.format(self.nC)
outStr += '\n Fill: %2.2f%%'%(self.fill*100)
outStr += '\n Fill: {0:2.2f}%'.format((self.fill*100))
return outStr
@property
@@ -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::
@@ -2210,7 +2210,7 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO):
ax.set_xlabel('y' if normal == 'X' else 'x')
ax.set_ylabel('y' if normal == 'Z' else 'z')
ax.set_title('Slice %d, %s = %4.2f' % (ind,normal,indLoc))
ax.set_title('Slice {0:d}, {1!s} = {2:4.2f}'.format(ind, normal, indLoc))
if grid:
_ = antiNormalInd
@@ -2240,7 +2240,7 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO):
if key < 0 : #Handle negative indices
key += len( self )
if key >= len( self ) :
raise IndexError, "The index (%d) is out of range."%key
raise IndexError, "The index ({0:d}) is out of range.".format(key)
self._numberCells() # no-op if numbered
index = self._i2cc[key]
+255 -428
View File
File diff suppressed because it is too large Load Diff
+87 -49
View File
@@ -171,7 +171,7 @@ class TensorView(object):
iz = ix + iy*nX
if iz < self.nCz:
ax.text((ix+1)*(self.vectorNx[-1]-self.x0[0])-pad,(iy)*(self.vectorNy[-1]-self.x0[1])+pad,
'#%i'%iz,color=annotationColor,verticalalignment='bottom',horizontalalignment='right',size='x-large')
'#{0:.0f}'.format(iz),color=annotationColor,verticalalignment='bottom',horizontalalignment='right',size='x-large')
ax.set_title(vType)
if showIt: plt.show()
@@ -218,13 +218,13 @@ 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)
assert vType in vTypeOpts, "vType must be in ['{0!s}']".format("','".join(vTypeOpts))
assert self.dim == 3, 'Must be a 3D mesh. Use plotImage.'
assert view in viewOpts, "view must be in ['%s']" % "','".join(viewOpts)
assert normal in normalOpts, "normal must be in ['%s']" % "','".join(normalOpts)
assert view in viewOpts, "view must be in ['{0!s}']".format("','".join(viewOpts))
assert normal in normalOpts, "normal must be in ['{0!s}']".format("','".join(normalOpts))
assert type(grid) is bool, 'grid must be a boolean'
szSliceDim = getattr(self, 'nC'+normal.lower()) #: Size of the sliced dimension
@@ -295,7 +295,7 @@ class TensorView(object):
ax.set_xlabel('y' if normal == 'X' else 'x')
ax.set_ylabel('y' if normal == 'Z' else 'z')
ax.set_title('Slice %d' % ind)
ax.set_title('Slice {0:.0f}'.format(ind))
return out
@@ -316,11 +316,11 @@ class TensorView(object):
vTypeOptsV = ['CCv','F','E']
vTypeOpts = vTypeOptsCC + vTypeOptsV
if view == 'vec':
assert vType in vTypeOptsV, "vType must be in ['%s'] when view='vec'" % "','".join(vTypeOptsV)
assert vType in vTypeOpts, "vType must be in ['%s']" % "','".join(vTypeOpts)
assert vType in vTypeOptsV, "vType must be in ['{0!s}'] when view='vec'".format("','".join(vTypeOptsV))
assert vType in vTypeOpts, "vType must be in ['{0!s}']".format("','".join(vTypeOpts))
viewOpts = ['real','imag','abs','vec']
assert view in viewOpts, "view must be in ['%s']" % "','".join(viewOpts)
assert view in viewOpts, "view must be in ['{0!s}']".format("','".join(viewOpts))
if ax is None:
@@ -552,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.
@@ -560,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()
@@ -630,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 *
+10 -9
View File
@@ -121,7 +121,7 @@ class Minimize(object):
@callback.setter
def callback(self, value):
if self.callback is not None:
print 'The callback on the %s Optimization was replaced.' % self.__name__
print 'The callback on the {0!s} Optimization was replaced.'.format(self.__name__)
self._callback = value
@@ -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.'
@@ -855,7 +855,7 @@ class NewtonRoot(object):
if self.comments and self.doLS: print '\tLinesearch:\n'
# Enter Linesearch
while True and self.doLS:
if self.comments: print '\t\tResid: %e\n'%norm(rt)
if self.comments: print '\t\tResid: {0:e}\n'.format(norm(rt))
if norm(rt) <= norm(r) or norm(rt) < self.tol:
break
@@ -873,7 +873,7 @@ class NewtonRoot(object):
if norm(rt) < self.tol:
break
if self.iter > self.maxIter:
print 'NewtonRoot stopped by maxIters (%d). norm: %4.4e' % (self.maxIter, norm(rt))
print 'NewtonRoot stopped by maxIters ({0:d}). norm: {1:4.4e}'.format(self.maxIter, norm(rt))
break
return x
@@ -1003,8 +1003,9 @@ class ProjectedGNCG(BFGS, Minimize, Remember):
# 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
return delx
+1 -1
View File
@@ -49,7 +49,7 @@ class BaseProblem(object):
def pair(self, d):
"""Bind a survey to this problem instance using pointers."""
assert isinstance(d, self.surveyPair), "Data object must be an instance of a %s class."%(self.surveyPair.__name__)
assert isinstance(d, self.surveyPair), "Data object must be an instance of a {0!s} class.".format((self.surveyPair.__name__))
if d.ispaired:
raise Exception("The survey object is already paired to a problem. Use survey.unpair()")
self._survey = d
+30 -30
View File
@@ -19,85 +19,85 @@ class Property(object):
return getattr(self, '_propertyLink', None)
@propertyLink.setter
def propertyLink(self, value):
assert type(value) is tuple and len(value) == 2 and type(value[0]) is str and issubclass(value[1], Maps.IdentityMap), 'Use format: ("%s", Maps.ReciprocalMap)'%self.name
assert type(value) is tuple and len(value) == 2 and type(value[0]) is str and issubclass(value[1], Maps.IdentityMap), 'Use format: ("{0!s}", Maps.ReciprocalMap)'.format(self.name)
self._propertyLink = value
def _getMapProperty(self):
prop = self
def fget(self):
return getattr(self, '_%sMap'%prop.name, None)
return getattr(self, '_{0!s}Map'.format(prop.name), None)
def fset(self, val):
if prop.propertyLink is not None:
linkName, linkMap = prop.propertyLink
assert getattr(self, '%sMap'%linkName, None) is None, 'Cannot set both sides of a linked property.'
assert getattr(self, '{0!s}Map'.format(linkName), None) is None, 'Cannot set both sides of a linked property.'
# TODO: Check if the mapping can be correct
setattr(self, '_%sMap'%prop.name, val)
setattr(self, '_{0!s}Map'.format(prop.name), val)
return property(fget=fget, fset=fset, doc=prop.doc)
def _getIndexProperty(self):
prop = self
def fget(self):
return getattr(self, '_%sIndex'%prop.name, slice(None))
return getattr(self, '_{0!s}Index'.format(prop.name), slice(None))
def fset(self, val):
setattr(self, '_%sIndex'%prop.name, val)
setattr(self, '_{0!s}Index'.format(prop.name), val)
return property(fget=fget, fset=fset, doc=prop.doc)
def _getProperty(self):
prop = self
def fget(self):
mapping = getattr(self, '%sMap'%prop.name)
mapping = getattr(self, '{0!s}Map'.format(prop.name))
if mapping is None and prop.propertyLink is None:
return prop.defaultVal
if mapping is None and prop.propertyLink is not None:
linkName, linkMapClass = prop.propertyLink
linkMap = linkMapClass(None)
if getattr(self, '%sMap'%linkName, None) is None:
if getattr(self, '{0!s}Map'.format(linkName), None) is None:
return prop.defaultVal
m = getattr(self, '%s'%linkName)
m = getattr(self, '{0!s}'.format(linkName))
return linkMap * m
m = getattr(self, '%sModel'%prop.name)
m = getattr(self, '{0!s}Model'.format(prop.name))
return mapping * m
return property(fget=fget)
def _getModelDerivProperty(self):
prop = self
def fget(self):
mapping = getattr(self, '%sMap'%prop.name)
mapping = getattr(self, '{0!s}Map'.format(prop.name))
if mapping is None and prop.propertyLink is None:
return None
if mapping is None and prop.propertyLink is not None:
linkName, linkMapClass = prop.propertyLink
linkedMap = getattr(self, '%sMap'%linkName)
linkedMap = getattr(self, '{0!s}Map'.format(linkName))
if linkedMap is None:
return None
linkMap = linkMapClass(None) * linkedMap
m = getattr(self, '%s'%linkName)
m = getattr(self, '{0!s}Model'.format(linkName))
return linkMap.deriv( m )
m = getattr(self, '%sModel'%prop.name)
m = getattr(self, '{0!s}Model'.format(prop.name))
return mapping.deriv( m )
return property(fget=fget)
def _getModelProperty(self):
prop = self
def fget(self):
mapping = getattr(self, '%sMap'%prop.name)
mapping = getattr(self, '{0!s}Map'.format(prop.name))
if mapping is None:
return None
index = getattr(self.propMap, '%sIndex'%prop.name)
index = getattr(self.propMap, '{0!s}Index'.format(prop.name))
return self.vector[index]
return property(fget=fget)
def _getModelProjProperty(self):
prop = self
def fget(self):
mapping = getattr(self, '%sMap'%prop.name)
mapping = getattr(self, '{0!s}Map'.format(prop.name))
if mapping is None:
return None
inds = getattr(self.propMap, '%sIndex'%prop.name)
inds = getattr(self.propMap, '{0!s}Index'.format(prop.name))
if type(inds) is slice:
inds = range(*inds.indices(self.nP))
nI, nP = len(inds),self.nP
@@ -107,7 +107,7 @@ class Property(object):
def _getModelMapProperty(self):
prop = self
def fget(self):
return getattr(self.propMap, '_%sMap'%prop.name, None)
return getattr(self.propMap, '_{0!s}Map'.format(prop.name), None)
return property(fget=fget)
@@ -123,7 +123,7 @@ class PropModel(object):
inds = []
if getattr(self, '_nP', None) is None:
for name in self.propMap._properties:
index = getattr(self.propMap, '%sIndex'%name, None)
index = getattr(self.propMap, '{0!s}Index'.format(name), None)
if index is not None:
if type(index) is slice:
inds += range(*index.indices(len(self.vector)))
@@ -163,9 +163,9 @@ class _PropMapMetaClass(type):
if prop.defaultInvProp:
defaultInvProps += [p]
if prop.propertyLink is not None:
assert prop.propertyLink[0] in _properties, "You can only link to things that exist: '%s' is trying to link to '%s'"%(prop.name, prop.propertyLink[0])
assert prop.propertyLink[0] in _properties, "You can only link to things that exist: '{0!s}' is trying to link to '{1!s}'".format(prop.name, prop.propertyLink[0])
if len(defaultInvProps) > 1:
raise Exception('You have more than one default inversion property: %s' % defaultInvProps)
raise Exception('You have more than one default inversion property: {0!s}'.format(defaultInvProps))
newClass = super(_PropMapMetaClass, cls).__new__(cls, name, bases, attrs)
@@ -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):
@@ -223,7 +223,7 @@ class PropMap(object):
type(m[0]) is str and
m[0] in self._properties and
isinstance(m[1], Maps.IdentityMap)
for m in maps]), "Use signature: [%s]" % (', '.join(["('%s', %sMap)"%(p,p) for p in self._properties]))
for m in maps]), "Use signature: [{0!s}]".format((', '.join(["('{0!s}', {1!s}Map)".format(p, p) for p in self._properties])))
if slices is None:
slices = dict()
else:
@@ -236,10 +236,10 @@ class PropMap(object):
nP = 0
for name, mapping in maps:
setattr(self, '%sMap'%name, mapping)
setattr(self, '%sIndex'%name, slices.get(name, slice(nP, nP + mapping.nP)))
setattr(self, '{0!s}Map'.format(name), mapping)
setattr(self, '{0!s}Index'.format(name), slices.get(name, slice(nP, nP + mapping.nP)))
nP += mapping.nP
self.nP = nP
self.nP = nP
@property
def defaultInvProp(self):
@@ -250,12 +250,12 @@ class PropMap(object):
def clearMaps(self):
for name in self._properties:
setattr(self, '%sMap'%name, None)
setattr(self, '%sIndex'%name, None)
setattr(self, '{0!s}Map'.format(name), None)
setattr(self, '{0!s}Index'.format(name), None)
def __call__(self, vec):
return self.PropModel(self, vec)
def __contains__(self, val):
activeMaps = [name for name in self._properties if getattr(self, '%sMap'%name) is not None]
activeMaps = [name for name in self._properties if getattr(self, '{0!s}Map'.format(name)) is not None]
return val in activeMaps
+448 -190
View File
@@ -1,4 +1,6 @@
import Utils, Maps, Mesh, numpy as np, scipy.sparse as sp
import Utils, Maps, Mesh
import numpy as np
import scipy.sparse as sp
class RegularizationMesh(object):
"""
@@ -8,7 +10,7 @@ class RegularizationMesh(object):
are not necessarily true differential operators, but are constructed from
a SimPEG Mesh.
:param Mesh mesh: problem mesh
:param BaseMesh mesh: problem mesh
:param numpy.array indActive: bool array, size nC, that is True where we have active cells. Used to reduce the operators so we regularize only on active cells
"""
@@ -381,8 +383,8 @@ class BaseRegularization(object):
: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
:rtype: scipy.sparse.csr_matrix
:return: WtW, or if v is supplied WtW*v (numpy.ndarray)
The regularization is:
@@ -403,7 +405,238 @@ class BaseRegularization(object):
return mD.T * ( self.W.T * ( self.W * ( mD * v) ) )
class Tikhonov(BaseRegularization):
class Simple(BaseRegularization):
"""
Simple regularization that does not include length scales in the derivatives.
"""
mrefInSmooth = False #: include mref in the smoothness?
alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight")
alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction")
alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction")
alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction")
cell_weights = 1.
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
if isinstance(self.cell_weights,float):
self.cell_weights = np.ones(self.regmesh.nC) * self.cell_weights
@property
def Wsmall(self):
"""Regularization matrix Wsmall"""
if getattr(self,'_Wsmall', None) is None:
self._Wsmall = Utils.sdiag((self.alpha_s*self.cell_weights)**0.5)
return self._Wsmall
@property
def Wx(self):
"""Regularization matrix Wx"""
if getattr(self, '_Wx', None) is None:
self._Wx = Utils.sdiag((self.alpha_x * (self.regmesh.aveCC2Fx*self.cell_weights))**0.5)*self.regmesh.cellDiffxStencil
return self._Wx
@property
def Wy(self):
"""Regularization matrix Wy"""
if getattr(self, '_Wy', None) is None:
self._Wy = Utils.sdiag((self.alpha_y * (self.regmesh.aveCC2Fy*self.cell_weights))**0.5)*self.regmesh.cellDiffyStencil
return self._Wy
@property
def Wz(self):
"""Regularization matrix Wz"""
if getattr(self, '_Wz', None) is None:
self._Wz = Utils.sdiag((self.alpha_z * (self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.regmesh.cellDiffzStencil
return self._Wz
# @property
# def Wsmooth(self):
# """Full smoothness regularization matrix W"""
# print 'wtf why are we using Wsmooth'
# raise NotImplementedError
# if getattr(self, '_Wsmooth', None) is None:
# wlist = (self.Wx,)
# if self.regmesh.dim > 1:
# wlist += (self.Wy,)
# if self.regmesh.dim > 2:
# wlist += (self.Wz,)
# self._Wsmooth = sp.vstack(wlist)
# return self._Wsmooth
#
# @property
# def W(self):
# """Full regularization matrix W"""
# print 'wtf why are we using W'
# if getattr(self, '_W', None) is None:
# wlist = (self.Wsmall, self.Wx)
# if self.regmesh.dim > 1:
# wlist += (self.Wy,)
# if self.regmesh.dim > 2:
# wlist += (self.Wz,)
# self._W = sp.vstack(wlist)
# return self._W
@Utils.timeIt
def _evalSmall(self, m):
r = self.Wsmall * ( self.mapping * (m - self.mref) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmallDeriv(self, m):
r = self.Wsmall * ( self.mapping * (m - self.mref) )
return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) )
@Utils.timeIt
def _evalSmall2Deriv(self, m, v = None):
rDeriv = self.Wsmall * ( self.mapping.deriv(m - self.mref) )
if v is not None:
return rDeriv.T * (rDeriv * v)
return rDeriv.T * rDeriv
@Utils.timeIt
def _evalSmoothx(self, m):
if self.mrefInSmooth == True:
r = self.Wx * ( self.mapping * (m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wx * ( self.mapping * (m) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmoothy(self, m):
if self.mrefInSmooth == True:
r = self.Wy * ( self.mapping * (m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wy * ( self.mapping * (m) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmoothz(self, m):
if self.mrefInSmooth == True:
r = self.Wz * ( self.mapping * (m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wz * ( self.mapping * (m) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmooth(self, m):
phiSmooth = self._evalSmoothx(m)
if self.regmesh.dim > 1:
phiSmooth += self._evalSmoothy(m)
if self.regmesh.dim > 2:
phiSmooth += self._evalSmoothz(m)
return phiSmooth
@Utils.timeIt
def _evalSmoothxDeriv(self, m):
if self.mrefInSmooth == True:
r = self.Wx * ( self.mapping * ( m - self.mref ) )
return r.T * ( self.Wx * self.mapping.deriv(m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wx * ( self.mapping * m )
return r.T * ( self.Wx * self.mapping.deriv(m) )
@Utils.timeIt
def _evalSmoothx2Deriv(self, m, v=None):
if self.mrefInSmooth == True:
rDeriv = self.Wx * ( self.mapping.deriv( m - self.mref ) )
elif self.mrefInSmooth == False:
rDeriv = self.Wx * ( self.mapping.deriv(m) )
if v is not None:
return rDeriv.T * ( rDeriv * v )
return rDeriv.T * rDeriv
@Utils.timeIt
def _evalSmoothyDeriv(self, m):
if self.mrefInSmooth == True:
r = self.Wy * ( self.mapping * ( m - self.mref ) )
return r.T * ( self.Wy * self.mapping.deriv(m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wy * ( self.mapping * m )
return r.T * ( self.Wy * self.mapping.deriv(m) )
@Utils.timeIt
def _evalSmoothy2Deriv(self, m, v=None):
if self.mrefInSmooth == True:
rDeriv = self.Wy * ( self.mapping.deriv( m - self.mref ) )
elif self.mrefInSmooth == False:
rDeriv = self.Wy * ( self.mapping.deriv(m) )
if v is not None:
return rDeriv.T * ( rDeriv * v )
return rDeriv.T * rDeriv
@Utils.timeIt
def _evalSmoothzDeriv(self, m):
if self.mrefInSmooth == True:
r = self.Wz * ( self.mapping * ( m - self.mref ) )
return r.T * ( self.Wz * self.mapping.deriv(m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wz * ( self.mapping * m )
return r.T * ( self.Wz * self.mapping.deriv(m) )
@Utils.timeIt
def _evalSmoothz2Deriv(self, m, v=None):
if self.mrefInSmooth == True:
rDeriv = self.Wz * ( self.mapping.deriv( m - self.mref ) )
elif self.mrefInSmooth == False:
rDeriv = self.Wz * ( self.mapping.deriv(m) )
if v is not None:
return rDeriv.T * ( rDeriv * v )
return rDeriv.T * rDeriv
@Utils.timeIt
def _evalSmoothDeriv(self, m):
deriv = self._evalSmoothxDeriv(m)
if self.regmesh.dim > 1:
deriv += self._evalSmoothyDeriv(m)
if self.regmesh.dim > 2:
deriv += self._evalSmoothzDeriv(m)
return deriv
@Utils.timeIt
def _evalSmooth2Deriv(self, m, v=None):
deriv = self._evalSmoothx2Deriv(m, v)
if self.regmesh.dim > 1:
deriv += self._evalSmoothy2Deriv(m, v)
if self.regmesh.dim > 2:
deriv += self._evalSmoothz2Deriv(m, v)
return deriv
@Utils.timeIt
def eval(self, m):
return self._evalSmall(m) + self._evalSmooth(m)
@Utils.timeIt
def evalDeriv(self, m):
"""
The regularization is:
.. math::
R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})}
So the derivative is straight forward:
.. math::
R(m) = \mathbf{W^\\top W (m-m_\\text{ref})}
"""
return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m)
@Utils.timeIt
def eval2Deriv(self, m, v=None):
return self._evalSmall2Deriv(m, v) + self._evalSmooth2Deriv(m, v)
class Tikhonov(Simple):
"""
L2 Tikhonov regularization with both smallness and smoothness (first order
derivative) contributions.
@@ -417,8 +650,8 @@ class Tikhonov(BaseRegularization):
Note if the key word argument `mrefInSmooth` is False, then mref is not
included in the smoothness contribution.
:param Mesh mesh: SimPEG mesh
:param Maps mapping: regularization mapping, takes the model from model space to the thing you want to regularize
:param BaseMesh mesh: SimPEG mesh
:param IdentityMap mapping: regularization mapping, takes the model from model space to the thing you want to regularize
:param numpy.ndarray indActive: active cell indices for reducing the size of differential operators in the definition of a regularization mesh
:param bool mrefInSmooth: (default = False) put mref in the smoothness component?
:param float alpha_s: (default 1e-6) smallness weight
@@ -438,7 +671,7 @@ class Tikhonov(BaseRegularization):
alpha_yy = Utils.dependentProperty('_alpha_yy', 0.0, ['_W', '_Wyy'], "Weight for the second derivative in the y direction")
alpha_zz = Utils.dependentProperty('_alpha_zz', 0.0, ['_W', '_Wzz'], "Weight for the second derivative in the z direction")
def __init__(self, mesh, mapping=None, indActive = None, **kwargs):
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
@property
@@ -493,56 +726,131 @@ class Tikhonov(BaseRegularization):
self._Wzz = Utils.sdiag((self.regmesh.vol*self.alpha_zz)**0.5)*self.regmesh.faceDiffz*self.regmesh.cellDiffz
return self._Wzz
@property
def Wsmooth(self):
def Wsmooth2(self):
"""Full smoothness regularization matrix W"""
if getattr(self, '_Wsmooth', None) is None:
wlist = (self.Wx, self.Wxx)
wlist = (self.Wxx)
if self.regmesh.dim > 1:
wlist += (self.Wy, self.Wyy)
wlist += (self.Wyy)
if self.regmesh.dim > 2:
wlist += (self.Wz, self.Wzz)
wlist += (self.Wzz)
self._Wsmooth = sp.vstack(wlist)
return self._Wsmooth
@property
def W(self):
"""Full regularization matrix W"""
if getattr(self, '_W', None) is None:
wlist = (self.Wsmall, self.Wsmooth)
self._W = sp.vstack(wlist)
return self._W
@Utils.timeIt
def _evalSmall(self, m):
r = self.Wsmall * ( self.mapping * (m - self.mref) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmooth(self, m):
def _evalSmoothxx(self, m):
if self.mrefInSmooth == True:
r = self.Wsmooth * ( self.mapping * (m - self.mref) )
r = self.Wxx * ( self.mapping * (m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wsmooth * ( self.mapping * (m) )
r = self.Wxx * ( self.mapping * (m) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmoothyy(self, m):
if self.mrefInSmooth == True:
r = self.Wyy * ( self.mapping * (m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wyy * ( self.mapping * (m) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmoothzz(self, m):
if self.mrefInSmooth == True:
r = self.Wzz * ( self.mapping * (m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wzz * ( self.mapping * (m) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmooth2(self, m):
phiSmooth2 = self._evalSmoothxx(m)
if self.regmesh.dim > 1:
phiSmooth2 += self._evalSmoothyy(m)
if self.regmesh.dim > 2:
phiSmooth2 += self._evalSmoothzz(m)
return phiSmooth2
@Utils.timeIt
def _evalSmoothxxDeriv(self, m):
if self.mrefInSmooth == True:
r = self.Wxx * ( self.mapping * ( m - self.mref ) )
return r.T * ( self.Wxx * self.mapping.deriv(m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wxx * ( self.mapping * m )
return r.T * ( self.Wxx * self.mapping.deriv(m) )
@Utils.timeIt
def _evalSmoothyyDeriv(self, m):
if self.mrefInSmooth == True:
r = self.Wyy * ( self.mapping * ( m - self.mref ) )
return r.T * ( self.Wyy * self.mapping.deriv(m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wyy * ( self.mapping * m )
return r.T * ( self.Wyy * self.mapping.deriv(m) )
@Utils.timeIt
def _evalSmoothzzDeriv(self, m):
if self.mrefInSmooth == True:
r = self.Wzz * ( self.mapping * ( m - self.mref ) )
return r.T * ( self.Wzz * self.mapping.deriv(m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wzz * ( self.mapping * m )
return r.T * ( self.Wzz * self.mapping.deriv(m) )
@Utils.timeIt
def _evalSmoothxx2Deriv(self, m, v=None):
if self.mrefInSmooth == True:
rDeriv = self.Wxx * ( self.mapping.deriv( m - self.mref ) )
elif self.mrefInSmooth == False:
rDeriv = self.Wxx * self.mapping.deriv(m)
if v is not None:
return rDeriv.T * (rDeriv * v)
return rDeriv.T * rDeriv
@Utils.timeIt
def _evalSmoothyy2Deriv(self, m, v=None):
if self.mrefInSmooth == True:
rDeriv = self.Wyy * ( self.mapping.deriv( m - self.mref ) )
elif self.mrefInSmooth == False:
rDeriv = self.Wyy * self.mapping.deriv(m)
if v is not None:
return rDeriv.T * (rDeriv * v)
return rDeriv.T * rDeriv
@Utils.timeIt
def _evalSmoothzz2Deriv(self, m, v=None):
if self.mrefInSmooth == True:
rDeriv = self.Wzz * ( self.mapping.deriv( m - self.mref ) )
elif self.mrefInSmooth == False:
rDeriv = self.Wzz * self.mapping.deriv(m)
if v is not None:
return rDeriv.T * (rDeriv * v)
return rDeriv.T * rDeriv
@Utils.timeIt
def _evalSmoothDeriv2(self, m):
deriv = self._evalSmoothxxDeriv(m)
if self.regmesh.dim > 1:
deriv += self._evalSmoothyyDeriv(m)
if self.regmesh.dim > 2:
deriv += self._evalSmoothzzDeriv(m)
return deriv
@Utils.timeIt
def _evalSmooth2Deriv2(self, m, v=None):
deriv = self._evalSmoothxx2Deriv(m, v)
if self.regmesh.dim > 1:
deriv += self._evalSmoothyy2Deriv(m, v)
if self.regmesh.dim > 2:
deriv += self._evalSmoothzz2Deriv(m, v)
return deriv
@Utils.timeIt
def eval(self, m):
return self._evalSmall(m) + self._evalSmooth(m)
@Utils.timeIt
def _evalSmallDeriv(self,m):
r = self.Wsmall * ( self.mapping * (m - self.mref) )
return r.T * ( self.Wsmall * self.mapping.deriv(m - self.mref) )
@Utils.timeIt
def _evalSmoothDeriv(self,m):
if self.mrefInSmooth == True:
r = self.Wsmooth * ( self.mapping * ( m - self.mref ) )
return r.T * ( self.Wsmooth * self.mapping.deriv(m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wsmooth * ( self.mapping * m )
return r.T * ( self.Wsmooth * self.mapping.deriv(m) )
return self._evalSmall(m) + self._evalSmooth(m) + self._evalSmooth2(m)
@Utils.timeIt
def evalDeriv(self, m):
@@ -560,184 +868,134 @@ class Tikhonov(BaseRegularization):
R(m) = \mathbf{W^\\top W (m-m_\\text{ref})}
"""
return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m)
return self._evalSmallDeriv(m) + self._evalSmoothDeriv(m) + self._evalSmoothDeriv2(m)
def eval2Deriv(self, m, v=None):
"""
The regularization is:
.. math::
R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top W(m-m_\\text{ref})}
So the derivative is straight forward:
.. math::
R(m) = \mathbf{W^\\top W (m-m_\\text{ref})}
"""
return self._evalSmall2Deriv(m, v) + self._evalSmooth2Deriv(m, v) + self._evalSmooth2Deriv2(m, v)
class Simple(Tikhonov):
class Sparse(Simple):
"""
Simple regularization that does not include length scales in the derivatives.
The regularization is:
.. math::
R(m) = \\frac{1}{2}\mathbf{(m-m_\\text{ref})^\\top W^\\top R^\\top R W(m-m_\\text{ref})}
where the IRLS weight
.. math::
R = \eta TO FINISH LATER!!!
So the derivative is straight forward:
.. math::
R(m) = \mathbf{W^\\top R^\\top R W (m-m_\\text{ref})}
The IRLS weights are recomputed after each beta solves.
It is strongly recommended to do a few Gauss-Newton iterations
before updating.
"""
mrefInSmooth = False #: SMOOTH and SMOOTH_MOD_DIF options
alpha_s = Utils.dependentProperty('_alpha_s', 1.0, ['_W', '_Wsmall'], "Smallness weight")
alpha_x = Utils.dependentProperty('_alpha_x', 1.0, ['_W', '_Wx'], "Weight for the first derivative in the x direction")
alpha_y = Utils.dependentProperty('_alpha_y', 1.0, ['_W', '_Wy'], "Weight for the first derivative in the y direction")
alpha_z = Utils.dependentProperty('_alpha_z', 1.0, ['_W', '_Wz'], "Weight for the first derivative in the z direction")
wght = 1.
# set default values
eps_p = 1e-1 # Threshold value for the model norm
eps_q = 1e-1 # Threshold value for the model gradient norm
curModel = None # Requires model to compute the weights
l2model = None
gamma = 1. # Model norm scaling to smooth out convergence
norms = [0., 2., 2., 2.] # Values for norm on (m, dmdx, dmdy, dmdz)
cell_weights = 1. # Consider overwriting with sensitivity weights
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
BaseRegularization.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
if isinstance(self.wght,float):
self.wght = np.ones(self.regmesh.nC) * self.wght
if isinstance(self.cell_weights,float):
self.cell_weights = np.ones(self.regmesh.nC) * self.cell_weights
@property
def Wsmall(self):
"""Regularization matrix Wsmall"""
if getattr(self,'_Wsmall', None) is None:
self._Wsmall = Utils.sdiag((self.regmesh.vol*self.alpha_s*self.wght)**0.5)
if getattr(self, 'curModel', None) is None:
self.Rs = Utils.speye(self.regmesh.nC)
else:
f_m = self.mapping * (self.curModel - self.reg.mref)
self.rs = self.R(f_m , self.eps_p, self.norms[0])
self.Rs = Utils.sdiag( self.rs )
self._Wsmall = Utils.sdiag((self.alpha_s*self.gamma*self.cell_weights)**0.5)*self.Rs
return self._Wsmall
@property
def Wx(self):
"""Regularization matrix Wx"""
if getattr(self, '_Wx', None) is None:
self._Wx = Utils.sdiag((self.regmesh.aveCC2Fx * self.regmesh.vol*self.alpha_x*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.regmesh.cellDiffxStencil
if getattr(self,'_Wx', None) is None:
if getattr(self, 'curModel', None) is None:
self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0])
else:
f_m = self.regmesh.cellDiffxStencil * (self.mapping * self.curModel)
self.rx = self.R( f_m , self.eps_q, self.norms[1])
self.Rx = Utils.sdiag( self.rx )
self._Wx = Utils.sdiag(( self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.cell_weights))**0.5)*self.Rx*self.regmesh.cellDiffxStencil
return self._Wx
@property
def Wy(self):
"""Regularization matrix Wy"""
if getattr(self, '_Wy', None) is None:
self._Wy = Utils.sdiag((self.regmesh.aveCC2Fy * self.regmesh.vol * self.alpha_y*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.regmesh.cellDiffyStencil
if getattr(self,'_Wy', None) is None:
if getattr(self, 'curModel', None) is None:
self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0])
else:
f_m = self.regmesh.cellDiffyStencil * (self.mapping * self.curModel)
self.ry = self.R( f_m , self.eps_q, self.norms[2])
self.Ry = Utils.sdiag( self.ry )
self._Wy = Utils.sdiag((self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.cell_weights))**0.5)*self.Ry*self.regmesh.cellDiffyStencil
return self._Wy
@property
def Wz(self):
"""Regularization matrix Wz"""
if getattr(self, '_Wz', None) is None:
self._Wz = Utils.sdiag((self.regmesh.aveCC2Fz * self.regmesh.vol*self.alpha_z*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.regmesh.cellDiffzStencil
if getattr(self,'_Wz', None) is None:
if getattr(self, 'curModel', None) is None:
self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0])
else:
f_m = self.regmesh.cellDiffzStencil * (self.mapping * self.curModel)
self.rz = self.R( f_m , self.eps_q, self.norms[3])
self.Rz = Utils.sdiag( self.rz )
self._Wz = Utils.sdiag((self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.cell_weights))**0.5)*self.Rz*self.regmesh.cellDiffzStencil
return self._Wz
@property
def Wsmooth(self):
"""Full smoothness regularization matrix W"""
if getattr(self, '_Wsmooth', None) is None:
wlist = (self.Wx,)
if self.regmesh.dim > 1:
wlist += (self.Wy,)
if self.regmesh.dim > 2:
wlist += (self.Wz,)
self._Wsmooth = sp.vstack(wlist)
return self._Wsmooth
@property
def W(self):
"""Full regularization matrix W"""
if getattr(self, '_W', None) is None:
wlist = (self.Wsmall, self.Wsmooth)
self._W = sp.vstack(wlist)
return self._W
@Utils.timeIt
def _evalSmall(self, m):
r = self.Wsmall * ( self.mapping * (m - self.mref) )
return 0.5 * r.dot(r)
@Utils.timeIt
def _evalSmooth(self, m):
if self.mrefInSmooth == True:
r = self.Wsmooth * ( self.mapping * (m - self.mref) )
elif self.mrefInSmooth == False:
r = self.Wsmooth * ( self.mapping * m)
return 0.5 * r.dot(r)
class Sparse(Simple):
# set default values
eps_p = 1e-1
eps_q = 1e-1
curModel = None # use a model to compute the weights
gamma = 1.
norms = [0., 2., 2., 2.]
wght = 1.
def __init__(self, mesh, mapping=None, indActive=None, **kwargs):
Simple.__init__(self, mesh, mapping=mapping, indActive=indActive, **kwargs)
if isinstance(self.wght,float):
self.wght = np.ones(self.regmesh.nC) * self.wght
@property
def Wsmall(self):
"""Regularization matrix Wsmall"""
if getattr(self, 'curModel', None) is None:
self.Rs = Utils.speye(self.regmesh.nC)
else:
f_m = self.curModel - self.reg.mref
self.rs = self.R(f_m , self.eps_p, self.norms[0])
#print "Min rs: " + str(np.max(self.rs)) + "Max rs: " + str(np.min(self.rs))
self.Rs = Utils.sdiag( self.rs )
return Utils.sdiag((self.regmesh.vol*self.alpha_s*self.gamma*self.wght)**0.5)*self.Rs
@property
def Wx(self):
"""Regularization matrix Wx"""
if getattr(self, 'curModel', None) is None:
self.Rx = Utils.speye(self.regmesh.cellDiffxStencil.shape[0])
else:
f_m = self.regmesh.cellDiffxStencil * self.curModel
self.rx = self.R( f_m , self.eps_q, self.norms[1])
self.Rx = Utils.sdiag( self.rx )
return Utils.sdiag(( (self.regmesh.aveCC2Fx * self.regmesh.vol) *self.alpha_x*self.gamma*(self.regmesh.aveCC2Fx*self.wght))**0.5)*self.Rx*self.regmesh.cellDiffxStencil
@property
def Wy(self):
"""Regularization matrix Wy"""
if getattr(self, 'curModel', None) is None:
self.Ry = Utils.speye(self.regmesh.cellDiffyStencil.shape[0])
else:
f_m = self.regmesh.cellDiffyStencil * self.curModel
self.ry = self.R( f_m , self.eps_q, self.norms[2])
self.Ry = Utils.sdiag( self.ry )
return Utils.sdiag(((self.regmesh.aveCC2Fy * self.regmesh.vol)*self.alpha_y*self.gamma*(self.regmesh.aveCC2Fy*self.wght))**0.5)*self.Ry*self.regmesh.cellDiffyStencil
@property
def Wz(self):
"""Regularization matrix Wz"""
if getattr(self, 'curModel', None) is None:
self.Rz = Utils.speye(self.regmesh.cellDiffzStencil.shape[0])
else:
f_m = self.regmesh.cellDiffzStencil * self.curModel
self.rz = self.R( f_m , self.eps_q, self.norms[3])
self.Rz = Utils.sdiag( self.rz )
return Utils.sdiag(((self.regmesh.aveCC2Fz * self.regmesh.vol)*self.alpha_z*self.gamma*(self.regmesh.aveCC2Fz*self.wght))**0.5)*self.Rz*self.regmesh.cellDiffzStencil
@property
def Wsmooth(self):
"""Full smoothness regularization matrix W"""
#if getattr(self, '_Wsmooth', None) is None:
wlist = (self.Wx,)
if self.regmesh.dim > 1:
wlist += (self.Wy,)
if self.regmesh.dim > 2:
wlist += (self.Wz,)
#self._Wsmooth = sp.vstack(wlist)
return sp.vstack(wlist)
@property
def W(self):
"""Full regularization matrix W"""
if getattr(self, '_W', None) is None:
wlist = (self.Wsmall, self.Wsmooth)
self._W = sp.vstack(wlist)
return self._W
def R(self, f_m , eps, exponent):
# Eta scaling is important for mix-norms...do not mess with it
eta = (eps**(1.-exponent/2.))**0.5
r = eta / (f_m**2.+ eps**2.)**((1.-exponent/2.)/2.)
+8 -9
View File
@@ -26,7 +26,7 @@ class BaseRx(object):
def rxType(self, value):
known = self.knownRxTypes
if known is not None:
assert value in known, "rxType must be in ['%s']" % ("', '".join(known))
assert value in known, "rxType must be in ['{0!s}']".format(("', '".join(known)))
self._rxType = value
@property
@@ -125,7 +125,7 @@ class BaseSrc(object):
def __init__(self, rxList, **kwargs):
assert type(rxList) is list, 'rxList must be a list'
for rx in rxList:
assert isinstance(rx, self.rxPair), 'rxList must be a %s'%self.rxPair.__name__
assert isinstance(rx, self.rxPair), 'rxList must be a {0!s}'.format(self.rxPair.__name__)
assert len(set(rxList)) == len(rxList), 'The rxList must be unique'
self.uid = str(uuid.uuid4())
self.rxList = rxList
@@ -227,7 +227,7 @@ class BaseSurvey(object):
@srcList.setter
def srcList(self, value):
assert type(value) is list, 'srcList must be a list'
assert np.all([isinstance(src, self.srcPair) for src in value]), 'All sources must be instances of %s' % self.srcPair.__name__
assert np.all([isinstance(src, self.srcPair) for src in value]), 'All sources must be instances of {0!s}'.format(self.srcPair.__name__)
assert len(set(value)) == len(value), 'The srcList must be unique'
self._srcList = value
self._sourceOrder = dict()
@@ -238,10 +238,10 @@ class BaseSurvey(object):
sources = [sources]
for src in sources:
if getattr(src,'uid',None) is None:
raise KeyError('Source does not have a uid: %s'%str(src))
raise KeyError('Source does not have a uid: {0!s}'.format(str(src)))
inds = map(lambda src: self._sourceOrder.get(src.uid, None), sources)
if None in inds:
raise KeyError('Some of the sources specified are not in this survey. %s'%str(inds))
raise KeyError('Some of the sources specified are not in this survey. {0!s}'.format(str(inds)))
return inds
@property
@@ -263,7 +263,7 @@ class BaseSurvey(object):
def pair(self, p):
"""Bind a problem to this survey instance using pointers"""
assert hasattr(p, 'surveyPair'), "Problem must have an attribute 'surveyPair'."
assert isinstance(self, p.surveyPair), "Problem requires survey object must be an instance of a %s class."%(p.surveyPair.__name__)
assert isinstance(self, p.surveyPair), "Problem requires survey object must be an instance of a {0!s} class.".format((p.surveyPair.__name__))
if p.ispaired:
raise Exception("The problem object is already paired to a survey. Use prob.unpair()")
self._prob = p
@@ -311,7 +311,6 @@ class BaseSurvey(object):
if f is None: f = self.prob.fields(m)
return Utils.mkvc(self.eval(f))
@Utils.count
def eval(self, f):
"""eval(f)
@@ -322,7 +321,7 @@ class BaseSurvey(object):
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, f):
@@ -334,7 +333,7 @@ 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, f=None):
+9 -10
View File
@@ -4,7 +4,6 @@ from SimPEG.Utils import mkvc, sdiag, diagEst
from SimPEG import Utils
from SimPEG.Mesh import TensorMesh, CurvilinearMesh, CylMesh
from SimPEG.Mesh.TreeMesh import TreeMesh as Tree
import numpy as np
import scipy.sparse as sp
import unittest
import inspect
@@ -200,10 +199,10 @@ class OrderTest(unittest.TestCase):
print '_____________________________________________'
print ' h | error | e(i-1)/e(i) | order'
print '~~~~~~|~~~~~~~~~~~~~|~~~~~~~~~~~~~|~~~~~~~~~~'
print '%4i | %8.2e |' % (nc, err)
print '{0:4d} | {1:8.2e} |'.format(nc, err)
else:
order.append(np.log(err/err_old)/np.log(max_h/max_h_old))
print '%4i | %8.2e | %6.4f | %6.4f' % (nc, err, err_old/err, order[-1])
print '{0:4d} | {1:8.2e} | {2:6.4f} | {3:6.4f}'.format(nc, err, err_old/err, order[-1])
err_old = err
max_h_old = max_h
print '---------------------------------------------'
@@ -237,7 +236,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
@@ -258,8 +257,8 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole
Tests.checkDerivative(simplePass, np.random.randn(5))
"""
print "%s checkDerivative %s" % ('='*20, '='*20)
print "iter h |ft-f0| |ft-f0-h*J0*dx| Order\n%s" % ('-'*57)
print "{0!s} checkDerivative {1!s}".format('='*20, '='*20)
print "iter h |ft-f0| |ft-f0-h*J0*dx| Order\n{0!s}".format(('-'*57))
f0, J0 = fctn(x0)
@@ -290,7 +289,7 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole
order0 = np.log10(E0[:-1]/E0[1:])
order1 = np.log10(E1[:-1]/E1[1:])
print " %d %1.2e %1.3e %1.3e %1.3f" % (i, h[i], E0[i], E1[i], np.nan if i == 0 else order1[i-1])
print " {0:d} {1:1.2e} {2:1.3e} {3:1.3e} {4:1.3f}".format(i, h[i], E0[i], E1[i], np.nan if i == 0 else order1[i-1])
# Ensure we are about precision
order0 = order0[E0[1:] > eps]
@@ -302,10 +301,10 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole
passTest = belowTol or correctOrder
if passTest:
print "%s PASS! %s" % ('='*25, '='*25)
print "{0!s} PASS! {1!s}".format('='*25, '='*25)
print happiness[np.random.randint(len(happiness))]+'\n'
else:
print "%s\n%s FAIL! %s\n%s" % ('*'*57, '<'*25, '>'*25, '*'*57)
print "{0!s}\n{1!s} FAIL! {2!s}\n{3!s}".format('*'*57, '<'*25, '>'*25, '*'*57)
print sadness[np.random.randint(len(sadness))]+'\n'
@@ -314,7 +313,7 @@ def checkDerivative(fctn, x0, num=7, plotIt=True, dx=None, expectedOrder=2, tole
ax = ax or plt.subplot(111)
ax.loglog(h, E0, 'b')
ax.loglog(h, E1, 'g--')
ax.set_title('Check Derivative - %s' % ('PASSED :)' if passTest else 'FAILED :('))
ax.set_title('Check Derivative - {0!s}'.format(('PASSED :)' if passTest else 'FAILED :(')))
ax.set_xlabel('h')
ax.set_ylabel('Error')
leg = ax.legend(['$\mathcal{O}(h)$', '$\mathcal{O}(h^2)$'], loc='best',
+13 -13
View File
@@ -7,11 +7,11 @@ def addBlock(gridCC, modelCC, p0, p1, blockProp):
"""
Add a block to an exsisting cell centered model, modelCC
:param numpy.array, gridCC: mesh.gridCC is the cell centered grid
:param numpy.array, modelCC: cell centered model
:param numpy.array, p0: bottom, southwest corner of block
:param numpy.array, p1: top, northeast corner of block
:blockProp float, blockProp: property to assign to the model
:param numpy.array gridCC: mesh.gridCC is the cell centered grid
:param numpy.array modelCC: cell centered model
:param numpy.array p0: bottom, southwest corner of block
:param numpy.array p1: top, northeast corner of block
:blockProp float blockProp: property to assign to the model
:return numpy.array, modelBlock: model with block
"""
@@ -147,7 +147,7 @@ def getIndicesSphere(center,radius,ccMesh):
if dimMesh == 1:
# Define the reference points
ind = np.abs(center[0] - ccMesh[:,0]) < radius
elif dimMesh == 2:
@@ -222,14 +222,14 @@ def layeredModel(ccMesh, layerTops, layerValues):
:param numpy.array ccMesh: cell-centered mesh
:param numpy.array layerTops: z-locations of the tops of each layer
:param numpy.array layerValue: values of the property to assign for each layer (starting at the top)
:param numpy.array layerValue: values of the property to assign for each layer (starting at the top)
:rtype: numpy.array
:return: M, layered model on the mesh
:return: M, layered model on the mesh
"""
descending = np.linalg.norm(sorted(layerTops, reverse=True) - layerTops) < 1e-20
# TODO: put an error check to make sure that there is an ordering... needs to work with inf elts
# TODO: put an error check to make sure that there is an ordering... needs to work with inf elts
# assert ascending or descending, "Layers must be listed in either ascending or descending order"
# start from bottom up
@@ -253,10 +253,10 @@ def layeredModel(ccMesh, layerTops, layerValues):
model = np.zeros(ccMesh.shape[0])
for i, top in enumerate(layerTops):
zind = z <= top
zind = z <= top
model[zind] = layerValues[i]
return model
return model
@@ -265,9 +265,9 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=None):
Create a random model by convolving a kernel with a
uniformly distributed model.
:param 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
+8 -8
View File
@@ -8,12 +8,12 @@ def _checkAccuracy(A, b, X, accuracyTol):
if nrm_b > 0:
nrm /= nrm_b
if nrm > accuracyTol:
msg = '### SolverWarning ###: Accuracy on solve is above tolerance: %e > %e' % (nrm, accuracyTol)
msg = '### SolverWarning ###: Accuracy on solve is above tolerance: {0:e} > {1:e}'.format(nrm, accuracyTol)
print msg
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):
+1 -1
View File
@@ -7,4 +7,4 @@ from CounterUtils import *
import ModelBuilder
import SolverUtils
from coordutils import *
from plottingUtils import *
from modelutils import *
+15 -15
View File
@@ -32,7 +32,7 @@ def memProfileWrapper(towrap, *funNames):
if hasattr(towrap,f):
attrs[f] = profile(getattr(towrap,f))
else:
print '%s not found in %s Class' % (f, towrap.__name__)
print '{0!s} not found in {1!s} Class'.format(f, towrap.__name__)
return type(towrap.__name__ + 'MemProfileWrap', (towrap,), attrs)
@@ -65,7 +65,7 @@ def setKwargs(obj, ignore=None, **kwargs):
if hasattr(obj, attr):
setattr(obj, attr, kwargs[attr])
else:
raise Exception('%s attr is not recognized' % attr)
raise Exception('{0!s} attr is not recognized'.format(attr))
hook(obj,hook, silent=True)
hook(obj,setKwargs, silent=True)
@@ -74,7 +74,7 @@ def printTitles(obj, printers, name='Print Titles', pad=''):
titles = ''
widths = 0
for printer in printers:
titles += ('{:^%i}'%printer['width']).format(printer['title']) + ''
titles += ('{{:^{0:d}}}'.format(printer['width'])).format(printer['title']) + ''
widths += printer['width']
print pad + "{0} {1} {0}".format('='*((widths-1-len(name))/2), name)
print pad + titles
@@ -83,7 +83,7 @@ def printTitles(obj, printers, name='Print Titles', pad=''):
def printLine(obj, printers, pad=''):
values = ''
for printer in printers:
values += ('{:^%i}'%printer['width']).format(printer['format'] % printer['value'](obj))
values += ('{{:^{0:d}}}'.format(printer['width'])).format(printer['format'] % printer['value'](obj))
print pad + values
def checkStoppers(obj, stoppers):
@@ -104,12 +104,12 @@ def checkStoppers(obj, stoppers):
return (len(optimal)>0 and all(optimal)) | (len(critical)>0 and any(critical))
def printStoppers(obj, stoppers, pad='', stop='STOP!', done='DONE!'):
print pad + "%s%s%s" % ('-'*25,stop,'-'*25)
print pad + "{0!s}{1!s}{2!s}".format('-'*25, stop, '-'*25)
for stopper in stoppers:
l = stopper['left'](obj)
r = stopper['right'](obj)
print pad + stopper['str'] % (l<=r,l,r)
print pad + "%s%s%s" % ('-'*25,done,'-'*25)
print pad + "{0!s}{1!s}{2!s}".format('-'*25, done, '-'*25)
def callHooks(match, mainFirst=False):
"""
@@ -144,14 +144,14 @@ def callHooks(match, mainFirst=False):
extra = """
If you have things that also need to run in the method %s, you can create a method::
If you have things that also need to run in the method {0!s}, you can create a method::
def _%s*(self, ... ):
def _{1!s}*(self, ... ):
pass
Where the * can be any string. If present, _%s* will be called at the start of the default %s call.
Where the * can be any string. If present, _{2!s}* will be called at the start of the default {3!s} call.
You may also completely overwrite this function.
""" % (match, match, match, match)
""".format(match, match, match, match)
doc = wrapper.__doc__
wrapper.__doc__ = ('' if doc is None else doc) + extra
return wrapper
@@ -186,7 +186,7 @@ def asArray_N_x_Dim(pts, dim):
elif len(pts.shape) == 1:
pts = pts[:,np.newaxis]
assert pts.shape[1] == dim, "pts must be a column vector of shape (nPts, %d) not (%d, %d)" % ((dim,)+pts.shape)
assert pts.shape[1] == dim, "pts must be a column vector of shape (nPts, {0:d}) not ({1:d}, {2:d})".format(*((dim,)+pts.shape))
return pts
@@ -207,17 +207,17 @@ def requires(var):
.. note::
To use survey.%s(), SimPEG requires that a problem be bound to the survey.
To use survey.{0!s}(), SimPEG requires that a problem be bound to the survey.
If a problem has not been bound, an Exception will be raised.
To bind a problem to the Data object::
survey.pair(myProblem)
""" % f.__name__
""".format(f.__name__)
else:
extra = """
To use *%s* method, SimPEG requires that the %s be specified.
""" % (f.__name__, var)
To use *{0!s}* method, SimPEG requires that the {1!s} be specified.
""".format(f.__name__, var)
@wraps(f)
def requiresVarWrapper(self,*args,**kwargs):
if getattr(self, var, None) is None:
+1 -1
View File
@@ -80,7 +80,7 @@ def indexCube(nodes, gridSize, n=None):
# Make sure that we choose from the possible nodes.
possibleNodes = 'ABCD' if gridSize.size == 2 else 'ABCDEFGH'
for node in nodes:
assert node in possibleNodes, "Nodes must be chosen from: '%s'" % possibleNodes
assert node in possibleNodes, "Nodes must be chosen from: '{0!s}'".format(possibleNodes)
dim = gridSize.size
if n is None:
n = gridSize - 1
+1 -1
View File
@@ -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::
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -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:
@@ -278,7 +278,7 @@ class TensorType(object):
else:
raise Exception('Unexpected shape of tensor')
def __str__(self):
return 'TensorType[%i]: %s' % (self._tt, self._tts)
return 'TensorType[{0:d}]: {1!s}'.format(self._tt, self._tts)
def __eq__(self, v): return self._tt == v
def __le__(self, v): return self._tt <= v
def __ge__(self, v): return self._tt >= v
@@ -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
View File
@@ -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) \
+63
View File
@@ -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 {0!s} mesh'.format(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 {0!s} mesh'.format(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)
-3
View File
@@ -1,3 +0,0 @@
# Plot Tree!
# Plot SphereSetup
# Plot LayerEarth
+1 -1
View File
@@ -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
View File
@@ -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
+22
View File
@@ -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 %}
-19
View File
@@ -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
-36
View File
@@ -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:

Some files were not shown because too many files have changed in this diff Show More