Compare commits

..
248 Commits
Author SHA1 Message Date
GudniRos 2fcdabf3d5 Fixed directive to save iteration dictionary. 2016-06-09 12:39:25 -07:00
GudniRos b965c96242 Updating examples by running python __init__.py 2016-06-07 13:48:29 -07:00
GudniRos f06ba238f8 Fixing Examples/__init__.py after merge conflict 2016-06-07 13:14:36 -07:00
GudniRos 11408a3788 Fixing an FDEM import to be more explicit 2016-06-07 11:52:29 -07:00
GudniRos 358e2f96af Pull request #328 on github.
Fixing MT namespace to NSEM.
2016-06-07 10:54:16 -07:00
GudniRos cf5181016f Made MT_1d_analytic_nLayer_Earth.run have default n layers of 3.
Trying to fix example testing.
2016-06-07 09:45:02 -07:00
GudniRos d1f7d0c37a Adding ipywidgets to the conda install list for travis 2016-06-01 21:54:19 -07:00
GudniRos 50c4a6caf8 Refactor and updated tests 2016-06-01 20:53:12 -07:00
GudniRos b3029b697b Adjust settings for the MT1D inversion example 2016-06-01 12:00:52 -07:00
GudniRos 8d4581e92f Cleaned MT_1D inverison example 2016-06-01 11:55:12 -07:00
Gudni Karl Rosenkjaer 0a44796d4c Merge pull request #329 from simpeg/em/dev
Em/dev into mt/dev
2016-06-01 11:17:19 -07:00
GudniRos 8117ee3b06 Fixing MT_1D example, runs but inversion results should be better. 2016-06-01 10:22:18 -07:00
GudniRos fb7f5a53d4 Working on examples 2016-06-01 01:05:21 -07:00
GudniRos f34314bba2 Fixed tests and Jvec 2016-05-31 22:33:57 -07:00
GudniRos 7087632701 Fixing name space, updating utils 2016-05-31 22:06:47 -07:00
Lindsey 382b31bd12 Merge pull request #310 from simpeg/ref/regularization
modularizing regularization
2016-05-31 14:09:54 -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
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
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
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
GudniRos 6165e619ed Moving Problem1D/3D folders to NSEM file
Looking at making Jvec more general.
2016-05-10 16:07:45 -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
GudniRos 1ab67b5790 Updated MT-->NSEM for all the classes.
Changed Vertical1DMap --> SurjectVertical1D
2016-05-10 14:41:20 -07:00
D Fournier fb5434695f Alpha_s default to 1.0 2016-05-10 14:31:45 -07:00
Gudni Karl Rosenkjaer a96e9e08d7 Merge pull request #316 from simpeg/em/dev
Em/dev into mt/NSEMrefact
2016-05-10 14:09:13 -07:00
GudniRos b1569e5734 Changes to MT1D analytic example 2016-05-10 14:00:48 -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
Lindsey 906cca30f3 Merge pull request #311 from simpeg/feat/cyl2cartinterp
Feat/cyl2cartinterp
2016-05-09 08:24:16 -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
Lindsey Heagy 8278230476 Use LocTypeTo to allow interpolation to different grid locations 2016-05-08 10:35:27 -07:00
Lindsey Heagy 069127333d allow interpolation to different cartsian grid locations 2016-05-05 16:41:21 -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 79e1378009 Merge pull request #305 from simpeg/feat/sparse-regularization
Feat/sparse regularization
2016-05-04 22:30:06 -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
D Fournier 4e296c4cd5 Update PreCond Directive to allow inactive cells mapping 2016-05-04 16:01:29 -07:00
seogi_macbook c488dabf9a working on IP 2016-05-04 12:48:29 -07:00
Lindsey 5e1de61a71 Merge pull request #308 from simpeg/bug/reg-indactive
if mapping is none, create an identity map that is size indactive.nonzero
2016-05-03 21:20:54 -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
Lindsey Heagy 00bbe0f35e if mapping is none, create an identity map that is size indactive.nonzero for regularization 2016-05-03 15:04:36 -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
GudniRos 22f0a742e7 Fixed UBC mesh read in function 2016-05-02 05:16:56 -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
D Fournier 3d1dfc13d7 Change Update_PreConditioner to default False 2016-04-29 15:49:44 -07:00
D Fournier a6e995e9fb Merge branch 'feat/meshutils' into feat/sparse-regularization 2016-04-29 15:42:42 -07:00
D Fournier 056dc09fa6 Fix Update_Precondition directive 2016-04-29 15:10:30 -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
Rowan Cockett 00db6746d4 Add a warnign about mesh attributes 2016-04-29 11:50:56 -07:00
Rowan Cockett 028a16a45a Syntax bug. 2016-04-29 11:44:42 -07:00
Rowan Cockett c83b460672 Surface to Indices (GoCAD and VTK) 2016-04-29 11:43:31 -07:00
D Fournier 225394f74e Latest commit 2016-04-29 11:10:04 -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
D Fournier d8bfb27415 Quick fix to MeshIO 2016-04-23 15:25:44 -07: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
D Fournier 79183ae9fb fIX MESH io 2016-04-22 16:05:43 -07:00
D Fournier 606488d152 Major fix to IRLS. 2016-04-21 21:58:40 -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
GudniRos 18357a11da Fixing analytic function 2016-04-15 14:48:58 -07:00
GudniRos abc5d72725 Merge branch 'em/dev' into mt/dev 2016-04-15 13:29:39 -07:00
GudniRos 23d2783bc1 Finalizing the pull request from mt/iss290 in to dev. 2016-04-15 12:31:00 -07:00
GudniRos b58ba55ffd Merge branch 'mt/iss290' into dev 2016-04-15 12:21:57 -07:00
GudniRos 0d6fe5f7a1 Merge branch 'dev' into mt/iss290 2016-04-15 12:03:09 -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
Lindsey bd318f0092 Merge pull request #294 from simpeg/patch/mutable-arguments
remove mutable arguments.
2016-04-08 17:12:20 -07:00
GudniRos 90b0301408 Fixing bug in write out. 2016-04-08 09:40:26 -07:00
GudniRos 083742cb40 Removing repeated directives 2016-04-08 09:34:30 -07:00
Lindsey 2a351be971 Merge pull request #289 from simpeg/patch/sparse-dcip
Patch/sparse dcip
2016-04-07 18:43:07 -07:00
Rowan Cockett 3e4f47711c remove mutable arguments. 2016-04-07 16:35:47 -07:00
D Fournier e305600de5 Update example list. Add comments for the DC_Forward_PseudoSection example. Fix Z of pseudo section plot. 2016-04-07 13:09:28 -07:00
GudniRos 8a18e479ab Removed the testProjDeriv (not needed, included in Jvec). 2016-04-07 11:48:17 -07:00
D Fournier d13c540be0 Uppercase on class names. Add flag for Directive.Update_Wj. Remove trailing spaces. Remove old DC example. 2016-04-07 09:25:20 -07:00
GudniRos f15a628136 Moved the osr import into the projection function. 2016-04-07 09:01:30 -07:00
GudniRos fb60f45a3c Fixed osr import in ediFilesUtils, moved into class which imports only on build up.
Fixed the boolean error in Directives.
2016-04-07 08:46:51 -07:00
D Fournier 822f6d333d Minor revisions + remove trailing white spaces 2016-04-06 22:29:57 -07:00
D Fournier 6000034826 Merge branch 'dcip/dev' into patch/sparse-dcip 2016-04-06 22:18:31 -07:00
D Fournier 16c6cc8d74 Update speudo plot and allow app_res, app_con, volt 2016-04-06 22:17:34 -07:00
Lindsey Heagy 636d178fbf removed examples that are in Examples PR 2016-04-06 16:19:39 -07:00
Lindsey 0575490f56 Merge pull request #288 from simpeg/feat/gitter-badge
Add gitter chat
2016-04-06 16:15:59 -07:00
Lindsey Heagy ae9ca6cec9 Merge branch 'feat/sparse-regularization' into patch/sparse-dcip
# Conflicts:
#	SimPEG/Examples/__init__.py
#	SimPEG/Optimization.py
2016-04-06 14:53:45 -07:00
D Fournier f799733a9d Fix TwoSphere example and Utils.pseudoPlot 2016-04-06 14:43:33 -07:00
Rowan Cockett 2bd5829b42 Add gitter chat 2016-04-06 13:15:03 -07:00
D Fournier 8b94cd4dfe Change flag for convertObs_DC3D_to_2D, which broke the example 2016-04-06 09:14:14 -07:00
D Fournier 09f3f7b55b Merge branch 'dev' into dcip/dev 2016-04-06 09:03:37 -07:00
D Fournier 15d59a5b50 Fix typos in Directives.update_Wj. overseer @lheagy 2016-04-06 09:00:13 -07:00
D Fournier e646211e7d Review Utils.gen_DCIPsurvey ... lets keep it. 2016-04-06 08:55:52 -07:00
D Fournier ba977206ea Create sensitivity re-weighting directive
Adapt Map/polymap for actInd (topography)
2016-04-06 07:22:18 -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 d8aec96080 Merge branch 'master' into dev 2016-04-05 17:51:27 -07:00
Lindsey aad596a8cc Merge pull request #282 from simpeg/example/EM_FDEM_1D_Inversion/patch
Better list comprehension.
2016-04-05 17:41:05 -07:00
Rowan Cockett 8d6bd65923 Better list comprehension. 2016-04-05 14:26:45 -07:00
D Fournier df620b42bd Fix plotting for Linear_IRLS example 2016-04-05 13:23:08 -07:00
Lindsey 31d418bed8 Merge pull request #253 from simpeg/bug/opt/projected-gradient
Allow moving off bounds in projected gradient
2016-04-05 12:27:48 -07:00
GudniRos 6482b94cf1 Merge branch 'master' into mt/dev 2016-04-05 10:26:03 -07:00
D Fournier 7a6f4e0780 Merge branch 'master' into feat/sparse-regularization 2016-04-03 17:26:57 -07:00
D Fournier 2ee158e5d7 Add distance weighting to example
TO DO: Create example with and without distance weights
2016-04-03 17:26:04 -07:00
D Fournier 8f73b2e7be Update directives
Add IRLS example
2016-04-03 17:18:39 -07:00
D Fournier 16d62a6d0a Merge branch 'Examples' into feat/sparse-regularization
Conflicts:
	SimPEG/Examples/__init__.py
2016-04-03 11:11:35 -07:00
Lindsey Heagy 5d9d746932 kwarg for stepping off bounds in projected gradient 2016-04-03 10:42:28 -07:00
Lindsey df3d32cb35 Merge pull request #269 from simpeg/feat/casingexample
Feat/casingexample
2016-04-02 08:47:25 -07:00
Lindsey Heagy b531c162a2 tab so we don't cut off the first characters in the docstring 2016-03-31 23:50:35 -07:00
Lindsey Heagy c7883673bf added the figshare doi link for the example 2016-03-31 09:36:55 -07:00
Lindsey Heagy 9c220ef37c default is mrefInSmooth = False 2016-03-29 23:05:04 -07:00
GudniRos 009806f2ba Merge remote-tracking branch 'origin/dev' into mt/dev 2016-03-29 16:52:01 -07:00
Lindsey Heagy b6438688d8 removed link for Schenkel paper (it seems to time-out) 2016-03-29 15:40:06 -07:00
Lindsey Heagy 824ce64c7e more descriptive titles 2016-03-29 14:56:56 -07:00
Lindsey Heagy 7aa5599211 improve the description 2016-03-29 14:41:45 -07:00
Lindsey Heagy fbec011983 typo fix 2016-03-29 14:29:39 -07:00
Lindsey Heagy 5fb8cdb88c example casing forward simulation to calculate vertical current 2016-03-29 13:00:37 -07:00
Lindsey Heagy b765699d2f seperated out smallness and smoothness contributions 2016-03-25 23:26:52 -07:00
D Fournier fdc081970e Merge branch 'feat/sparse-regularization' into dcip/dev 2016-03-21 15:03:59 -07:00
D Fournier f92ff1301d Add reference model in compact term. 2016-03-17 18:45:09 -07:00
D Fournier d302a59b2c Change the projection from 3D to 2D 2016-03-16 11:43:25 -07:00
D Fournier ef467efce0 Small change to directive 2016-03-15 20:56:38 -07:00
D Fournier d226186c8e Add auto-beta adjustment. 2016-03-11 15:09:31 -08:00
D Fournier 38b4079f0b Move cell-based weights (i.e. distance weighting) inside regularization.
Fix gamma parameter update
TO DO: Check inversion print screen -> values don't match reality.
2016-03-11 11:40:47 -08:00
D Fournier 9d4e2488f3 Merge branch 'dcip/dev' of https://github.com/simpeg/simpeg into dcip/dev
Conflicts:
	SimPEG/DCIP/DCIPUtils.py
2016-03-10 14:33:06 -08:00
Lindsey Heagy 838035adae fixed indentation level on test_regularization 2016-03-10 14:30:43 -08:00
Lindsey Heagy ef4513bcd4 some cleanup inside of sparse regularization 2016-03-10 14:25:53 -08:00
D Fournier 4fefccc97d Add readPUBC_DC2Dpre 2016-03-10 14:25:27 -08:00
GudniRos 127c51974f Fixed errors in analytic solution 2016-03-10 08:10:21 -08:00
seogi_macbook 1946e1f69e minor change for plotting 2016-03-09 15:49:08 -08:00
GudniRos e96945b991 Indexing 2016-03-09 14:30:39 -08:00
GudniRos fc444a345f Fixing dtypes in the MT1Danalytic 2016-03-09 14:24:15 -08:00
GudniRos 9a739d8380 Merge branch 'mt/dev' of https://github.com/simpeg/simpeg into mt/dev 2016-03-09 13:27:50 -08:00
GudniRos 664a7bb484 Updated plotting functions for MT 2016-03-09 13:26:50 -08:00
Lindsey Heagy 33c9059e4e SparseRegularization --> Sparse 2016-03-08 16:40:02 -08:00
Lindsey Heagy d9b3c038c4 Merge branch 'dev' into feat/sparse-regularization
# Conflicts:
#	SimPEG/Regularization.py
#	SimPEG/Survey.py
2016-03-06 23:01:59 -08:00
Lindsey Heagy 2f8b8a36bf smoothModel --> mrefInSmooth 2016-03-02 09:46:50 -08:00
Lindsey Heagy 5e5c7ba0fb docs for regmesh, cellGrad--> cellDiff, faceDiv--> faceDiff for regmesh 2016-03-01 17:31:37 -08:00
D Fournier 6c33455d15 update Directive for sparse norm 2016-02-25 08:56:18 -08:00
D Fournier 7000699e38 Merge branch 'feat/sparse-regularization' of https://github.com/simpeg/simpeg into feat/sparse-regularization 2016-02-24 21:00:02 -08:00
D Fournier 63bf8b9e4d Add linear survey 2016-02-24 20:59:51 -08:00
Lindsey Heagy e3af1fd94e convert indActive to a bool if an integer list is provided 2016-02-24 20:28:09 -08:00
Lindsey Heagy 4e871a43a9 prototype of defining regularization mesh within Regularization.py for constructing operators for regularization that are not true differential operators 2016-02-24 18:03:42 -08:00
Lindsey Heagy b5f4d8e999 typo in Regularization.py 2016-02-19 17:43:50 -08:00
Lindsey Heagy e4a3e0a16d break out the Pac, Pafx, ... and make part of base regularization 2016-02-19 16:23:26 -08:00
Rowan Cockett 1c2fecf3a2 Add the IRLS Directive. 2016-02-16 22:07:33 -08:00
Rowan Cockett c10777a245 Addition of unitCellGrad. Possibly rename to cellGradStencil? 2016-02-16 22:00:12 -08:00
Rowan Cockett 05a85018de Create a Simple and a SparseRegularization class.
The SparseRegularization class allows implementation of p-q norms.
2016-02-16 21:59:08 -08:00
Rowan Cockett 8aa23c31de Allow moving off bounds in projected gradient.
The current implementation does not allow you to move off the
bounds (lower/upper) once you have gotten on them, this allows you
to move off of the bound.

Please note that more testing should be done to ensure that this does
not introduce oscillations into the optimization routine.
2016-02-16 21:53:31 -08:00
Thibaut Astic a9c9ce6bc8 remove ipywidget 2016-02-15 19:50:04 -08:00
Thibaut Astic 6286e48830 Sphere Electrostatic example. code cleaned, commented and updated. 2016-02-15 13:13:44 -08:00
Thibaut Astic 4cf5d49524 Ignoring non functioning examples 2016-02-12 15:48:48 -08:00
Thibaut Astic 88ef74ac38 MT_1D_analytic example 2016-02-12 15:40:48 -08:00
seogi_macbook 3a506b9051 Fix DC examples ... 2016-02-11 08:54:44 -08:00
seogi_macbook fa6bcd3ffa Minor changes 2016-02-11 00:10:25 -08:00
seogi_macbook 47895ef270 consistent file name 2016-02-10 23:58:48 -08:00
seogi_macbook 429d8b1191 Add EM_FDEM_SusEffects example 2016-02-10 23:45:19 -08:00
seogi_macbook 774d612c18 Merge branch 'master' of https://github.com/simpeg/simpeg into Examples
Conflicts:
	SimPEG/Examples/__init__.py
2016-02-10 23:38:51 -08:00
Lindsey Heagy 433457f649 docs and import for DC_PseudoSection_Simulation.rst 2016-02-03 20:12:55 -08:00
D Fournier 3eeb5dbd3c Remove dependency from Utils. Replace by internal function. 2016-02-03 20:03:05 -08:00
D Fournier df78f7b33a Branch off master
Add DC_Pseudo_Section example.
2016-02-03 14:35:03 -08:00
124 changed files with 9359 additions and 3231 deletions
+1 -1
View File
@@ -35,7 +35,7 @@ before_install:
# Install packages
install:
- conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython nose vtk
- conda install --yes pip python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib cython ipython ipywidgets nose vtk
- pip install nose-cov python-coveralls
- git clone https://github.com/rowanc1/pymatsolver.git
+4
View File
@@ -25,6 +25,10 @@ SimPEG
:target: https://coveralls.io/r/simpeg/simpeg?branch=master
:alt: Coverage status
.. image:: http://img.shields.io/badge/GITTER-JOIN_CHAT-brightgreen.svg?style=flat-square
:alt: gitter chat room at https://gitter.im/simpeg/simpeg
:target: https://gitter.im/simpeg/simpeg
Simulation and Parameter Estimation in Geophysics - A python package for simulation and gradient based parameter estimation in the context of geophysical applications.
The vision is to create a package for finite volume simulation with applications to geophysical imaging and subsurface flow. To enable the understanding of the many different components, this package has the following features:
+324 -215
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,32 +169,25 @@ def readUBC_DC2DModel(fileName):
return model
def plot_pseudoSection(DCsurvey, axs, stype):
def plot_pseudoSection(DCsurvey, axs, surveyType='dipole-dipole', unitType='volt', clim=None, cblabel=True, axlabel = True, colorbar = True, contour = None):
"""
Read list of 2D tx-rx location and plot a speudo-section of apparent
resistivity.
Read list of 2D tx-rx location and plot a speudo-section of apparent
resistivity.
Assumes flat topo for now...
Assumes flat topo for now...
Input:
:param d2D, z0
:switch stype -> Either 'pdp' (pole-dipole) | 'dpdp' (dipole-dipole)
Output:
:figure scatter plot overlayed on image
Edited Feb 17th, 2016
@author: dominiquef
:param SurveyDC DCsurvey:
:param string surveyType: Either 'pole-dipole' | 'dipole-dipole'
:param string unitType: Either 'appResistivity' | 'appConductivity' | 'volt'
:rtype: matplotlib.plt
:return: figure scatter plot overlayed on image
"""
from SimPEG import np
from scipy.interpolate import griddata
import pylab as plt
# Set depth to 0 for now
z0 = 0.
# Pre-allocate
midx = []
midz = []
@@ -221,69 +214,117 @@ def plot_pseudoSection(DCsurvey, axs, stype):
Cmid = (Tx[0][0] + Tx[1][0])/2
Pmid = (Rx[0][:,0] + Rx[1][:,0])/2
# Compute pant leg of apparent rho
if stype == 'pdp':
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
# Change output for unitType
if unitType == 'volt':
leg = np.log10(abs(1/leg))
rho = np.hstack([rho,data])
elif stype == 'dpdp':
leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA )
else:
# Compute pant leg of apparent rho
if surveyType == 'pole-dipole':
leg = data * 2*np.pi * MA * ( MA + MN ) / MN
elif surveyType == 'dipole-dipole':
leg = data * 2*np.pi / ( 1/MA - 1/MB - 1/NB + 1/NA )
else:
print """unitType must be 'pole-dipole' | 'dipole-dipole' """
break
if unitType == 'appConductivity':
leg = np.log10(abs(1./leg))
rho = np.hstack([rho,leg])
elif unitType == 'appResistivity':
leg = np.log10(abs(leg))
rho = np.hstack([rho,leg])
else:
print """unitType must be 'appResistivity' | 'appConductivity' | 'volt' """
break
midx = np.hstack([midx, ( Cmid + Pmid )/2 ])
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + z0 ])
rho = np.hstack([rho,leg])
ax = axs
midz = np.hstack([midz, -np.abs(Cmid-Pmid)/2 + (Tx[0][2] + Tx[1][2])/2 ])
# Grid points
grid_x, grid_z = np.mgrid[np.min(midx):np.max(midx), np.min(midz):np.max(midz)]
grid_rho = griddata(np.c_[midx,midz], rho.T, (grid_x, grid_z), method='linear')
# Scale the color scheme
if clim == None:
vmin, vmax = rho.min(), rho.max()
else:
vmin, vmax = clim[0], clim[1]
plt.imshow(grid_rho.T, extent = (np.min(midx),np.max(midx),np.min(midz),np.max(midz)), origin='lower', alpha=0.8, vmin = np.min(rho), vmax = np.max(rho))
cbar = plt.colorbar(format = '%.2f',fraction=0.04,orientation="horizontal")
# Plot data
grid_rho = np.ma.masked_where(np.isnan(grid_rho), grid_rho)
cmin,cmax = cbar.get_clim()
ticks = np.linspace(cmin,cmax,3)
cbar.set_ticks(ticks)
# Plot apparent resistivity
plt.scatter(midx,midz,s=50,c=rho.T)
ax.set_xticklabels([])
ph = plt.pcolormesh(grid_x[:,0],grid_z[0,:],grid_rho.T, vmin = vmin, vmax = vmax)
plt.gca().tick_params(axis='both', which='major', labelsize=8)
if contour is not None:
plt.contour(grid_x,grid_z,grid_rho,levels = contour,colors = 'r', vmin = vmin, vmax = vmax)
# Add scatter points
axs.scatter(midx,midz,s=10,c=rho.T, vmin = vmin, vmax = vmax)
if colorbar:
if unitType == 'volt':
cbar = plt.colorbar(ph, ax = axs, format="%4.1f",fraction=0.04,orientation="horizontal")
else:
cbar = plt.colorbar(ph, ax = axs, format="$10^{%.1f}$",fraction=0.04,orientation="horizontal")
cmin,cmax = cbar.get_clim()
ticks = np.linspace(cmin,cmax,3)
cbar.set_ticks(ticks)
cbar.ax.tick_params(labelsize=10)
if unitType == 'appConductivity':
cbar.set_label("App.Cond",size=12)
elif unitType == 'appResistivity':
cbar.set_label("App.Res.",size=12)
elif unitType == 'volt':
cbar.set_label("Potential (V)",size=12)
if not axlabel:
axs.set_xticklabels([])
axs.set_yticklabels([])
ax.set_ylabel('Z')
ax.yaxis.tick_right()
ax.yaxis.set_label_position('right')
plt.gca().set_aspect('equal', adjustable='box')
return ax
def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
return ph
def gen_DCIPsurvey(endl, mesh, surveyType, AM_sep, MN_sep, nrx):
"""
Load in endpoints and survey specifications to generate Tx, Rx location
stations.
Load in endpoints and survey specifications to generate Tx, Rx location
stations.
Assumes flat topo for now...
Assumes flat topo for now...
Input:
:param endl -> input endpoints [x1, y1, z1, x2, y2, z2]
:object mesh -> SimPEG mesh object
:switch stype -> "dpdp" (dipole-dipole) | "pdp" (pole-dipole) | 'gradient'
: param a, n -> pole seperation, number of rx dipoles per tx
:param numpy.array endl: input endpoints [[x1, y1] , [x2, y2]]
:param Mesh mesh: SimPEG mesh object
:param string surveyType: 'dipole-dipole' | 'pole-dipole' | 'gradient'
:param float AM_sep: transmitter (A) - receiver (M) seperation
:param float b: receiver dipole seperation
:param float nrx: pole seperation, number of rx dipoles per tx
Output:
:param Tx, Rx -> List objects for each tx location
Lines: P1x, P1y, P1z, P2x, P2y, P2z
:rtype: DC.Survey, Src, Rx
:returns: DC survey, Source
Created on Wed December 9th, 2015
@author: dominiquef
!! Require clean up to deal with DCsurvey
!! Require clean up to deal with DCsurvey
"""
from SimPEG import np
@@ -299,17 +340,17 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
dl_x = ( endl[1,0] - endl[0,0] ) / dl_len
dl_y = ( endl[1,1] - endl[0,1] ) / dl_len
nstn = np.floor( dl_len / a )
nstn = np.floor( dl_len / AM_sep )
# Compute discrete pole location along line
stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*a
stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*a
stn_x = endl[0,0] + np.array(range(int(nstn)))*dl_x*AM_sep
stn_y = endl[0,1] + np.array(range(int(nstn)))*dl_y*AM_sep
# Create line of P1 locations
M = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]]
# Create line of P2 locations
N = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
N = np.c_[stn_x+AM_sep*dl_x, stn_y+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
## Build list of Tx-Rx locations depending on survey type
# Dipole-dipole: Moving tx with [a] spacing -> [AB a MN1 a MN2 ... a MNn]
@@ -319,14 +360,14 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
SrcList = []
if stype != 'gradient':
if surveyType != 'gradient':
for ii in range(0, int(nstn)-1):
if stype == 'dpdp':
if surveyType == 'dipole-dipole':
tx = np.c_[M[ii,:],N[ii,:]]
elif stype == 'pdp':
elif surveyType == 'pole-dipole':
tx = np.c_[M[ii,:],M[ii,:]]
# Rx.append(np.c_[M[ii+1:indx,:],N[ii+1:indx,:]])
@@ -335,43 +376,33 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
AB = xy_2_r(tx[0,1],endl[1,0],tx[1,1],endl[1,1])
# Number of receivers to fit
nstn = np.min([np.floor( (AB - b) / a ) , n])
nstn = np.min([np.floor( (AB - MN_sep) / AM_sep ) , nrx])
# Check if there is enough space, else break the loop
if nstn <= 0:
continue
# Compute discrete pole location along line
stn_x = N[ii,0] + dl_x*b + np.array(range(int(nstn)))*dl_x*a
stn_y = N[ii,1] + dl_y*b + np.array(range(int(nstn)))*dl_y*a
stn_x = N[ii,0] + dl_x*MN_sep + np.array(range(int(nstn)))*dl_x*AM_sep
stn_y = N[ii,1] + dl_y*MN_sep + np.array(range(int(nstn)))*dl_y*AM_sep
# Create receiver poles
# Create line of P1 locations
P1 = np.c_[stn_x, stn_y, np.ones(nstn).T*mesh.vectorNz[-1]]
# Create line of P2 locations
P2 = np.c_[stn_x+a*dl_x, stn_y+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
P2 = np.c_[stn_x+AM_sep*dl_x, stn_y+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
Rx.append(np.c_[P1,P2])
rxClass = DC.RxDipole(P1, P2)
Tx.append(tx)
if stype == 'dpdp':
if surveyType == 'dipole-dipole':
srcClass = DC.SrcDipole([rxClass], M[ii,:],N[ii,:])
elif stype == 'pdp':
elif surveyType == 'pole-dipole':
srcClass = DC.SrcDipole([rxClass], M[ii,:],M[ii,:])
SrcList.append(srcClass)
#==============================================================================
# elif re.match(stype,'dpdp'):
#
# for ii in range(0, int(nstn)-2):
#
# indx = np.min([ii+n+1,nstn])
# Tx.append(np.c_[M[ii,:],N[ii,:]])
# Rx.append(np.c_[M[ii+2:indx,:],N[ii+2:indx,:]])
#==============================================================================
elif stype == 'gradient':
elif surveyType == 'gradient':
# Gradient survey only requires Tx at end of line and creates a square
# grid of receivers at in the middle at a pre-set minimum distance
@@ -379,23 +410,23 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
Tx.append(np.c_[M[0,:],N[-1,:]])
# Get the edge limit of survey area
min_x = endl[0,0] + dl_x * b
min_y = endl[0,1] + dl_y * b
min_x = endl[0,0] + dl_x * MN_sep
min_y = endl[0,1] + dl_y * MN_sep
max_x = endl[1,0] - dl_x * b
max_y = endl[1,1] - dl_y * b
max_x = endl[1,0] - dl_x * MN_sep
max_y = endl[1,1] - dl_y * MN_sep
box_l = np.sqrt( (min_x - max_x)**2 + (min_y - max_y)**2 )
box_w = box_l/2.
nstn = np.floor( box_l / a )
nstn = np.floor( box_l / AM_sep )
# Compute discrete pole location along line
stn_x = min_x + np.array(range(int(nstn)))*dl_x*a
stn_y = min_y + np.array(range(int(nstn)))*dl_y*a
stn_x = min_x + np.array(range(int(nstn)))*dl_x*AM_sep
stn_y = min_y + np.array(range(int(nstn)))*dl_y*AM_sep
# Define number of cross lines
nlin = int(np.floor( box_w / a ))
nlin = int(np.floor( box_w / AM_sep ))
lind = range(-nlin,nlin+1)
ngrad = nstn * len(lind)
@@ -404,12 +435,12 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
for ii in range( len(lind) ):
# Move line in perpendicular direction by dipole spacing
lxx = stn_x - lind[ii]*a*dl_y
lyy = stn_y + lind[ii]*a*dl_x
lxx = stn_x - lind[ii]*AM_sep*dl_y
lyy = stn_y + lind[ii]*AM_sep*dl_x
M = np.c_[ lxx, lyy , np.ones(nstn).T*mesh.vectorNz[-1]]
N = np.c_[ lxx+a*dl_x, lyy+a*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
N = np.c_[ lxx+AM_sep*dl_x, lyy+AM_sep*dl_y, np.ones(nstn).T*mesh.vectorNz[-1]]
rx[(ii*nstn):((ii+1)*nstn),:] = np.c_[M,N]
@@ -418,37 +449,37 @@ def gen_DCIPsurvey(endl, mesh, stype, a, b, n):
srcClass = DC.SrcDipole([rxClass], M[0,:], N[-1,:])
SrcList.append(srcClass)
else:
print """stype must be either 'pdp', 'dpdp' or 'gradient'. """
print """surveyType must be either 'pole-dipole', 'dipole-dipole' or 'gradient'. """
survey = DC.SurveyDC(SrcList)
return survey, Tx, Rx
def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
def writeUBC_DCobs(fileName, DCsurvey, dim, surveyType, iptype = 0):
"""
Write UBC GIF DCIP 2D or 3D observation file
Input:
:string fileName -> including path where the file is written out
:DCsurvey -> DC survey class object
:string dtype -> either '2D' | '3D'
:string stype -> either 'SURFACE' | 'GENERAL'
Output:
:param UBC2D-Data file
:return
Last edit: February 16th, 2016
@author: dominiquef
:param string fileName: including path where the file is written out
:param Survey DCsurvey: DC survey class object
:param string dim: either '2D' | '3D'
:param string surveyType: either 'SURFACE' | 'GENERAL'
:rtype: file
:return: UBC2D-Data file
"""
from SimPEG import mkvc
assert (dtype=='2D') | (dtype=='3D'), "Data must be either '2D' | '3D'"
assert (stype=='SURFACE') | (stype=='GENERAL') | (stype=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'"
assert (dim=='2D') | (dim=='3D'), "Data must be either '2D' | '3D'"
assert (surveyType=='SURFACE') | (surveyType=='GENERAL') | (surveyType=='SIMPLE'), "Data must be either 'SURFACE' | 'GENERAL' | 'SIMPLE'"
fid = open(fileName,'w')
fid.write('! ' + stype + ' FORMAT\n')
fid.write('! ' + surveyType + ' FORMAT\n')
if iptype!=0:
fid.write('IPTYPE=%i\n'%iptype)
else:
fid.write('! ' + stype + ' FORMAT\n')
count = 0
@@ -463,10 +494,10 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
M = rx[0]
N = rx[1]
# Adapt source-receiver location for dtype and stype
if dtype=='2D':
# Adapt source-receiver location for dim and surveyType
if dim=='2D':
if stype == 'SIMPLE':
if surveyType == 'SIMPLE':
#fid.writelines("%e " % ii for ii in mkvc(tx[0,:]))
A = np.repeat(tx[0,0],M.shape[0],axis=0)
@@ -479,58 +510,60 @@ def writeUBC_DCobs(fileName, DCsurvey, dtype, stype):
else:
if stype == 'SURFACE':
if surveyType == 'SURFACE':
fid.writelines("%e " % ii for ii in mkvc(tx[0,:]))
fid.writelines("%f " % ii for ii in mkvc(tx[0,:]))
M = M[:,0]
N = N[:,0]
if stype == 'GENERAL':
if surveyType == 'GENERAL':
# Flip sign for z-elevation to depth
tx[2::2,:] = -tx[2::2,:]
fid.writelines("%e " % ii for ii in mkvc(tx[::2,:]))
M = M[:,0::2]
N = N[:,0::2]
# Flip sign for z-elevation to depth
M[:,1::2] = -M[:,1::2]
N[:,1::2] = -N[:,1::2]
fid.write('%i\n'% nD)
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n')
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%f',delimiter=' ',newline='\n')
if dtype=='3D':
if dim=='3D':
if stype == 'SURFACE':
if surveyType == 'SURFACE':
fid.writelines("%e " % ii for ii in mkvc(tx[0:2,:]))
M = M[:,0:2]
N = N[:,0:2]
if stype == 'GENERAL':
if surveyType == 'GENERAL':
fid.writelines("%e " % ii for ii in mkvc(tx))
fid.writelines("%e " % ii for ii in mkvc(tx[0:3,:]))
fid.write('%i\n'% nD)
np.savetxt(fid, np.c_[ M, N , DCsurvey.dobs[count:count+nD], DCsurvey.std[count:count+nD] ], fmt='%e',delimiter=' ',newline='\n')
fid.write('\n')
count += nD
fid.close()
def convertObs_DC3D_to_2D(DCsurvey,lineID):
def convertObs_DC3D_to_2D(DCsurvey, lineID, flag='local'):
"""
Read DC survey and data and change
coordinate system to distance along line assuming
all data is acquired along line.
First transmitter pole is assumed to be at the origin
Read DC survey and projects the coordinate system
according to the flag = 'Xloc' | 'Yloc' | 'local' (default)
In the 'local' system, station coordinates are referenced
to distance from the first srcLoc[0].loc[0]
Assumes flat topo for now...
The Z value is preserved, but Y coordinates zeroed.
Input:
:param Tx, Rx
Output:
:figure Tx2d, Rx2d
Edited Feb 17th, 2016
@author: dominiquef
:param DC.Survey survey3D: 3D simpeg DC survey
:rtype: DC.Survey
:return: survey2D
"""
from SimPEG import np
@@ -570,25 +603,39 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID):
Rx = DCsurvey.srcList[indx[ii]].rxList[0].locs
nrx = Rx[0].shape[0]
# Find A electrode along line
vec, r = r_unit(x0,Tx[ii][0,0:2])
A = stn_id(vecTx,vec,r)
if flag == 'local':
# Find A electrode along line
vec, r = r_unit(x0,Tx[ii][0,0:2])
A = stn_id(vecTx,vec,r)
# Find B electrode along line
vec, r = r_unit(x0,Tx[ii][1,0:2])
B = stn_id(vecTx,vec,r)
# Find B electrode along line
vec, r = r_unit(x0,Tx[ii][1,0:2])
B = stn_id(vecTx,vec,r)
M = np.zeros(nrx)
N = np.zeros(nrx)
for kk in range(nrx):
M = np.zeros(nrx)
N = np.zeros(nrx)
for kk in range(nrx):
# Find all M electrodes along line
vec, r = r_unit(x0,Rx[0][kk,0:2])
M[kk] = stn_id(vecTx,vec,r)
# Find all M electrodes along line
vec, r = r_unit(x0,Rx[0][kk,0:2])
M[kk] = stn_id(vecTx,vec,r)
# Find all N electrodes along line
vec, r = r_unit(x0,Rx[1][kk,0:2])
N[kk] = stn_id(vecTx,vec,r)
# Find all N electrodes along line
vec, r = r_unit(x0,Rx[1][kk,0:2])
N[kk] = stn_id(vecTx,vec,r)
elif flag == 'Yloc':
""" Flip the XY axis locs"""
A = Tx[ii][0,1]
B = Tx[ii][1,1]
M = Rx[0][:,1]
N = Rx[1][:,1]
elif flag == 'Xloc':
""" Copy the rx-tx locs"""
A = Tx[ii][0,0]
B = Tx[ii][1,0]
M = Rx[0][:,0]
N = Rx[1][:,0]
Rx = DC.RxDipole(np.c_[M,np.zeros(nrx),Rx[0][:,2]],np.c_[N,np.zeros(nrx),Rx[1][:,2]])
@@ -602,50 +649,53 @@ def convertObs_DC3D_to_2D(DCsurvey,lineID):
return DCsurvey2D
def readUBC_DC3Dobs(fileName):
def readUBC_DC3Dobs(fileName, rtype = 'DC'):
"""
Read UBC GIF DCIP 3D observation file and generate arrays for tx-rx location
Read UBC GIF IP 3D observation file and generate survey
Input:
:param fileName, path to the UBC GIF 3D obs file
Output:
:param rx, tx, d, wd
:return
Created on Mon December 7th, 2015
@author: dominiquef
:param string fileName:, path to the UBC GIF 3D obs file
:rtype: Survey
:return: DCIPsurvey
"""
zflag = True # Flag for z value provided
# Load file
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
if rtype == 'IP':
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='IPTYPE')
elif rtype == 'DC':
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
else:
print "rtype must be 'DC'(default) | 'IP'"
# Pre-allocate
srcLists = []
Rx = []
d = []
wd = []
zflag = True # Flag for z value provided
# Countdown for number of obs/tx
count = 0
for ii in range(obsfile.shape[0]):
# Skip if blank line
if not obsfile[ii]:
continue
# First line is transmitter with number of receivers
# First line or end of a transmitter block, read transmitter info
if count==0:
temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T)
# Read the line
temp = (np.fromstring(obsfile[ii], dtype=float, sep=' ').T)
count = int(temp[-1])
# Check if z value is provided, if False -> nan
if len(temp)==5:
tx = np.r_[temp[0:2],np.nan,temp[0:2],np.nan]
zflag = False
tx = np.r_[temp[0:2],np.nan,temp[2:4],np.nan]
zflag = False # Pass on the flag to the receiver loc
else:
tx = temp[:-1]
@@ -653,8 +703,16 @@ def readUBC_DC3Dobs(fileName):
rx = []
continue
temp = np.fromstring(obsfile[ii], dtype=float,sep=' ')
temp = np.fromstring(obsfile[ii], dtype=float,sep=' ') # Get the string
# Filter out negative IP
# if temp[-2] < 0:
# count = count -1
# print "Negative!"
#
# else:
# If the Z-location is provided, otherwise put nan
if zflag:
rx.append(temp[:-2])
@@ -664,7 +722,7 @@ def readUBC_DC3Dobs(fileName):
wd.append(temp[-1])
else:
rx.append(np.r_[temp[0:2],np.nan,temp[0:2],np.nan] )
rx.append(np.r_[temp[0:2],np.nan,temp[2:4],np.nan] )
# Check if there is data with the location
if len(temp)==6:
d.append(temp[-2])
@@ -672,7 +730,7 @@ def readUBC_DC3Dobs(fileName):
count = count -1
# Reach the end of transmitter block
# Reach the end of transmitter block, append the src, rx and continue
if count == 0:
rx = np.asarray(rx)
Rx = DC.RxDipole(rx[:,:3],rx[:,3:])
@@ -688,19 +746,12 @@ def readUBC_DC3Dobs(fileName):
def readUBC_DC2Dobs(fileName):
"""
------- NEEDS TO BE UPDATED ------
Read UBC GIF 2D observation file and generate arrays for tx-rx location
Input:
:param fileName, path to the UBC GIF 2D model file
Output:
:param rx, tx
:return
Created on Thu Nov 12 13:14:10 2015
@author: dominiquef
:param string fileName: path to the UBC GIF 2D model file
:rtype: (DC.Src, DC.Rx, ??, ??)
:return: source_locs, rx_locs, ??, ??
"""
from SimPEG import np
@@ -735,16 +786,78 @@ def readUBC_DC2Dobs(fileName):
return tx, rx, d, wd
def readUBC_DC2Dpre(fileName):
"""
Read UBC GIF DCIP 2D observation file and generate arrays for tx-rx location
Input:
:param string fileName: path to the UBC GIF 3D obs file
:rtype: DC.Survey
:return: DCsurvey
Created on Mon March 9th, 2016 << Doug's 70th Birthday !! >>
@author: dominiquef
"""
# Load file
obsfile = np.genfromtxt(fileName,delimiter=' \n',dtype=np.str,comments='!')
# Pre-allocate
srcLists = []
Rx = []
d = []
zflag = True # Flag for z value provided
for ii in range(obsfile.shape[0]):
if not obsfile[ii]:
continue
# First line is transmitter with number of receivers
temp = (np.fromstring(obsfile[ii], dtype=float,sep=' ').T)
# Check if z value is provided, if False -> nan
if len(temp)==5:
tx = np.r_[temp[0],np.nan,np.nan,temp[1],np.nan,np.nan]
zflag = False
else:
tx = np.r_[temp[0],np.nan,temp[1],temp[2],np.nan,temp[3]]
if zflag:
rx = np.c_[temp[4],np.nan,temp[5],temp[6],np.nan,temp[7]]
else:
rx = np.c_[temp[2],np.nan,np.nan,temp[3],np.nan,np.nan]
# Check if there is data with the location
d.append(temp[-1])
Rx = DC.RxDipole(rx[:,:3],rx[:,3:])
srcLists.append( DC.SrcDipole( [Rx], tx[:3],tx[3:]) )
# Create survey class
survey = DC.SurveyDC(srcLists)
survey.dobs = np.asarray(d)
return {'DCsurvey':survey}
def readUBC_DC2DMesh(fileName):
"""
Read UBC GIF 2DTensor mesh and generate 2D Tensor mesh in simpeg
Input:
:param fileName, path to the UBC GIF mesh file
Output:
:param SimPEG TensorMesh 2D object
:return
:param string fileName: path to the UBC GIF mesh file
:rtype: Mesh.TensorMesh
:return: SimPEG TensorMesh 2D object
Created on Thu Nov 12 13:14:10 2015
@@ -810,12 +923,9 @@ def xy_2_lineID(DCsurvey):
they were collected. May need to generalize for random
point locations, but will be more expensive
Input:
:param DCdict Vectors of station location
Output:
:param LineID Vector of integers
:return
:param numpy.array DCdict: Vectors of station location
:rtype: numpy.array
:return: LineID Vector of integers
Created on Thu Feb 11, 2015
@@ -928,7 +1038,6 @@ def getSrc_locs(DCsurvey):
srcMat = np.zeros((DCsurvey.nSrc,2,3))
for ii in range(DCsurvey.nSrc):
print np.asarray(DCsurvey.srcList[ii].loc).shape
srcMat[ii,:,:] = np.asarray(DCsurvey.srcList[ii].loc)
return srcMat
+202 -57
View File
@@ -144,12 +144,18 @@ class BetaSchedule(InversionDirective):
if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter
self.invProb.beta /= self.coolingFactor
class TargetMisfit(InversionDirective):
chifact = 1.
phi_d_star = None
@property
def target(self):
if getattr(self, '_target', None) is None:
self._target = self.survey.nD*0.5
if self.phi_d_star is None:
self.phi_d_star = 0.5 * self.survey.nD
self._target = self.chifact * self.phi_d_star # the factor of 0.5 is because we do phid = 0.5*|| dpred - dobs||^2
return self._target
@target.setter
def target(self, val):
@@ -207,79 +213,218 @@ class SaveOutputEveryIteration(_SaveEveryIteration):
f.close()
class SaveOutputDictEveryIteration(_SaveEveryIteration):
"""SaveOutputDictEveryIteration"""
"""
Saves inversion parameters at every iteraion.
"""
def initialize(self):
print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '###-%s.npz'"%self.fileName
def endIter(self):
# Save the data.
ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) )
phi_ms = 0.5*ms.dot(ms)
if self.reg.smoothModel == True:
mref = self.reg.mref
else:
mref = 0
mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) )
phi_mx = 0.5 * mx.dot(mx)
if self.prob.mesh.dim==2:
my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) )
phi_my = 0.5 * my.dot(my)
else:
phi_my = 'NaN'
if self.prob.mesh.dim==3:
mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) )
phi_mz = 0.5 * mz.dot(mz)
else:
phi_mz = 'NaN'
# Initialize the output dict
outDict = {}
# Save the data.
outDict['iter'] = self.opt.iter
outDict['beta'] = self.invProb.beta
outDict['phi_d'] = self.invProb.phi_d
outDict['phi_ms'] = self.reg._evalSmall(self.invProb.curModel)
outDict['phi_mx'] = self.reg._evalSmoothx(self.invProb.curModel)
outDict['phi_my'] = self.reg._evalSmoothy(self.invProb.curModel) if self.prob.mesh.dim >= 2 else 'NaN'
outDict['phi_mz'] = self.reg._evalSmoothz(self.invProb.curModel) if self.prob.mesh.dim==3 else 'NaN'
outDict['f'] = self.opt.f
outDict['m'] = self.invProb.curModel
outDict['dpred'] = self.invProb.dpred
# Save the file as a npz
np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred)
np.savez('{:03d}-{:s}'.format(self.opt.iter,self.fileName), outDict)
class SaveOutputDictEveryIteration(_SaveEveryIteration):
"""SaveOutputDictEveryIteration
A directive that saves some relevant information from the inversion run to a numpy .npz dictionary file (see numpy.savez function for further info).
"""
class Update_IRLS(InversionDirective):
eps_min = None
eps_p = None
eps_q = None
norms = [2.,2.,2.,2.]
factor = None
gamma = None
phi_m_last = None
phi_d_last = None
f_old = None
f_min_change = 1e-2
beta_tol = 5e-2
# Solving parameter for IRLS (mode:2)
IRLSiter = 0
minGNiter = 5
maxIRLSiter = 10
iterStart = 0
# Beta schedule
coolingFactor = 2.
coolingRate = 1
mode = 1
@property
def target(self):
if getattr(self, '_target', None) is None:
self._target = self.survey.nD*0.5
return self._target
@target.setter
def target(self, val):
self._target = val
def initialize(self):
print "SimPEG.SaveOutputDictEveryIteration will save your inversion progress as dictionary: '%s-###.npz'"%self.fileName
if self.mode == 1:
self.reg.norms = [2., 2., 2., 2.]
def endIter(self):
# Save the data.
ms = self.reg.Ws * ( self.reg.mapping * (self.invProb.curModel - self.reg.mref) )
phi_ms = 0.5*ms.dot(ms)
if self.reg.smoothModel == True:
mref = self.reg.mref
else:
mref = 0
mx = self.reg.Wx * ( self.reg.mapping * (self.invProb.curModel - mref) )
phi_mx = 0.5 * mx.dot(mx)
if self.prob.mesh.dim==2:
my = self.reg.Wy * ( self.reg.mapping * (self.invProb.curModel - mref) )
phi_my = 0.5 * my.dot(my)
else:
phi_my = 'NaN'
if self.prob.mesh.dim==3 and 'CYL' not in self.prob.mesh._meshType:
mz = self.reg.Wz * ( self.reg.mapping * (self.invProb.curModel - mref) )
phi_mz = 0.5 * mz.dot(mz)
else:
phi_mz = 'NaN'
# After reaching target misfit with l2-norm, switch to IRLS (mode:2)
if self.invProb.phi_d < self.target and self.mode == 1:
print "Convergence with smooth l2-norm regularization: Start IRLS steps..."
self.mode = 2
print self.eps_p, self.eps_q, self.norms
self.reg.eps_p = self.eps_p
self.reg.eps_q = self.eps_q
self.reg.norms = self.norms
self.coolingFactor = 1.
self.coolingRate = 1
self.iterStart = self.opt.iter
self.phi_d_last = self.invProb.phi_d
self.phi_m_last = self.invProb.phi_m_last
self.reg.l2model = self.invProb.curModel
self.reg.curModel = self.invProb.curModel
if getattr(self, 'f_old', None) is None:
self.f_old = self.reg.eval(self.invProb.curModel)#self.invProb.evalFunction(self.invProb.curModel, return_g=False, return_H=False)
# Beta Schedule
if self.opt.iter > 0 and self.opt.iter % self.coolingRate == 0:
if self.debug: print 'BetaSchedule is cooling Beta. Iteration: %d' % self.opt.iter
self.invProb.beta /= self.coolingFactor
# Save the file as a npz
np.savez('{:s}-{:03d}'.format(self.fileName,self.opt.iter), iter=self.opt.iter, beta=self.invProb.beta, phi_d=self.invProb.phi_d, phi_m=self.invProb.phi_m, phi_ms=phi_ms, phi_mx=phi_mx, phi_my=phi_my, phi_mz=phi_mz,f=self.opt.f, m=self.invProb.curModel,dpred=self.invProb.dpred)
# Only update after GN iterations
if (self.opt.iter-self.iterStart) % self.minGNiter == 0 and self.mode==2:
self.IRLSiter += 1
phim_new = self.reg.eval(self.invProb.curModel)
self.f_change = np.abs(self.f_old - phim_new) / self.f_old
print "Regularization decrease: %6.3e" % (self.f_change)
# Check for maximum number of IRLS cycles
if self.IRLSiter == self.maxIRLSiter:
print "Reach maximum number of IRLS cycles: %i" % self.maxIRLSiter
self.opt.stopNextIteration = True
return
# Check if the function has changed enough
if self.f_change < self.f_min_change and self.IRLSiter > 1:
print "Minimum decrease in regularization. End of IRLS"
self.opt.stopNextIteration = True
return
else:
self.f_old = phim_new
# Cool the threshold parameter if required
if getattr(self, 'factor', None) is not None:
eps = self.reg.eps / self.factor
if getattr(self, 'eps_min', None) is not None:
self.reg.eps = np.max([self.eps_min,eps])
else:
self.reg.eps = eps
# Get phi_m at the end of current iteration
self.phi_m_last = self.invProb.phi_m_last
# Reset the regularization matrices so that it is
# recalculated for current model
self.reg._Wsmall = None
self.reg._Wx = None
self.reg._Wy = None
self.reg._Wz = None
# Update the model used for the IRLS weights
self.reg.curModel = self.invProb.curModel
# Temporarely set gamma to 1. to get raw phi_m
self.reg.gamma = 1.
# Compute new model objective function value
phim_new = self.reg.eval(self.invProb.curModel)
# Update gamma to scale the regularization between IRLS iterations
self.reg.gamma = self.phi_m_last / phim_new
# Reset the regularization matrices again for new gamma
self.reg._Wsmall = None
self.reg._Wx = None
self.reg._Wy = None
self.reg._Wz = None
# Check if misfit is within the tolerance, otherwise scale beta
val = self.invProb.phi_d / (self.survey.nD*0.5)
if np.abs(1.-val) > self.beta_tol:
self.invProb.beta = self.invProb.beta * self.survey.nD*0.5 / self.invProb.phi_d
class Update_lin_PreCond(InversionDirective):
"""
Create a Jacobi preconditioner for the linear problem
"""
onlyOnStart=False
def initialize(self):
if getattr(self.opt, 'approxHinv', None) is None:
# Update the pre-conditioner
diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2.
PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.)
self.opt.approxHinv = PC
def endIter(self):
# Cool the threshold parameter
if self.onlyOnStart==True:
return
if getattr(self.opt, 'approxHinv', None) is not None:
# Update the pre-conditioner
diagA = np.sum(self.prob.G**2.,axis=0) + self.invProb.beta*(self.reg.W.T*self.reg.W).diagonal() #* (self.reg.mapping * np.ones(self.reg.curModel.size))**2.
PC = Utils.sdiag((self.prob.mapping.deriv(None).T *diagA)**-1.)
self.opt.approxHinv = PC
class Update_Wj(InversionDirective):
"""
Create approx-sensitivity base weighting using the probing method
"""
k = None # Number of probing cycles
itr = None # Iteration number to update Wj, or always update if None
# class UpdateReferenceModel(Parameter):
def endIter(self):
# mref0 = None
if self.itr is None or self.itr == self.opt.iter:
# def nextIter(self):
# mref = getattr(self, 'm_prev', None)
# if mref is None:
# if self.debug: print 'UpdateReferenceModel is using mref0'
# mref = self.mref0
# self.m_prev = self.invProb.m_current
# return mref
m = self.invProb.curModel
if self.k is None:
self.k = int(self.survey.nD/10)
def JtJv(v):
Jv = self.prob.Jvec(m, v)
return self.prob.Jtvec(m,Jv)
JtJdiag = Utils.diagEst(JtJv,len(m),k=self.k)
JtJdiag = JtJdiag / max(JtJdiag)
self.reg.wght = JtJdiag
+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
+1
View File
@@ -1,3 +1,4 @@
from TDEM import hzAnalyticDipoleT
from FDEM import hzAnalyticDipoleF
from FDEMcasing import *
from DC import DCAnalyticHalf, DCAnalyticSphere
+34 -12
View File
@@ -1,13 +1,14 @@
from SimPEG import Survey, Problem, Utils, Models, Maps, PropMaps, np, sp, Solver as SimpegSolver
from scipy.constants import mu_0
class EMPropMap(Maps.PropMap):
"""
Property Map for EM Problems. The electrical conductivity (\\(\\sigma\\)) is the default inversion property, and the default value of the magnetic permeability is that of free space (\\(\\mu = 4\\pi\\times 10^{-7} \\) H/m)
"""
sigma = Maps.Property("Electrical Conductivity", defaultInvProp = True, propertyLink=('rho',Maps.ReciprocalMap))
mu = Maps.Property("Magnetic Permeability", defaultVal = mu_0, propertyLink=('mui',Maps.ReciprocalMap))
mu = Maps.Property("Inverse Magnetic Permeability", defaultVal = mu_0, propertyLink=('mui',Maps.ReciprocalMap))
rho = Maps.Property("Electrical Resistivity", propertyLink=('sigma', Maps.ReciprocalMap))
mui = Maps.Property("Inverse Magnetic Permeability", defaultVal = 1./mu_0, propertyLink=('mu', Maps.ReciprocalMap))
@@ -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,7 +214,7 @@ 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
@@ -202,8 +224,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.')
+50 -9
View File
@@ -160,9 +160,9 @@ class Fields(SimPEG.Problem.Fields):
return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint)
return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = complex)
class Fields_e(Fields):
class Fields3D_e(Fields):
"""
Fields object for Problem_e.
Fields object for Problem3D_e.
:param Mesh mesh: mesh
:param Survey survey: survey
@@ -181,7 +181,7 @@ class Fields_e(Fields):
}
def __init__(self, mesh, survey, **kwargs):
Fields.__init__(self,mesh,survey,**kwargs)
Fields.__init__(self, mesh, survey, **kwargs)
def startup(self):
self.prob = self.survey.prob
@@ -193,6 +193,16 @@ class Fields_e(Fields):
self._MeSigmaDeriv = self.survey.prob.MeSigmaDeriv
self._MfMui = self.survey.prob.MfMui
def _GLoc(self, fieldType):
if fieldType == 'e':
return 'E'
elif fieldType == 'b':
return 'F'
elif (fieldType == 'h') or (fieldType == 'j'):
return 'CCV'
else:
raise Exception('Field type must be e, b, h, j')
def _ePrimary(self, eSolution, srcList):
"""
@@ -416,9 +426,9 @@ class Fields_e(Fields):
class Fields_b(Fields):
class Fields3D_b(Fields):
"""
Fields object for Problem_b.
Fields object for Problem3D_b.
:param Mesh mesh: mesh
:param Survey survey: survey
@@ -455,6 +465,17 @@ class Fields_b(Fields):
self._nC = self.survey.prob.mesh.nC
def _GLoc(self,fieldType):
if fieldType == 'e':
return 'E'
elif fieldType == 'b':
return 'F'
elif (fieldType == 'h') or (fieldType == 'j'):
return'CCV'
else:
raise Exception('Field type must be e, b, h, j')
def _bPrimary(self, bSolution, srcList):
"""
Primary magnetic flux density from source
@@ -672,9 +693,9 @@ class Fields_b(Fields):
return Zero()
class Fields_j(Fields):
class Fields3D_j(Fields):
"""
Fields object for Problem_j.
Fields object for Problem3D_j.
:param Mesh mesh: mesh
:param Survey survey: survey
@@ -708,6 +729,16 @@ class Fields_j(Fields):
self._aveE2CCV = self.survey.prob.mesh.aveE2CCV
self._nC = self.survey.prob.mesh.nC
def _GLoc(self,fieldType):
if fieldType == 'h':
return 'E'
elif fieldType == 'j':
return 'F'
elif (fieldType == 'e') or (fieldType == 'b'):
return 'CCV'
else:
raise Exception('Field type must be e, b, h, j')
def _jPrimary(self, jSolution, srcList):
"""
Primary current density from source
@@ -957,9 +988,9 @@ 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(Fields):
"""
Fields object for Problem_h.
Fields object for Problem3D_h.
:param Mesh mesh: mesh
:param Survey survey: survey
@@ -993,6 +1024,16 @@ class Fields_h(Fields):
self._aveE2CCV = self.survey.prob.mesh.aveE2CCV
self._nC = self.survey.prob.mesh.nC
def _GLoc(self,fieldType):
if fieldType == 'h':
return 'E'
elif fieldType == 'j':
return 'F'
elif (fieldType == 'e') or (fieldType == 'b'):
return 'CCV'
else:
raise Exception('Field type must be e, b, h, j')
def _hPrimary(self, hSolution, srcList):
"""
Primary magnetic field from source
@@ -1,36 +1,36 @@
from SimPEG import Problem, Utils, np, sp, Solver as SimpegSolver
from scipy.constants import mu_0
from SurveyFDEM import Survey as SurveyFDEM
from FieldsFDEM import Fields, Fields_e, Fields_b, Fields_h, Fields_j
from FieldsFDEM import Fields, Fields3D_e, Fields3D_b, Fields3D_h, Fields3D_j
from SimPEG.EM.Base import BaseEMProblem
from SimPEG.EM.Utils import omega
class BaseFDEMProblem(BaseEMProblem):
"""
We start by looking at Maxwell's equations in the electric
field \\\(\\\mathbf{e}\\\) and the magnetic flux
density \\\(\\\mathbf{b}\\\)
We start by looking at Maxwell's equations in the electric
field \\\(\\\mathbf{e}\\\) and the magnetic flux
density \\\(\\\mathbf{b}\\\)
.. math ::
.. math ::
\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}}
\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}\\\)
If we write Maxwell's equations in terms of
\\\(\\\mathbf{h}\\\) and current density \\\(\\\mathbf{j}\\\)
.. math ::
.. math ::
\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}
\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}\\\)
The problem performs the elimination so that we are solving the system for \\\(\\\mathbf{e},\\\mathbf{b},\\\mathbf{j} \\\) or \\\(\\\mathbf{h}\\\)
"""
surveyPair = SurveyFDEM
@@ -87,7 +87,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()
@@ -125,7 +125,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 +137,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')
@@ -167,6 +166,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 +177,7 @@ class BaseFDEMProblem(BaseEMProblem):
################################ E-B Formulation #########################################
##########################################################################################
class Problem_e(BaseFDEMProblem):
class Problem3D_e(BaseFDEMProblem):
"""
By eliminating the magnetic flux density using
@@ -199,22 +199,11 @@ class Problem_e(BaseFDEMProblem):
_solutionType = 'eSolution'
_formulation = 'EB'
fieldsPair = Fields_e
fieldsPair = Fields3D_e
def __init__(self, mesh, **kwargs):
BaseFDEMProblem.__init__(self, mesh, **kwargs)
def _GLoc(self, fieldType):
if fieldType == 'e':
return 'E'
elif fieldType == 'b':
return 'F'
elif (fieldType == 'h') or (fieldType == 'j'):
return 'CCV'
else:
raise Exception('Field type must be e, b, h, j')
def getA(self, freq):
"""
System matrix
@@ -294,11 +283,12 @@ class Problem_e(BaseFDEMProblem):
if adjoint:
dRHS = MfMui * (C * v)
return s_mDeriv(dRHS) - 1j * omega(freq) * s_eDeriv(v)
else:
return C.T * (MfMui * s_mDeriv(v)) -1j * omega(freq) * s_eDeriv(v)
class Problem_b(BaseFDEMProblem):
class Problem3D_b(BaseFDEMProblem):
"""
We eliminate :math:`\mathbf{e}` using
@@ -320,21 +310,11 @@ class Problem_b(BaseFDEMProblem):
_solutionType = 'bSolution'
_formulation = 'EB'
fieldsPair = Fields_b
fieldsPair = Fields3D_b
def __init__(self, mesh, **kwargs):
BaseFDEMProblem.__init__(self, mesh, **kwargs)
def _GLoc(self, fieldType):
if fieldType == 'e':
return 'E'
elif fieldType == 'b':
return 'F'
elif (fieldType == 'h') or (fieldType == 'j'):
return'CCV'
else:
raise Exception('Field type must be e, b, h, j')
def getA(self, freq):
"""
System matrix
@@ -456,7 +436,7 @@ class Problem_b(BaseFDEMProblem):
##########################################################################################
class Problem_j(BaseFDEMProblem):
class Problem3D_j(BaseFDEMProblem):
"""
We eliminate \\\(\\\mathbf{h}\\\) using
@@ -478,21 +458,11 @@ class Problem_j(BaseFDEMProblem):
_solutionType = 'jSolution'
_formulation = 'HJ'
fieldsPair = Fields_j
fieldsPair = Fields3D_j
def __init__(self, mesh, **kwargs):
BaseFDEMProblem.__init__(self, mesh, **kwargs)
def _GLoc(self, fieldType):
if fieldType == 'h':
return 'E'
elif fieldType == 'j':
return 'F'
elif (fieldType == 'e') or (fieldType == 'b'):
return 'CCV'
else:
raise Exception('Field type must be e, b, h, j')
def getA(self, freq):
"""
System matrix
@@ -607,7 +577,7 @@ class Problem_j(BaseFDEMProblem):
class Problem_h(BaseFDEMProblem):
class Problem3D_h(BaseFDEMProblem):
"""
We eliminate \\\(\\\mathbf{j}\\\) using
@@ -626,22 +596,11 @@ class Problem_h(BaseFDEMProblem):
_solutionType = 'hSolution'
_formulation = 'HJ'
fieldsPair = Fields_h
fieldsPair = Fields3D_h
def __init__(self, mesh, **kwargs):
BaseFDEMProblem.__init__(self, mesh, **kwargs)
def _GLoc(self, fieldType):
if fieldType == 'h':
return 'E'
elif fieldType == 'j':
return 'F'
elif (fieldType == 'e') or (fieldType == 'b'):
return 'CCV'
else:
raise Exception('Field type must be e, b, h, j')
def getA(self, freq):
"""
System matrix
+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 %s not known. Orientation must be in 'x', 'y', 'z'. Arbitrary orientations have not yet been implemented."%orientation
assert(component in ['real', 'imag']), "'component' must be 'real' or 'imag', not %s"%component
self.projComp = orientation
self.component = component
SimPEG.Survey.BaseRx.__init__(self, locs, rxType=None) #TODO: remove rxType from baseRx
def projGLoc(self, u):
"""Grid Location projection (e.g. Ex Fy ...)"""
return u._GLoc(self.projField) + self.projComp
def eval(self, src, mesh, f):
"""
Project fields to recievers to get data.
:param Source src: FDEM source
:param Mesh mesh: mesh used
:param Fields f: fields object
:rtype: numpy.ndarray
:return: fields projected to recievers
"""
P = self.getP(mesh, self.projGLoc(f))
f_part_complex = f[src, self.projField]
f_part = getattr(f_part_complex, self.component) # get the real or imag component
return P*f_part
def evalDeriv(self, src, mesh, f, v, adjoint=False):
"""
Derivative of projected fields with respect to the inversion model times a vector.
:param Source src: FDEM source
:param Mesh mesh: mesh used
:param Fields f: fields object
:param numpy.ndarray v: vector to multiply
:rtype: numpy.ndarray
:return: fields projected to recievers
"""
P = self.getP(mesh, self.projGLoc(f))
if not adjoint:
Pv_complex = P * v
Pv = getattr(Pv_complex, self.component)
elif adjoint:
Pv_real = P.T * v
if self.component == 'imag':
Pv = 1j*Pv_real
elif self.component == 'real':
Pv = Pv_real.astype(complex)
else:
raise NotImplementedError('must be real or imag')
return Pv
class Point_e(BaseRx):
"""
Electric field FDEM receiver
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
:param string orientation: receiver orientation 'x', 'y' or 'z'
:param string component: real or imaginary component 'real' or 'imag'
"""
def __init__(self, locs, orientation=None, component=None):
self.projField = 'e'
super(Point_e, self).__init__(locs, orientation, component)
class Point_b(BaseRx):
"""
Magnetic flux FDEM receiver
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
:param string orientation: receiver orientation 'x', 'y' or 'z'
:param string component: real or imaginary component 'real' or 'imag'
"""
def __init__(self, locs, orientation=None, component=None):
self.projField = 'b'
super(Point_b, self).__init__(locs, orientation, component)
class Point_h(BaseRx):
"""
Magnetic field FDEM receiver
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
:param string orientation: receiver orientation 'x', 'y' or 'z'
:param string component: real or imaginary component 'real' or 'imag'
"""
def __init__(self, locs, orientation=None, component=None):
self.projField = 'h'
super(Point_h, self).__init__(locs, orientation, component)
class Point_j(BaseRx):
"""
Current density FDEM receiver
:param numpy.ndarray locs: receiver locations (ie. :code:`np.r_[x,y,z]`)
:param string orientation: receiver orientation 'x', 'y' or 'z'
:param string component: real or imaginary component 'real' or 'imag'
"""
def __init__(self, locs, orientation=None, component=None):
self.projField = 'j'
super(Point_j, self).__init__(locs, orientation, component)
+23 -238
View File
@@ -10,13 +10,16 @@ class BaseSrc(Survey.BaseSrc):
freq = None
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
@@ -53,7 +56,9 @@ class BaseSrc(Survey.BaseSrc):
:rtype: numpy.ndarray
:return: primary magnetic flux density
"""
return Zero()
if self._bPrimary is None:
return Zero()
return self._bPrimary
def hPrimary(self, prob):
"""
@@ -63,7 +68,9 @@ class BaseSrc(Survey.BaseSrc):
:rtype: numpy.ndarray
:return: primary magnetic field
"""
return Zero()
if self._hPrimary is None:
return Zero()
return self._hPrimary
def ePrimary(self, prob):
"""
@@ -73,7 +80,9 @@ class BaseSrc(Survey.BaseSrc):
:rtype: numpy.ndarray
:return: primary electric field
"""
return Zero()
if self._ePrimary is None:
return Zero()
return self._ePrimary
def jPrimary(self, prob):
"""
@@ -83,7 +92,9 @@ class BaseSrc(Survey.BaseSrc):
:rtype: numpy.ndarray
:return: primary current density
"""
return Zero()
if self._jPrimary is None:
return Zero()
return self._jPrimary
def s_m(self, prob):
"""
@@ -105,7 +116,7 @@ class BaseSrc(Survey.BaseSrc):
"""
return Zero()
def s_mDeriv(self, prob, v, adjoint=False):
def s_mDeriv(self, prob, v, adjoint = False):
"""
Derivative of magnetic source term with respect to the inversion model
@@ -118,7 +129,7 @@ class BaseSrc(Survey.BaseSrc):
return Zero()
def s_eDeriv(self, prob, v, adjoint=False):
def s_eDeriv(self, prob, v, adjoint = False):
"""
Derivative of electric source term with respect to the inversion model
@@ -141,11 +152,11 @@ class RawVec_e(BaseSrc):
:param bool integrate: Integrate the source term (multiply by Me) [False]
"""
def __init__(self, rxList, freq, s_e):
def __init__(self, rxList, freq, s_e, **kwargs):
self._s_e = np.array(s_e, dtype=complex)
self.freq = float(freq)
BaseSrc.__init__(self, rxList)
BaseSrc.__init__(self, rxList, **kwargs)
def s_e(self, prob):
"""
@@ -170,11 +181,11 @@ class RawVec_m(BaseSrc):
: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)
BaseSrc.__init__(self, rxList)
BaseSrc.__init__(self, rxList, **kwargs)
def s_m(self, prob):
"""
@@ -544,7 +555,7 @@ class CircularLoop(BaseSrc):
a = MagneticLoopVectorPotential(self.loc, gridY, 'y', moment=self.radius, mu=self.mu)
else:
srcfct = MagneticLoopVectorPotential
srcfct = MagneticDipoleVectorPotential
ax = srcfct(self.loc, gridX, 'x', self.radius, mu=self.mu)
ay = srcfct(self.loc, gridY, 'y', self.radius, mu=self.mu)
az = srcfct(self.loc, gridZ, 'z', self.radius, mu=self.mu)
@@ -603,231 +614,5 @@ class CircularLoop(BaseSrc):
return -C.T * (MMui_s * self.bPrimary(prob))
class PrimSec(BaseSrc):
"""
Primary-Secondary source in the physical properties. A primary problem is
first solved, and the fields from this problem are used to construct a
source term for the secondary problem. Either a mesh and
fields need to be provided or a prob and a survey.
For the EB formulation, we start the derivation from Maxwell's equations:
.. math::
\\nabla \\times \\vec{E} + i \omega \\vec{B} = \\vec{s_m} \\\\
\\nabla \\times \\mu^{-1} \\vec{B} - \sigma \\vec{E} = \\vec{s_e}
we consider the physical properties, fields, and fluxes to be composed of
two parts, a primary and a secondary:
- :math:`\sigma = \sigma_p + \sigma_s`
- :math:`\mu^{-1} = \mu^{-1}_p + \mu^{-1}_s`
- :math:`\\vec{E} = \\vec{E_p} + \\vec{E_s}`
- :math:`\\vec{B} = \\vec{B_p} + \\vec{B_s}`
and choose our primary such that
.. math::
\\nabla \\times \\vec{E}_p + i \omega \\vec{B}_p = \\vec{s_m} \\\\
\\nabla \\times \\mu^{-1}_p \\vec{B}_p - \sigma_p \\vec{E}_p = \\vec{s_e}_p
so the secondary problem is then
.. math::
\\nabla \\times \\vec{E}_s + i \omega \\vec{B}_s = 0 \\\\
\\nabla \\times \\mu^{-1} \\vec{B}_s - \sigma \\vec{E}_s = - \\nabla \\times \\mu^{-1}_s \\vec{B}_p + \sigma_s \\vec{E}_p
If instead, HJ formulation is considered, then we start off with
.. math::
\\nabla \\times \\rho \\vec{J} + i \omega \\mu \\vec{H} = \\vec{s_m} \\\\
\\nabla \\times \\vec{H} - \\vec{J} = \\vec{s_e}
and we define the primary secondary problem in terms of
- :math:`\\rho = \\rho_p + \\rho_s`
- :math:`\mu = \mu_p + \mu_s`
- :math:`\\vec{J} = \\vec{J_p} + \\vec{J_s}`
- :math:`\\vec{H} = \\vec{H_p} + \\vec{H_s}`
with the primary being defined by
.. math::
\\nabla \\times \\rho_p \\vec{J}_p + i \omega \\mu_p \\vec{H}_p = \\vec{s_m} \\\\
\\nabla \\times \\vec{H}_p - \\vec{J}_p = \\vec{s_e}
so the secondary problem is given by
.. math::
\\nabla \\times \\rho \\vec{J}_s + i \omega \\mu \\vec{H} = - \\nabla \\times \\rho_s \\vec{J}_p - i \omega \\mu_s \\vec{H}_p \\
\\nabla \\times \\vec{H}_p - \\vec{J}_p = 0
Note: if different meshes are employed for the primary and secondary
problems, then we need to interpolate the fields from the primary mesh to
the secondary mesh. We do this by always interpolating the field and
computing a flux if need be in order to ensure that fluxes remain
numerically divergence free.
:param list rxList: Receiver list
:param float freq: frequency
:param numpy.array m: primary model
:param Problem prob: primary problem
:param Survey survey: primary survey
"""
def __init__(self, rxList, freq, m, prob, survey):
self.freq = float(freq)
self.m = m
self.prob = prob
self.survey = survey
self.fields = None
if self.survey.ispaired:
if self.survey.prob is not self.prob:
raise Exception('The survey object is already paired to a problem. Use survey.unpair()')
else:
self.prob.pair(self.survey)
self.mesh = self.prob.mesh
self.prob.curModel = self.m
BaseSrc.__init__(self, rxList)
def MeSigma(self, prob):
if getattr(self, '_MeSigma', None) is None:
sigmaprimary = self.prob.curModel.sigma
if self.mesh != prob.mesh:
P = self.mesh.getInterpolationMatMesh2Mesh(prob.mesh, locType='CC')
sigmaprimary = P * sigmaprimary
self._MeSigma = prob.mesh.getEdgeInnerProduct(sigmaprimary)
return self._MeSigma
def MfMui(self, prob):
if getattr(self, '_MfMui', None) is None:
muiprimary = self.prob.curModel.mui
if self.mesh != prob.mesh and not isinstance(muiprimary,float): # if different meshes and mu is a vector --> need to interpolate
P = self.mesh.getInterpolationMatMesh2Mesh(prob.mesh, locType='CC')
muiprimary = P * muiprimary
self._MfMui = prob.mesh.getFaceInnerProduct(muiprimary)
return self._MfMui
def MfRho(self, prob):
if getattr(self, '_MfRho', None) is None:
rhoprimary = self.prob.curModel.rho
if self.mesh != prob.mesh:
P = self.mesh.getInterpolationMatMesh2Mesh(prob.mesh, locType='CC')
rhoprimary = P * rhoprimary
self._MfRho = prob.mesh.getFaceInnerProduct(rhoprimary)
return self._MfRho
def MeMu(self, prob):
if getattr(self, '_MeMu', None) is None:
muprimary = self.prob.curModel.mu
if self.mesh != prob.mesh and not isinstance(muiprimary,float): # if different meshes and mu is a vector --> need to interpolate
P = self.mesh.getInterpolationMatMesh2Mesh(prob.mesh, locType='CC')
muprimary = P * muprimary
self._MeMu = prob.mesh.getEdgeInnerProduct(muprimary)
return self._MeMu
# note if you switch from one formulation to another, but are using the same mesh, this will break
def ePrimary(self,prob):
if getattr(self, '_ePrimary', None) is None:
if self.fields is None:
self.fields = self.prob.fields(self.m)
ePrimary = self.fields[:,'e']
if self.mesh != prob.mesh:
if self.prob._formulation == 'HJ':
P = self.mesh.getInterpolationMatMesh2Mesh(prob.mesh, locType=prob._GLoc('e'), locTypeFrom='CCV')
else:
P = self.mesh.getInterpolationMatMesh2Mesh(prob.mesh, locType=prob._GLoc('e'))
ePrimary = Utils.mkvc(P * ePrimary)
self._ePrimary = Utils.mkvc(ePrimary)
return self._ePrimary
# note if you switch from one formulation to another, but are using the same mesh, this will break
def bPrimary(self, prob):
if getattr(self, '_bPrimary', None) is None:
if self.fields is None:
self.fields = self.prob.fields(self.m)
if self.mesh == prob.mesh:
bPrimary = self.fields[:,'b']
else:
bPrimary = prob.mesh.edgeCurl * self.ePrimary(prob)
self._bPrimary = Utils.mkvc(bPrimary)
return self._bPrimary
# note if you switch from one formulation to another, but are using the same mesh, this will break
def hPrimary(self, prob):
if getattr(self, '_hPrimary', None) is None:
if self.fields is None:
self.fields = self.prob.fields(self.m)
hPrimary = self.fields[:,'h']
if self.mesh != prob.mesh:
if self.prob._formulation == 'EB':
P = self.mesh.getInterpolationMatMesh2Mesh(prob.mesh, locType=prob._GLoc('h'), locTypeFrom='CCV')
else:
P = self.mesh.getInterpolationMatMesh2Mesh(prob.mesh, locType=prob._GLoc('h'))
print P.shape, hPrimary.shape, prob._GLoc('h')
hPrimary = Utils.mkvc(P * hPrimary)
self._hPrimary = Utils.mkvc(hPrimary)
return self._hPrimary
# note if you switch from one formulation to another, but are using the same mesh, this will break
def jPrimary(self, prob):
if getattr(self, '_jPrimary', None) is None:
if self.fields is None:
self.fields = self.prob.fields(self.m)
if self.mesh == prob.mesh:
jPrimary = self.fields[:,'j']
else:
jPrimary = prob.mesh.edgeCurl * self.hPrimary(prob)
self._jPrimary = Utils.mkvc(jPrimary)
return self._jPrimary
def s_e(self,prob):
if prob._formulation == 'EB':
# - \\nabla \\times \\mu^{-1}_s \\vec{B}_p + \sigma_s \\vec{E}_p
s_e = -prob.mesh.edgeCurl.T * ((prob.MfMui - self.MfMui(prob)) * self.bPrimary(prob)) + (prob.MeSigma - self.MeSigma(prob)) * self.ePrimary(prob)
return Utils.mkvc(s_e)
else:
return Zero()
def s_eDeriv(self, prob, v, adjoint=False):
if prob._formulation == 'EB':
if adjoint is True:
return prob.MeSigmaDeriv(self.ePrimary(prob)).T * v
return prob.MeSigmaDeriv(self.ePrimary(prob)) * v
else:
return Zero()
def s_m(self,prob):
if prob._formulation == 'HJ':
# - \\nabla \\times \\rho_s \\vec{J}_p - i \omega \\mu_s \\vec{H}_p
s_m = - prob.mesh.edgeCurl.T * (prob.MfRho - self.MfRho(prob)) * self.jPrimary(prob) - 1j * omega(self.freq) * ((prob.MeMu - self.MeMu(prob)) * self.hPrimary(prob))
return s_m
else:
return Zero()
def s_mDeriv(self, prob, v, adjoint=False):
if prob._formulation == 'HJ':
if adjoint is True:
return - prob.MfRhoDeriv(self.jPrimary(prob)).T * (prob.mesh.edgeCurl * v)
return - prob.mesh.edgeCurl.T * (prob.MfRhoDeriv(self.jPrimary(prob)) * v)
else:
return Zero()
+2 -117
View File
@@ -4,124 +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.prob._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
"""
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
@@ -130,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 %s is not implemented' %self.knownFields.keys()[0])
if adjoint:
return self._phiDeriv_u(src, v, adjoint=adjoint), self._phiDeriv_m(src, v, adjoint=adjoint)
return np.array(self._phiDeriv_u(src, du_dm_v, adjoint) + self._phiDeriv_m(src, v, adjoint), dtype = float)
def _eDeriv(self, src, du_dm_v, v, adjoint=False):
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
if adjoint:
return self._eDeriv_u(src, v, adjoint), self._eDeriv_m(src, v, adjoint)
return np.array(self._eDeriv_u(src, du_dm_v, adjoint) + self._eDeriv_m(src, v, adjoint), dtype = float)
def _jDeriv(self, src, du_dm_v, v, adjoint=False):
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
if adjoint:
return self._jDeriv_u(src, v, adjoint), self._jDeriv_m(src, v, adjoint)
return np.array(self._jDeriv_u(src, du_dm_v, adjoint) + self._jDeriv_m(src, v, adjoint), dtype = float)
class Fields_CC(Fields):
knownFields = {'phiSolution':'CC'}
aliasFields = {
'phi': ['phiSolution','CC','_phi'],
'j' : ['phiSolution','F','_j'],
'e' : ['phiSolution','F','_e'],
'charge' : ['phiSolution','CC','_charge'],
}
# primary - secondary
# CC variables
def __init__(self, mesh, survey, **kwargs):
Fields.__init__(self, mesh, survey, **kwargs)
mesh.setCellGradBC("neumann")
cellGrad = mesh.cellGrad
def startup(self):
self.prob = self.survey.prob
def _GLoc(self, fieldType):
if fieldType == 'phi':
return 'CC'
elif fieldType == 'e' or fieldType == 'j':
return 'F'
else:
raise Exception('Field type must be phi, e, j')
def _phi(self, phiSolution, srcList):
return phiSolution
def _phiDeriv_u(self, src, v, adjoint = False):
return Identity()*v
def _phiDeriv_m(self, src, v, adjoint = False):
return Zero()
def _j(self, phiSolution, srcList):
"""
.. math::
\mathbf{j} = \mathbf{M}^{f \ -1}_{\rho} \mathbf{G} \phi
"""
return self.prob.MfRhoI*self.prob.Grad*phiSolution
def _e(self, phiSolution, srcList):
"""
In HJ formulation e is not well-defined!!
.. math::
\vec{e} = -\nabla \phi
"""
return -self.mesh.cellGrad*phiSolution
def _charge(self, phiSolution, srcList):
"""
.. math::
\int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0}
"""
return epsilon_0*self.prob.Vol*(self.mesh.faceDiv*self._e(phiSolution, srcList))
class Fields_N(Fields):
knownFields = {'phiSolution':'N'}
aliasFields = {
'phi': ['phiSolution','N','_phi'],
'j' : ['phiSolution','E','_j'],
'e' : ['phiSolution','E','_e'],
'charge' : ['phiSolution','N','_charge'],
}
# primary - secondary
# N variables
def __init__(self, mesh, survey, **kwargs):
Fields.__init__(self, mesh, survey, **kwargs)
def startup(self):
self.prob = self.survey.prob
def _GLoc(self, fieldType):
if fieldType == 'phi':
return 'N'
elif fieldType == 'e' or fieldType == 'j':
return 'E'
else:
raise Exception('Field type must be phi, e, j')
def _phi(self, phiSolution, srcList):
return phiSolution
def _phiDeriv_u(self, src, v, adjoint = False):
return Identity()*v
def _phiDeriv_m(self, src, v, adjoint = False):
return Zero()
def _j(self, phiSolution, srcList):
"""
In EB formulation j is not well-defined!!
.. math::
\mathbf{j} = - \mathbf{M}^{e}_{\sigma} \mathbf{G} \phi
"""
return self.prob.MeSigma * self._e(phiSolution, srcList)
def _e(self, phiSolution, srcList):
"""
In HJ formulation e is not well-defined!!
.. math::
\vec{e} = -\nabla \phi
"""
return -self.mesh.nodalGrad * phiSolution
def _charge(self, phiSolution, srcList):
"""
.. math::
\int \nabla \codt \vec{e} = \int \frac{\rho_v }{\epsillon_0}
"""
return - epsilon_0*(self.mesh.nodalGrad.T*self.mesh.getEdgeInnerProduct()*self._e(phiSolution, srcList))
+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 %s is not implemented' %self.knownFields.keys()[0])
if adjoint:
return self._phiDeriv_u(kyInd, src, v, adjoint=adjoint), self._phiDeriv_m(kyInd, src, v, adjoint=adjoint)
return np.array(self._phiDeriv_u(kyInd, src, du_dm_v, adjoint) + self._phiDeriv_m(kyInd, src, v, adjoint), dtype = float)
def _eDeriv(self,kyInd, src, du_dm_v, v, adjoint=False):
if getattr(self, '_eDeriv_u', None) is None or getattr(self, '_eDeriv_m', None) is None:
raise NotImplementedError ('Getting eDerivs from %s is not implemented' %self.knownFields.keys()[0])
if adjoint:
return self._eDeriv_u(kyInd, src, v, adjoint), self._eDeriv_m(kyInd, src, v, adjoint)
return np.array(self._eDeriv_u(kyInd, src, du_dm_v, adjoint) + self._eDeriv_m(kyInd, src, v, adjoint), dtype = float)
def _jDeriv(self,kyInd, src, du_dm_v, v, adjoint=False):
if getattr(self, '_jDeriv_u', None) is None or getattr(self, '_jDeriv_m', None) is None:
raise NotImplementedError ('Getting jDerivs from %s is not implemented' %self.knownFields.keys()[0])
if adjoint:
return self._jDeriv_u(kyInd, src, v, adjoint), self._jDeriv_m(kyInd, src, v, adjoint)
return np.array(self._jDeriv_u(kyInd, src, du_dm_v, adjoint) + self._jDeriv_m(kyInd, src, v, adjoint), dtype = float)
# def _eDeriv(self, tInd, src, dun_dm_v, v, adjoint=False):
# if adjoint is True:
# return self._eDeriv_u(tInd, src, v, adjoint), self._eDeriv_m(tInd, src, v, adjoint)
# return self._eDeriv_u(tInd, src, dun_dm_v) + self._eDeriv_m(tInd, src, v)
# def _bDeriv(self, tInd, src, dun_dm_v, v, adjoint=False):
# if adjoint is True:
# return self._bDeriv_u(tInd, src, v, adjoint), self._bDeriv_m(tInd, src, v, adjoint)
# return self._bDeriv_u(tInd, src, dun_dm_v) + self._bDeriv_m(tInd, src, v)
class Fields_ky_CC(Fields_ky):
knownFields = {'phiSolution':'CC'}
aliasFields = {
'phi': ['phiSolution','CC','_phi'],
'j' : ['phiSolution','F','_j'],
'e' : ['phiSolution','F','_e'],
}
# primary - secondary
# CC variables
def __init__(self, mesh, survey, **kwargs):
Fields_ky.__init__(self, mesh, survey, **kwargs)
def startup(self):
self.prob = self.survey.prob
def _GLoc(self, fieldType):
if fieldType == 'phi':
return 'CC'
elif fieldType == 'e' or fieldType == 'j':
return 'F'
else:
raise Exception('Field type must be phi, e, j')
def _phi(self, phiSolution, src, kyInd):
return phiSolution
def _phiDeriv_u(self, kyInd, src, v, adjoint = False):
return Identity()*v
def _phiDeriv_m(self, kyInd, src, v, adjoint = False):
return Zero()
def _j(self, phiSolution, srcList):
raise NotImplementedError
def _e(self, phiSolution, srcList):
raise NotImplementedError
class Fields_ky_N(Fields_ky):
knownFields = {'phiSolution':'N'}
aliasFields = {
'phi': ['phiSolution','N','_phi'],
'j' : ['phiSolution','E','_j'],
'e' : ['phiSolution','E','_e'],
}
# primary - secondary
# CC variables
def __init__(self, mesh, survey, **kwargs):
Fields_ky.__init__(self, mesh, survey, **kwargs)
def startup(self):
self.prob = self.survey.prob
def _GLoc(self, fieldType):
if fieldType == 'phi':
return 'N'
elif fieldType == 'e' or fieldType == 'j':
return 'E'
else:
raise Exception('Field type must be phi, e, j')
def _phi(self, phiSolution, src, kyInd):
return phiSolution
def _phiDeriv_u(self, kyInd, src, v, adjoint = False):
return Identity()*v
def _phiDeriv_m(self, kyInd, src, v, adjoint = False):
return Zero()
def _j(self, phiSolution, srcList):
raise NotImplementedError
def _e(self, phiSolution, srcList):
raise NotImplementedError
+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, '_%sDeriv'%rx.projField, None)
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
return Utils.mkvc(Jv)
def Jtvec(self, m, v, f=None):
if f is None:
f = self.fields(m)
self.curModel = m
# Ensure v is a data object.
if not isinstance(v, self.dataPair):
v = self.dataPair(self.survey, v)
Jtv = np.zeros(m.size)
AT = self.getA()
for src in self.survey.srcList:
u_src = f[src, self._solutionType]
for rx in src.rxList:
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
ATinvdf_duT = self.Ainv * df_duT
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
du_dmT = -dA_dmT + dRHS_dmT
Jtv += (df_dmT + du_dmT).astype(float)
return Utils.mkvc(Jtv)
def getSourceTerm(self):
"""
takes concept of source and turns it into a matrix
"""
"""
Evaluates the sources, and puts them in matrix form
:rtype: (numpy.ndarray, numpy.ndarray)
:return: q (nC or nN, nSrc)
"""
Srcs = self.survey.srcList
if self._formulation is 'EB':
n = self.mesh.nN
# return NotImplementedError
elif self._formulation is 'HJ':
n = self.mesh.nC
q = np.zeros((n, len(Srcs)))
for i, src in enumerate(Srcs):
q[:,i] = src.eval(self)
return q
class Problem3D_CC(BaseDCProblem):
_solutionType = 'phiSolution'
_formulation = 'HJ' # CC potentials means J is on faces
fieldsPair = Fields_CC
def __init__(self, mesh, **kwargs):
BaseDCProblem.__init__(self, mesh, **kwargs)
self.setBC()
def getA(self):
"""
Make the A matrix for the cell centered DC resistivity problem
A = D MfRhoI G
"""
D = self.Div
G = self.Grad
MfRhoI = self.MfRhoI
A = D * MfRhoI * G
# I think we should deprecate this for DC problem.
# if self._makeASymmetric is True:
# return V.T * A
return A
def getADeriv(self, u, v, adjoint= False):
D = self.Div
G = self.Grad
MfRhoIDeriv = self.MfRhoIDeriv
if adjoint:
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
return D * (MfRhoIDeriv( G * u ) * v)
def getRHS(self):
"""
RHS for the DC problem
q
"""
RHS = self.getSourceTerm()
return RHS
def getRHSDeriv(self, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
"""
# TODO: add qDeriv for RHS depending on m
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
# return qDeriv
return Zero()
def setBC(self):
if self.mesh.dim==3:
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
gBFxm = self.mesh.gridFx[fxm,:]
gBFxp = self.mesh.gridFx[fxp,:]
gBFym = self.mesh.gridFy[fym,:]
gBFyp = self.mesh.gridFy[fyp,:]
gBFzm = self.mesh.gridFz[fzm,:]
gBFzp = self.mesh.gridFz[fzp,:]
# Setup Mixed B.C (alpha, beta, gamma)
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
beta_xm, beta_xp = temp_xm, temp_xp
beta_ym, beta_yp = temp_ym, temp_yp
beta_zm, beta_zp = temp_zm, temp_zp
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
elif self.mesh.dim==2:
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
gBFxm = self.mesh.gridFx[fxm,:]
gBFxp = self.mesh.gridFx[fxp,:]
gBFym = self.mesh.gridFy[fym,:]
gBFyp = self.mesh.gridFy[fyp,:]
# Setup Mixed B.C (alpha, beta, gamma)
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
beta_xm, beta_xp = temp_xm, temp_xp
beta_ym, beta_yp = temp_ym, temp_yp
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
V = self.Vol
self.Div = V * self.mesh.faceDiv
P_BC, B = self.mesh.getBCProjWF_simple()
M = B*self.mesh.aveCC2F
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
class Problem3D_N(BaseDCProblem):
_solutionType = 'phiSolution'
_formulation = 'EB' # N potentials means B is on faces
fieldsPair = Fields_N
def __init__(self, mesh, **kwargs):
BaseDCProblem.__init__(self, mesh, **kwargs)
def getA(self):
"""
Make the A matrix for the cell centered DC resistivity problem
A = G.T MeSigma G
"""
MeSigma = self.MeSigma
Grad = self.mesh.nodalGrad
A = Grad.T * MeSigma * Grad
# Handling Null space of A
A[0,0] = A[0,0] + 1.
return A
def getADeriv(self, u, v, adjoint=False):
"""
Product of the derivative of our system matrix with respect to the model and a vector
"""
MeSigma = self.MeSigma
Grad = self.mesh.nodalGrad
if not adjoint:
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
elif adjoint:
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
def getRHS(self):
"""
RHS for the DC problem
q
"""
RHS = self.getSourceTerm()
return RHS
def getRHSDeriv(self, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
"""
# TODO: add qDeriv for RHS depending on m
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
# return qDeriv
return Zero()
+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, '_%sDeriv'%rx.projField, None)
df_dm_v = df_dmFun(iky, src, du_dm_v, v, adjoint=False)
# Trapezoidal intergration
Jv1_temp = 1./np.pi*rx.evalDeriv(ky, src, self.mesh, f, df_dm_v)
if iky==0:
#First assigment
Jv[src, rx] = Jv1_temp*dky[iky]*np.cos(ky*y)
else:
Jv[src, rx] += Jv1_temp*dky[iky] /2.*np.cos(ky*y)
Jv[src, rx] += Jv0[src, rx]*dky[iky]/2.*np.cos(ky*y)
Jv0[src, rx] = Jv1_temp.copy()
return Utils.mkvc(Jv)
def Jtvec(self, m, v, f=None):
if f is None:
f = self.fields(m)
self.curModel = m
# Ensure v is a data object.
if not isinstance(v, self.dataPair):
v = self.dataPair(self.survey, v)
Jtv = np.zeros(m.size, dtype=float)
# Assume y=0.
# This needs some thoughts to implement in general when src is dipole
dky = np.diff(self.kys)
dky = np.r_[dky[0], dky]
y = 0.
for src in self.survey.srcList:
for rx in src.rxList:
Jtv_temp1 = np.zeros(m.size, dtype=float)
Jtv_temp0 = np.zeros(m.size, dtype=float)
#TODO: this loop is pretty slow .. (Parellize)
for iky in range(self.nky):
u_src = f[src, self._solutionType, iky]
ky = self.kys[iky]
AT = self.getA(ky)
PTv = rx.evalDeriv(ky, src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
df_duT, df_dmT = df_duTFun(iky, src, None, PTv, adjoint=True)
ATinvdf_duT = self.Ainv[iky] * df_duT
dA_dmT = self.getADeriv(ky, u_src, ATinvdf_duT, adjoint=True)
dRHS_dmT = self.getRHSDeriv(ky, src, ATinvdf_duT, adjoint=True)
du_dmT = -dA_dmT + dRHS_dmT
Jtv_temp1 = 1./np.pi*(df_dmT + du_dmT).astype(float)
# Trapezoidal intergration
if iky==0:
#First assigment
Jtv += Jtv_temp1*dky[iky]*np.cos(ky*y)
else:
Jtv += Jtv_temp1*dky[iky]/2.*np.cos(ky*y)
Jtv += Jtv_temp0*dky[iky]/2.*np.cos(ky*y)
Jtv_temp0 = Jtv_temp1.copy()
return Utils.mkvc(Jtv)
def getSourceTerm(self, ky):
"""
takes concept of source and turns it into a matrix
"""
"""
Evaluates the sources, and puts them in matrix form
:rtype: (numpy.ndarray, numpy.ndarray)
:return: q (nC or nN, nSrc)
"""
Srcs = self.survey.srcList
if self._formulation is 'EB':
n = self.mesh.nN
# return NotImplementedError
elif self._formulation is 'HJ':
n = self.mesh.nC
q = np.zeros((n, len(Srcs)))
for i, src in enumerate(Srcs):
q[:,i] = src.eval(self)
return q
class Problem2D_CC(BaseDCProblem_2D):
_solutionType = 'phiSolution'
_formulation = 'HJ' # CC potentials means J is on faces
fieldsPair = Fields_ky_CC
def __init__(self, mesh, **kwargs):
BaseDCProblem_2D.__init__(self, mesh, **kwargs)
self.setBC()
def getA(self, ky):
"""
Make the A matrix for the cell centered DC resistivity problem
A = D MfRhoI G
"""
D = self.Div
G = self.Grad
vol = self.mesh.vol
MfRhoI = self.MfRhoI
# Get resistivity rho
rho = self.curModel.rho
A = D * MfRhoI * G + Utils.sdiag(ky**2*vol/rho)
return A
def getADeriv(self, ky, u, v, adjoint= False):
D = self.Div
G = self.Grad
vol = self.mesh.vol
MfRhoIDeriv = self.MfRhoIDeriv
rho = self.curModel.rho
if adjoint:
return(MfRhoIDeriv( G * u ).T) * ( D.T * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v
return D * ((MfRhoIDeriv( G * u )) * v) + ky**2*Utils.sdiag(u.flatten()*vol*(-1./rho**2))*v
def getRHS(self, ky):
"""
RHS for the DC problem
q
"""
RHS = self.getSourceTerm(ky)
return RHS
def getRHSDeriv(self, ky, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
"""
# TODO: add qDeriv for RHS depending on m
# qDeriv = src.evalDeriv(self, ky, adjoint=adjoint)
# return qDeriv
return Zero()
def setBC(self):
if self.mesh.dim==3:
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
gBFxm = self.mesh.gridFx[fxm,:]
gBFxp = self.mesh.gridFx[fxp,:]
gBFym = self.mesh.gridFy[fym,:]
gBFyp = self.mesh.gridFy[fyp,:]
gBFzm = self.mesh.gridFz[fzm,:]
gBFzp = self.mesh.gridFz[fzp,:]
# Setup Mixed B.C (alpha, beta, gamma)
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
beta_xm, beta_xp = temp_xm, temp_xp
beta_ym, beta_yp = temp_ym, temp_yp
beta_zm, beta_zp = temp_zm, temp_zp
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
elif self.mesh.dim==2:
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
gBFxm = self.mesh.gridFx[fxm,:]
gBFxp = self.mesh.gridFx[fxp,:]
gBFym = self.mesh.gridFy[fym,:]
gBFyp = self.mesh.gridFy[fyp,:]
# Setup Mixed B.C (alpha, beta, gamma)
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
beta_xm, beta_xp = temp_xm, temp_xp
beta_ym, beta_yp = temp_ym, temp_yp
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
V = self.Vol
self.Div = V * self.mesh.faceDiv
P_BC, B = self.mesh.getBCProjWF_simple()
M = B*self.mesh.aveCC2F
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
class Problem2D_N(BaseDCProblem_2D):
_solutionType = 'phiSolution'
_formulation = 'EB' # CC potentials means J is on faces
fieldsPair = Fields_ky_N
def __init__(self, mesh, **kwargs):
BaseDCProblem_2D.__init__(self, mesh, **kwargs)
# self.setBC()
@property
def MnSigma(self):
"""
Node inner product matrix for \\(\\sigma\\). Used in the E-B formulation
"""
# TODO: only works isotropic sigma
sigma = self.curModel.sigma
vol = self.mesh.vol
MnSigma = Utils.sdiag(self.mesh.aveN2CC.T*(Utils.sdiag(vol)*sigma))
return MnSigma
def MnSigmaDeriv(self, u):
"""
Derivative of MnSigma with respect to the model
"""
sigma = self.curModel.sigma
sigmaderiv = self.curModel.sigmaDeriv
vol = self.mesh.vol
return Utils.sdiag(u)*self.mesh.aveN2CC.T*Utils.sdiag(vol) * self.curModel.sigmaDeriv
def getA(self, ky):
"""
Make the A matrix for the cell centered DC resistivity problem
A = D MfRhoI G
"""
MeSigma = self.MeSigma
MnSigma = self.MnSigma
Grad = self.mesh.nodalGrad
# Get conductivity sigma
sigma = self.curModel.sigma
A = Grad.T * MeSigma * Grad + ky**2*MnSigma
# Handling Null space of A
A[0,0] = A[0,0] + 1.
return A
def getADeriv(self, ky, u, v, adjoint= False):
MeSigma = self.MeSigma
Grad = self.mesh.nodalGrad
sigma = self.curModel.sigma
vol = self.mesh.vol
if adjoint:
return self.MeSigmaDeriv(Grad*u).T * (Grad*v) + ky**2*self.MnSigmaDeriv(u).T*v
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v) + ky**2*self.MnSigmaDeriv(u)*v
def getRHS(self, ky):
"""
RHS for the DC problem
q
"""
RHS = self.getSourceTerm(ky)
return RHS
def getRHSDeriv(self, ky, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
"""
# TODO: add qDeriv for RHS depending on m
# qDeriv = src.evalDeriv(self, ky, adjoint=adjoint)
# return qDeriv
return Zero()
+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, '_%sDeriv'%rx.projField, None)
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
Jv[src, rx] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
# Conductivity (d u / d log sigma)
if self._formulation is 'EB':
return -Utils.mkvc(Jv)
# Conductivity (d u / d log rho)
if self._formulation is 'HJ':
return Utils.mkvc(Jv)
def Jtvec(self, m, v, f=None):
if f is None:
f = self.fields(m)
self.curModel = m
# Ensure v is a data object.
if not isinstance(v, self.dataPair):
v = self.dataPair(self.survey, v)
Jtv = np.zeros(m.size)
AT = self.getA()
for src in self.survey.srcList:
u_src = f[src, self._solutionType]
for rx in src.rxList:
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx], adjoint=True) # wrt f, need possibility wrt m
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
ATinvdf_duT = self.Ainv * df_duT
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
du_dmT = -dA_dmT + dRHS_dmT
Jtv += (df_dmT + du_dmT).astype(float)
# Conductivity ((d u / d log sigma).T)
if self._formulation is 'EB':
return -Utils.mkvc(Jtv)
# Conductivity ((d u / d log rho).T)
if self._formulation is 'HJ':
return Utils.mkvc(Jtv)
def getSourceTerm(self):
"""
takes concept of source and turns it into a matrix
"""
"""
Evaluates the sources, and puts them in matrix form
:rtype: (numpy.ndarray, numpy.ndarray)
:return: q (nC or nN, nSrc)
"""
Srcs = self.survey.srcList
if self._formulation is 'EB':
n = self.mesh.nN
# return NotImplementedError
elif self._formulation is 'HJ':
n = self.mesh.nC
q = np.zeros((n, len(Srcs)))
for i, src in enumerate(Srcs):
q[:,i] = src.eval(self)
return q
@property
def deleteTheseOnModelUpdate(self):
toDelete = []
return toDelete
# assume log rho or log cond
@property
def MeSigma(self):
"""
Edge inner product matrix for \\(\\sigma\\). Used in the E-B formulation
"""
if getattr(self, '_MeSigma', None) is None:
self._MeSigma = self.mesh.getEdgeInnerProduct(self.sigma)
return self._MeSigma
@property
def MfRhoI(self):
"""
Inverse of :code:`MfRho`
"""
if getattr(self, '_MfRhoI', None) is None:
self._MfRhoI = self.mesh.getFaceInnerProduct(self.rho, invMat=True)
return self._MfRhoI
def MfRhoIDeriv(self,u):
"""
Derivative of :code:`MfRhoI` with respect to the model.
"""
dMfRhoI_dI = -self.MfRhoI**2
dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u)
drho_dlogrho = Utils.sdiag(self.rho)*self.curModel.etaDeriv
return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho))
# TODO: This should take a vector
def MeSigmaDeriv(self, u):
"""
Derivative of MeSigma with respect to the model
"""
dsigma_dlogsigma = Utils.sdiag(self.sigma)*self.curModel.etaDeriv
return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma
class Problem3D_CC(BaseIPProblem):
_solutionType = 'phiSolution'
_formulation = 'HJ' # CC potentials means J is on faces
fieldsPair = Fields_CC
def __init__(self, mesh, **kwargs):
BaseIPProblem.__init__(self, mesh, **kwargs)
self.setBC()
def getA(self):
"""
Make the A matrix for the cell centered DC resistivity problem
A = D MfRhoI G
"""
D = self.Div
G = self.Grad
MfRhoI = self.MfRhoI
A = D * MfRhoI * G
# I think we should deprecate this for DC problem.
# if self._makeASymmetric is True:
# return V.T * A
return A
def getADeriv(self, u, v, adjoint= False):
D = self.Div
G = self.Grad
MfRhoIDeriv = self.MfRhoIDeriv
if adjoint:
# if self._makeASymmetric is True:
# v = V * v
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
# I think we should deprecate this for DC problem.
# if self._makeASymmetric is True:
# return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) )
return D * (MfRhoIDeriv( G * u ) * v)
def getRHS(self):
"""
RHS for the DC problem
q
"""
RHS = self.getSourceTerm()
# I think we should deprecate this for DC problem.
# if self._makeASymmetric is True:
# return self.Vol.T * RHS
return RHS
def getRHSDeriv(self, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
"""
# TODO: add qDeriv for RHS depending on m
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
# return qDeriv
return Zero()
def setBC(self):
if self.mesh.dim==3:
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
gBFxm = self.mesh.gridFx[fxm,:]
gBFxp = self.mesh.gridFx[fxp,:]
gBFym = self.mesh.gridFy[fym,:]
gBFyp = self.mesh.gridFy[fyp,:]
gBFzm = self.mesh.gridFz[fzm,:]
gBFzp = self.mesh.gridFz[fzp,:]
# Setup Mixed B.C (alpha, beta, gamma)
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
beta_xm, beta_xp = temp_xm, temp_xp
beta_ym, beta_yp = temp_ym, temp_yp
beta_zm, beta_zp = temp_zm, temp_zp
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
elif self.mesh.dim==2:
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
gBFxm = self.mesh.gridFx[fxm,:]
gBFxp = self.mesh.gridFx[fxp,:]
gBFym = self.mesh.gridFy[fym,:]
gBFyp = self.mesh.gridFy[fyp,:]
# Setup Mixed B.C (alpha, beta, gamma)
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
beta_xm, beta_xp = temp_xm, temp_xp
beta_ym, beta_yp = temp_ym, temp_yp
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
V = self.Vol
self.Div = V * self.mesh.faceDiv
P_BC, B = self.mesh.getBCProjWF_simple()
M = B*self.mesh.aveCC2F
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
class Problem3D_N(BaseIPProblem):
_solutionType = 'phiSolution'
_formulation = 'EB' # N potentials means B is on faces
fieldsPair = Fields_N
def __init__(self, mesh, **kwargs):
BaseIPProblem.__init__(self, mesh, **kwargs)
def getA(self):
"""
Make the A matrix for the cell centered DC resistivity problem
A = G.T MeSigma G
"""
MeSigma = self.MeSigma
Grad = self.mesh.nodalGrad
A = Grad.T * MeSigma * Grad
# Handling Null space of A
A[0,0] = A[0,0] + 1.
return A
def getADeriv(self, u, v, adjoint=False):
"""
Product of the derivative of our system matrix with respect to the model and a vector
"""
MeSigma = self.MeSigma
Grad = self.mesh.nodalGrad
if not adjoint:
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
elif adjoint:
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
def getRHS(self):
"""
RHS for the DC problem
q
"""
RHS = self.getSourceTerm()
return RHS
def getRHSDeriv(self, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
"""
# TODO: add qDeriv for RHS depending on m
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
# return qDeriv
return Zero()
if __name__ == '__main__':
cs = 12.5
hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
hz = [(cs,7, -1.3),(cs,20)]
mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN")
sigma = np.ones(mesh.nC)
prob = BaseIPProblem(mesh, sigma=sigma)
+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, '_%sDeriv'%rx.projField, None)
df_dm_v = df_dmFun(src, du_dm_v, v, adjoint=False)
Jv[src, rx, t] = rx.evalDeriv(src, self.mesh, f, df_dm_v)
# Conductivity (d u / d log sigma)
if self._formulation is 'EB':
return -Utils.mkvc(Jv)
# Resistivity (d u / d log rho)
if self._formulation is 'HJ':
return Utils.mkvc(Jv)
def Jvec(self, m, v, f=None):
if f is None:
f = self.fields(m)
self.curModel = m
Jv = self.dataPair(self.survey) #same size as the data
# A = self.getA()
JvAll = []
#Assume only eta and tau (eta first then tau)
# v = [2*Mx1]
v = v.reshape((int(v.size/2), 2), order='F')
for tind in range(len(self.survey.times)):
t = self.survey.times[tind]
v0 = self.EtaDeriv(t, v[:,0])
v1 = self.TauiDeriv(t, v[:,1])
for src in self.survey.srcList:
u_src = f[src, self._solutionType] # solution vector
dA_dm_v0 = self.getADeriv(u_src, v0)
dRHS_dm_v0 = self.getRHSDeriv(src, v0)
du_dm_v0 = self.Ainv * ( - dA_dm_v0 + dRHS_dm_v0 )
dA_dm_v1 = self.getADeriv(u_src, v1)
dRHS_dm_v1 = self.getRHSDeriv(src, v1)
du_dm_v1 = self.Ainv * ( - dA_dm_v1 + dRHS_dm_v1 )
for rx in src.rxList:
timeindex = rx.getTimeP(self.survey.times)
if timeindex[tind]:
df_dmFun = getattr(f, '_%sDeriv'%rx.projField, None)
df_dm_v0 = df_dmFun(src, du_dm_v0, v0, adjoint=False)
df_dm_v1 = df_dmFun(src, du_dm_v1, v1, adjoint=False)
Jv[src, rx, t] = rx.evalDeriv(src, self.mesh, f, df_dm_v0)
Jv[src, rx, t] += rx.evalDeriv(src, self.mesh, f, df_dm_v1)
# Conductivity (d u / d log sigma)
if self._formulation is 'EB':
return -Jv.tovec()
# Resistivity (d u / d log rho)
if self._formulation is 'HJ':
return Jv.tovec()
def Jtvec(self, m, v, f=None):
if f is None:
f = self.fields(m)
self.curModel = m
# Ensure v is a data object.
if not isinstance(v, self.dataPair):
v = self.dataPair(self.survey, v)
Jtv= np.zeros(m.size)
for tind in range(len(self.survey.times)):
t = self.survey.times[tind]
for src in self.survey.srcList:
u_src = f[src, self._solutionType]
for rx in src.rxList:
timeindex = rx.getTimeP(self.survey.times)
if timeindex[tind]:
PTv = rx.evalDeriv(src, self.mesh, f, v[src, rx, t], adjoint=True) # wrt f, need possibility wrt m
df_duTFun = getattr(f, '_%sDeriv'%rx.projField, None)
df_duT, df_dmT = df_duTFun(src, None, PTv, adjoint=True)
ATinvdf_duT = self.Ainv * df_duT
dA_dmT = self.getADeriv(u_src, ATinvdf_duT, adjoint=True)
dRHS_dmT = self.getRHSDeriv(src, ATinvdf_duT, adjoint=True)
du_dmT = -dA_dmT + dRHS_dmT
Jtv += np.r_[self.EtaDeriv(self.survey.times[tind], du_dmT, adjoint=True), self.TauiDeriv(self.survey.times[tind], du_dmT, adjoint=True)]
# Conductivity ((d u / d log sigma).T)
if self._formulation is 'EB':
return -Jtv
# Conductivity ((d u / d log rho).T)
if self._formulation is 'HJ':
return Jtv
def getSourceTerm(self):
"""
takes concept of source and turns it into a matrix
"""
"""
Evaluates the sources, and puts them in matrix form
:rtype: (numpy.ndarray, numpy.ndarray)
:return: q (nC or nN, nSrc)
"""
Srcs = self.survey.srcList
if self._formulation is 'EB':
n = self.mesh.nN
# return NotImplementedError
elif self._formulation is 'HJ':
n = self.mesh.nC
q = np.zeros((n, len(Srcs)))
for i, src in enumerate(Srcs):
q[:,i] = src.eval(self)
return q
@property
def deleteTheseOnModelUpdate(self):
toDelete = []
return toDelete
# assume log rho or log cond
@property
def MeSigma(self):
"""
Edge inner product matrix for \\(\\sigma\\). Used in the E-B formulation
"""
if getattr(self, '_MeSigma', None) is None:
self._MeSigma = self.mesh.getEdgeInnerProduct(self.sigma)
return self._MeSigma
@property
def MfRhoI(self):
"""
Inverse of :code:`MfRho`
"""
if getattr(self, '_MfRhoI', None) is None:
self._MfRhoI = self.mesh.getFaceInnerProduct(self.rho, invMat=True)
return self._MfRhoI
def MfRhoIDeriv(self,u):
"""
Derivative of :code:`MfRhoI` with respect to the model.
"""
dMfRhoI_dI = -self.MfRhoI**2
dMf_drho = self.mesh.getFaceInnerProductDeriv(self.rho)(u)
drho_dlogrho = Utils.sdiag(self.rho)
return dMfRhoI_dI * ( dMf_drho * ( drho_dlogrho))
# TODO: This should take a vector
def MeSigmaDeriv(self, u):
"""
Derivative of MeSigma with respect to the model
"""
dsigma_dlogsigma = Utils.sdiag(self.sigma)
return self.mesh.getEdgeInnerProductDeriv(self.sigma)(u) * dsigma_dlogsigma
class Problem3D_CC(BaseSIPProblem):
_solutionType = 'phiSolution'
_formulation = 'HJ' # CC potentials means J is on faces
fieldsPair = Fields_CC
def __init__(self, mesh, **kwargs):
BaseSIPProblem.__init__(self, mesh, **kwargs)
self.setBC()
def getA(self):
"""
Make the A matrix for the cell centered DC resistivity problem
A = D MfRhoI G
"""
D = self.Div
G = self.Grad
# TODO: this won't work for full anisotropy
MfRhoI = self.MfRhoI
A = D * MfRhoI * G
# I think we should deprecate this for DC problem.
# if self._makeASymmetric is True:
# return V.T * A
return A
def getADeriv(self, u, v, adjoint= False):
D = self.Div
G = self.Grad
MfRhoIDeriv = self.MfRhoIDeriv
if adjoint:
# if self._makeASymmetric is True:
# v = V * v
return(MfRhoIDeriv( G * u ).T) * ( D.T * v)
# I think we should deprecate this for DC problem.
# if self._makeASymmetric is True:
# return V.T * ( D * ( MfRhoIDeriv( D.T * ( V * u ) ) * v ) )
return D * (MfRhoIDeriv( G * u ) * v)
def getRHS(self):
"""
RHS for the DC problem
q
"""
RHS = self.getSourceTerm()
# I think we should deprecate this for DC problem.
# if self._makeASymmetric is True:
# return self.Vol.T * RHS
return RHS
def getRHSDeriv(self, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
"""
# TODO: add qDeriv for RHS depending on m
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
# return qDeriv
return Zero()
def setBC(self):
if self.mesh.dim==3:
fxm,fxp,fym,fyp,fzm,fzp = self.mesh.faceBoundaryInd
gBFxm = self.mesh.gridFx[fxm,:]
gBFxp = self.mesh.gridFx[fxp,:]
gBFym = self.mesh.gridFy[fym,:]
gBFyp = self.mesh.gridFy[fyp,:]
gBFzm = self.mesh.gridFz[fzm,:]
gBFzp = self.mesh.gridFz[fzp,:]
# Setup Mixed B.C (alpha, beta, gamma)
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
temp_zm, temp_zp = np.ones_like(gBFzm[:,2]), np.ones_like(gBFzp[:,2])
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
alpha_zm, alpha_zp = temp_zm*0., temp_zp*0.
beta_xm, beta_xp = temp_xm, temp_xp
beta_ym, beta_yp = temp_ym, temp_yp
beta_zm, beta_zp = temp_zm, temp_zp
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
gamma_zm, gamma_zp = temp_zm*0., temp_zp*0.
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp, alpha_zm, alpha_zp]
beta = [beta_xm, beta_xp, beta_ym, beta_yp, beta_zm, beta_zp]
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp, gamma_zm, gamma_zp]
elif self.mesh.dim==2:
fxm,fxp,fym,fyp = self.mesh.faceBoundaryInd
gBFxm = self.mesh.gridFx[fxm,:]
gBFxp = self.mesh.gridFx[fxp,:]
gBFym = self.mesh.gridFy[fym,:]
gBFyp = self.mesh.gridFy[fyp,:]
# Setup Mixed B.C (alpha, beta, gamma)
temp_xm, temp_xp = np.ones_like(gBFxm[:,0]), np.ones_like(gBFxp[:,0])
temp_ym, temp_yp = np.ones_like(gBFym[:,1]), np.ones_like(gBFyp[:,1])
alpha_xm, alpha_xp = temp_xm*0., temp_xp*0.
alpha_ym, alpha_yp = temp_ym*0., temp_yp*0.
beta_xm, beta_xp = temp_xm, temp_xp
beta_ym, beta_yp = temp_ym, temp_yp
gamma_xm, gamma_xp = temp_xm*0., temp_xp*0.
gamma_ym, gamma_yp = temp_ym*0., temp_yp*0.
alpha = [alpha_xm, alpha_xp, alpha_ym, alpha_yp]
beta = [beta_xm, beta_xp, beta_ym, beta_yp]
gamma = [gamma_xm, gamma_xp, gamma_ym, gamma_yp]
x_BC, y_BC = getxBCyBC_CC(self.mesh, alpha, beta, gamma)
V = self.Vol
self.Div = V * self.mesh.faceDiv
P_BC, B = self.mesh.getBCProjWF_simple()
M = B*self.mesh.aveCC2F
self.Grad = self.Div.T - P_BC*Utils.sdiag(y_BC)*M
class Problem3D_N(BaseSIPProblem):
_solutionType = 'phiSolution'
_formulation = 'EB' # N potentials means B is on faces
fieldsPair = Fields_N
def __init__(self, mesh, **kwargs):
BaseSIPProblem.__init__(self, mesh, **kwargs)
def getA(self):
"""
Make the A matrix for the cell centered DC resistivity problem
A = G.T MeSigma G
"""
# TODO: this won't work for full anisotropy
MeSigma = self.MeSigma
Grad = self.mesh.nodalGrad
A = Grad.T * MeSigma * Grad
# Handling Null space of A
A[0,0] = A[0,0] + 1.
return A
def getADeriv(self, u, v, adjoint=False):
"""
Product of the derivative of our system matrix with respect to the model and a vector
"""
MeSigma = self.MeSigma
Grad = self.mesh.nodalGrad
if not adjoint:
return Grad.T*(self.MeSigmaDeriv(Grad*u)*v)
elif adjoint:
return self.MeSigmaDeriv(Grad*u).T * (Grad*v)
def getRHS(self):
"""
RHS for the DC problem
q
"""
RHS = self.getSourceTerm()
return RHS
def getRHSDeriv(self, src, v, adjoint=False):
"""
Derivative of the right hand side with respect to the model
"""
# TODO: add qDeriv for RHS depending on m
# qDeriv = src.evalDeriv(self, adjoint=adjoint)
# return qDeriv
return Zero()
if __name__ == '__main__':
cs = 12.5
hx = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
hy = [(cs,7, -1.3),(cs,21),(cs,7, 1.3)]
hz = [(cs,7, -1.3),(cs,20)]
mesh = Mesh.TensorMesh([hx, hy, hz],x0="CCN")
sigma = np.ones(mesh.nC)
prob = BaseSIPProblem(mesh, sigma=sigma)
+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
+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
+15 -29
View File
@@ -26,69 +26,55 @@ def getFDEMProblem(fdemType, comp, SrcList, freq, useMu=False, verbose=False):
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, integrate=True))
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, integrate=True))
elif SrcType is 'PrimSec':
primSrc = EM.FDEM.Src.MagDipole([], freq, np.r_[0.,0.,0.])
primarySurvey = EM.FDEM.Survey([primSrc])
primaryProblem = EM.FDEM.Problem_e(mesh,mapping=mapping)
mPrimary = np.ones(mapping.nP)*np.log(CONDUCTIVITY)
Src.append(EM.FDEM.Src.PrimSec([Rx0], freq, mPrimary, prob=primaryProblem, survey=primarySurvey))
elif SrcType is 'PrimSecCyl':
hx = [(cs,ncx + 2), (cs,npad + 2,1.3)]
hz = [(cs,npad + 2 ,-1.3), (cs,ncz+2), (cs,npad+2,1.3)]
primmesh = Mesh.CylMesh([hx,1,hz], '00C')
primSrc = EM.FDEM.Src.MagDipole([], freq, np.r_[0.,0.,0.])
primarySurvey = EM.FDEM.Survey([primSrc])
primaryProblem = EM.FDEM.Problem_e(primmesh)
mPrimary = np.ones(primmesh.nC)*CONDUCTIVITY
Src.append(EM.FDEM.Src.PrimSec([Rx0], freq, mPrimary, prob=primaryProblem, survey=primarySurvey))
Src.append(EM.FDEM.Src.RawVec([rx0], freq, mesh.getEdgeInnerProduct()*S_m, S_e))
if verbose:
print ' Fetching %s problem' % (fdemType)
if fdemType == 'e':
survey = EM.FDEM.Survey(Src)
prb = EM.FDEM.Problem_e(mesh, mapping=mapping)
prb = EM.FDEM.Problem3D_e(mesh, mapping=mapping)
elif fdemType == 'b':
survey = EM.FDEM.Survey(Src)
prb = EM.FDEM.Problem_b(mesh, mapping=mapping)
prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping)
elif fdemType == 'j':
survey = EM.FDEM.Survey(Src)
prb = EM.FDEM.Problem_j(mesh, mapping=mapping)
prb = EM.FDEM.Problem3D_j(mesh, mapping=mapping)
elif fdemType == 'h':
survey = EM.FDEM.Survey(Src)
prb = EM.FDEM.Problem_h(mesh, mapping=mapping)
prb = EM.FDEM.Problem3D_h(mesh, mapping=mapping)
else:
raise NotImplementedError()
+1
View File
@@ -1,5 +1,6 @@
import TDEM
import FDEM
import Static
import Base
import Analytics
import Utils
+53 -32
View File
@@ -2,19 +2,27 @@ from SimPEG import Mesh, Utils, np, sp
import SimPEG.DCIP as DC
import time
def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
def run(loc=None, sig=None, radi=None, param=None, surveyType='dipole-dipole', unitType='appConductivity', plotIt=True):
"""
DC Forward Simulation
=====================
Forward model conductive spheres in a half-space and plot a pseudo-section
Forward model two conductive spheres in a half-space and plot a
pseudo-section. Assumes an infinite line source and measures along the
center of the spheres.
Created by @fourndo on Mon Feb 01 19:28:06 2016
INPUT:
loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]]
radi = Radius of spheres [r1,r2]
param = Conductivity of background and two spheres [m0,m1,m2]
surveyType = survey type 'pole-dipole' or 'dipole-dipole'
unitType = Data type "appResistivity" | "appConductivity" | "volt"
Created by @fourndo
"""
assert stype in ['pdp', 'dpdp'], "Source type (stype) must be pdp or dpdp (pole dipole or dipole dipole)"
assert surveyType in ['pole-dipole', 'dipole-dipole'], "Source type (surveyType) must be pdp or dpdp (pole dipole or dipole dipole)"
assert unitType in ['appResistivity', 'appConductivity', 'volt'], "Unit type (unitType) must be appResistivity or appConductivity or volt (potential)"
if loc is None:
loc = np.c_[[-50.,0.,-50.],[50.,0.,-50.]]
@@ -27,7 +35,6 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
# First we need to create a mesh and a model.
# This is our mesh
dx = 5.
@@ -52,14 +59,10 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
# Get index of the center
indy = int(mesh.nCy/2)
# Plot the model for reference
# Define core mesh extent
xlim = 200
zlim = 125
# Specify the survey type: "pdp" | "dpdp"
zlim = 100
# Then specify the end points of the survey. Let's keep it simple for now and survey above the anomalies, top of the mesh
ends = [(-175,0),(175,0)]
@@ -70,19 +73,20 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
locs = np.c_[mesh.gridCC[indx,0],mesh.gridCC[indx,1],np.ones(2).T*mesh.vectorNz[-1]]
# We will handle the geometry of the survey for you and create all the combination of tx-rx along line
# [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2])
survey, Tx, Rx = DC.gen_DCIPsurvey(locs, mesh, stype, param[0], param[1], param[2])
# [Tx, Rx] = DC.gen_DCIPsurvey(locs, mesh, surveyType, param[0], param[1], param[2])
survey, Tx, Rx = DC.gen_DCIPsurvey(locs, mesh, surveyType, param[0], param[1], param[2])
# Define some global geometry
dl_len = np.sqrt( np.sum((locs[0,:] - locs[1,:])**2) )
dl_x = ( Tx[-1][0,1] - Tx[0][0,0] ) / dl_len
dl_y = ( Tx[-1][1,1] - Tx[0][1,0] ) / dl_len
azm = np.arctan(dl_y/dl_x)
#azm = np.arctan(dl_y/dl_x)
#Set boundary conditions
mesh.setCellGradBC('neumann')
# Define the differential operators needed for the DC problem
# Define the linear system needed for the DC problem. We assume an infitite
# line source for simplicity.
Div = mesh.faceDiv
Grad = mesh.cellGrad
Msig = Utils.sdiag(1./(mesh.aveF2CC.T*(1./model)))
@@ -114,8 +118,8 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
rxloc_N = np.asarray(Rx[ii][:,3:])
# For usual cases "dpdp" or "gradient"
if stype == 'pdp':
# For usual cases 'dipole-dipole' or "gradient"
if surveyType == 'pole-dipole':
# Create an "inifinity" pole
tx = np.squeeze(Tx[ii][:,0:1])
tinf = tx + np.array([dl_x,dl_y,0])*dl_len*2
@@ -145,16 +149,23 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
print 'Forward completed'
# Let's just convert the 3D format into 2D (distance along line) and plot
# [Tx2d, Rx2d] = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc))
survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc))
survey2D = DC.convertObs_DC3D_to_2D(survey, np.ones(survey.nSrc) , 'Xloc')
survey2D.dobs =np.hstack(data)
# Here is an example for the first tx-rx array
if plotIt:
import matplotlib.pyplot as plt
fig = plt.figure()
fig = plt.figure(figsize=(7,7))
ax = plt.subplot(2,1,1, aspect='equal')
mesh.plotSlice(np.log10(model), ax =ax, normal = 'Y', ind = indy,grid=True)
ax.set_title('E-W section at '+str(mesh.vectorCCy[indy])+' m')
# Plot the location of the spheres for reference
circle1=plt.Circle((loc[0,0], loc[2,0]), radi[0], color='w', fill=False, lw=3)
circle2=plt.Circle((loc[0,1], loc[2,1]), radi[1], color='k', fill=False, lw=3)
ax.add_artist(circle1)
ax.add_artist(circle2)
dat = mesh.plotSlice(np.log10(model), ax = ax, normal = 'Y',
ind = indy,grid=True, clim = np.log10([sig.min(),sig.max()]))
ax.set_title('3-D model')
plt.gca().set_aspect('equal', adjustable='box')
plt.scatter(Tx[0][0,:],Tx[0][2,:],s=40,c='g', marker='v')
@@ -163,22 +174,32 @@ def run(loc=None, sig=None, radi=None, param=None, stype='dpdp', plotIt=True):
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
ax = plt.subplot(2,1,2, aspect='equal')
pos = ax.get_position()
ax.set_position([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height])
pos = ax.get_position()
cbarax = fig.add_axes([pos.x0 , pos.y0 + 0.025 , pos.width, pos.height * 0.04]) ## the parameters are the specified position you set
cb = fig.colorbar(dat[0],cax=cbarax, orientation="horizontal",
ax = ax, ticks=np.linspace(np.log10(sig.min()),
np.log10(sig.max()), 3), format="$10^{%.1f}$")
cb.set_label("Conductivity (S/m)",size=12)
cb.ax.tick_params(labelsize=12)
# Second plot for the predicted apparent resistivity data
ax2 = plt.subplot(2,1,2, aspect='equal')
# Plot the location of the spheres for reference
circle1=plt.Circle((loc[0,0]-Tx[0][0,0],loc[2,0]),radi[0],color='w',fill=False, lw=3)
circle2=plt.Circle((loc[0,1]-Tx[0][0,0],loc[2,1]),radi[1],color='k',fill=False, lw=3)
ax.add_artist(circle1)
ax.add_artist(circle2)
circle1=plt.Circle((loc[0,0], loc[2,0]), radi[0], color='w', fill=False, lw=3)
circle2=plt.Circle((loc[0,1], loc[2,1]), radi[1], color='k', fill=False, lw=3)
ax2.add_artist(circle1)
ax2.add_artist(circle2)
# Add the speudo section
DC.plot_pseudoSection(survey2D,ax,stype)
# plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v')
dat = DC.plot_pseudoSection(survey2D, ax2, surveyType=surveyType, unitType=unitType) # plt.scatter(Tx2d[0][:],Tx[0][2,:],s=40,c='g', marker='v')
# plt.scatter(Rx2d[0][:],Rx[0][:,2::3],s=40,c='y')
# plt.plot(np.r_[Tx2d[0][0],Rx2d[-1][-1,-1]],np.ones(2)*mesh.vectorNz[-1], color='k')
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
ax2.set_title('Apparent Conductivity data')
plt.ylim([-zlim,mesh.vectorNz[-1]+dx])
plt.show()
return fig, ax
+4 -5
View File
@@ -42,17 +42,16 @@ def run(plotIt=True):
ax.grid(color='k', alpha=0.5, linestyle='dashed', linewidth=0.5)
rxOffset=10.
bzi = EM.FDEM.Rx(np.array([[rxOffset, 0., 1e-3]]), 'bzi')
rxOffset=10.
bzi = EM.FDEM.Rx.Point_b(np.array([[rxOffset, 0., 1e-3]]), orientation='z', component='imag')
freqs = np.logspace(1,3,10)
srcLoc = np.array([0., 0., 10.])
srcList = []
[srcList.append(EM.FDEM.Src.MagDipole([bzi],freq, srcLoc,orientation='Z')) for freq in freqs]
srcList = [EM.FDEM.Src.MagDipole([bzi],freq, srcLoc,orientation='Z') for freq in freqs]
survey = EM.FDEM.Survey(srcList)
prb = EM.FDEM.Problem_b(mesh, mapping=mapping)
prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping)
try:
from pymatsolver import MumpsSolver
@@ -0,0 +1,275 @@
from SimPEG import *
from SimPEG.EM import FDEM, Analytics, mu_0
import time
try:
from pymatsolver import MumpsSolver
solver = MumpsSolver
except Exception:
solver = SolverLU
pass
def run(plotIt=True):
"""
EM: Schenkel and Morrison Casing Model
======================================
Here we create and run a FDEM forward simulation to calculate the vertical
current inside a steel-cased. The model is based on the Schenkel and
Morrison Casing Model, and the results are used in a 2016 SEG abstract by
Yang et al.
- Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686.
The model consists of:
- Air: Conductivity 1e-8 S/m, above z = 0
- Background: conductivity 1e-2 S/m, below z = 0
- Casing: conductivity 1e6 S/m
- 300m long
- radius of 0.1m
- thickness of 6e-3m
Inside the casing, we take the same conductivity as the background.
We are using an EM code to simulate DC, so we use frequency low enough
that the skin depth inside the casing is longer than the casing length (f
= 1e-6 Hz). The plot produced is of the current inside the casing.
These results are shown in the SEG abstract by Yang et al., 2016: 3D DC
resistivity modeling of steel casing for reservoir monitoring using
equivalent resistor network. The solver used to produce these results and
achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_
.. _pymatsolver: https://github.com/rowanc1/pymatsolver
This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1
If you would use this example for a code comparison, or build upon it, a
citation would be much appreciated!
"""
if plotIt:
import matplotlib.pylab as plt
# ------------------ MODEL ------------------
sigmaair = 1e-8 # air
sigmaback = 1e-2 # background
sigmacasing = 1e6 # casing
sigmainside = sigmaback # inside the casing
casing_t = 0.006 # 1cm thickness
casing_l = 300 # length of the casing
casing_r = 0.1
casing_a = casing_r - casing_t/2. # inner radius
casing_b = casing_r + casing_t/2. # outer radius
casing_z = np.r_[-casing_l,0.]
# ------------------ SURVEY PARAMETERS ------------------
freqs = np.r_[1e-6] #[1e-1, 1, 5] # frequencies
dsz = -300 # down-hole z source location
src_loc = np.r_[0.,0.,dsz]
inf_loc = np.r_[0.,0.,1e4]
print 'Skin Depth: ', [(500./np.sqrt(sigmaback*_)) for _ in freqs]
# ------------------ MESH ------------------
# fine cells near well bore
csx1, csx2 = 2e-3, 60.
pfx1, pfx2 = 1.3, 1.3
ncx1 = np.ceil(casing_b/csx1+2)
# pad nicely to second cell size
npadx1 = np.floor(np.log(csx2/csx1) / np.log(pfx1))
hx1a,hx1b = Utils.meshTensor([(csx1,ncx1)]),Utils.meshTensor([(csx1,npadx1,pfx1)])
dx1 = sum(hx1a)+sum(hx1b)
dx1 = np.floor(dx1/csx2)
hx1b *= (dx1*csx2 - sum(hx1a))/sum(hx1b)
# second chunk of mesh
dx2 = 300. # uniform mesh out to here
ncx2 = np.ceil((dx2 - dx1)/csx2)
npadx2 = 45
hx2a, hx2b = Utils.meshTensor([(csx2,ncx2)]), Utils.meshTensor([(csx2,npadx2,pfx2)])
hx = np.hstack([hx1a,hx1b,hx2a,hx2b])
# z-direction
csz = 0.05
nza = 10
ncz, npadzu, npadzd = np.int(np.ceil(np.diff(casing_z)[0]/csz))+10, 68, 68 # cell size, number of core cells, number of padding cells in the x- direction
hz = Utils.meshTensor([(csz,npadzd,-1.3), (csz,ncz), (csz,npadzu,1.3)]) # vector of cell widths in the z-direction
# Mesh
mesh = Mesh.CylMesh([hx,1.,hz], [0.,0.,-np.sum(hz[:npadzu+ncz-nza])])
print 'Mesh Extent xmax: %f,: zmin: %f, zmax: %f'%(mesh.vectorCCx.max(), mesh.vectorCCz.min(), mesh.vectorCCz.max())
print 'Number of cells', mesh.nC
if plotIt is True:
fig, ax = plt.subplots(1, 1, figsize=(6, 4))
ax.set_title('Simulation Mesh')
mesh.plotGrid(ax=ax)
plt.show()
# Put the model on the mesh
sigWholespace = sigmaback*np.ones((mesh.nC))
sigBack = sigWholespace.copy()
sigBack[mesh.gridCC[:,2] > 0.] = sigmaair
sigCasing = sigBack.copy()
iCasingZ = (mesh.gridCC[:,2] <= casing_z[1]) & (mesh.gridCC[:,2] >= casing_z[0])
iCasingX = (mesh.gridCC[:,0] >= casing_a) & (mesh.gridCC[:,0] <= casing_b)
iCasing = iCasingX & iCasingZ
sigCasing[iCasing] = sigmacasing
if plotIt is True:
# plotting parameters
xlim = np.r_[0., 0.2]
zlim = np.r_[-350., 10.]
clim_sig = np.r_[-8,6]
# plot models
fig, ax = plt.subplots(1,1,figsize=(4,4))
f = plt.colorbar(mesh.plotImage(np.log10(sigCasing),ax=ax)[0], ax=ax)
ax.grid(which='both')
ax.set_title('Log_10 (Sigma)')
ax.set_xlim(xlim)
ax.set_ylim(zlim)
f.set_clim(clim_sig)
plt.show()
# -------------- Sources --------------------
# Define Custom Current Sources
# surface source
sg_x = np.zeros(mesh.vnF[0],dtype=complex)
sg_y = np.zeros(mesh.vnF[1],dtype=complex)
sg_z = np.zeros(mesh.vnF[2],dtype=complex)
nza = 2 # put the wire two cells above the surface
ncin = 2
# vertically directed wire
sgv_indx = (mesh.gridFz[:,0] > casing_a) & (mesh.gridFz[:,0] < casing_a + csx1) # hook it up to casing at the surface
sgv_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] >= -csz*2)
sgv_ind = sgv_indx & sgv_indz
sg_z[sgv_ind] = -1.
# horizontally directed wire
sgh_indx = (mesh.gridFx[:,0] > casing_a) & (mesh.gridFx[:,0] <= inf_loc[2])
sgh_indz = (mesh.gridFx[:,2] > csz*(nza-0.5)) & (mesh.gridFx[:,2] < csz*(nza+0.5))
sgh_ind = sgh_indx & sgh_indz
sg_x[sgh_ind] = -1.
sgv2_indx = (mesh.gridFz[:,0] >= mesh.gridFx[sgh_ind,0].max()) & (mesh.gridFz[:,0] <= inf_loc[2]*1.2) # hook it up to casing at the surface
sgv2_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] >= -csz*2)
sgv2_ind = sgv2_indx & sgv2_indz
sg_z[sgv2_ind] = 1.
# assemble the source
sg = np.hstack([sg_x,sg_y,sg_z])
sg_p = [FDEM.Src.RawVec_e([],_,sg/mesh.area) for _ in freqs]
# downhole source
dg_x = np.zeros(mesh.vnF[0],dtype=complex)
dg_y = np.zeros(mesh.vnF[1],dtype=complex)
dg_z = np.zeros(mesh.vnF[2],dtype=complex)
# vertically directed wire
dgv_indx = (mesh.gridFz[:,0] < csx1) # go through the center of the well
dgv_indz = (mesh.gridFz[:,2] <= +csz*nza) & (mesh.gridFz[:,2] > dsz + csz/2.)
dgv_ind = dgv_indx & dgv_indz
dg_z[dgv_ind] = -1.
# couple to the casing downhole
dgh_indx = mesh.gridFx[:,0] < casing_a + csx1
dgh_indz = (mesh.gridFx[:,2] < dsz + csz) & (mesh.gridFx[:,2] >= dsz)
dgh_ind = dgh_indx & dgh_indz
dg_x[dgh_ind] = 1.
# horizontal part at surface
dgh2_indx = mesh.gridFx[:,0] <= inf_loc[2]*1.2
dgh2_indz = sgh_indz.copy()
dgh2_ind = dgh2_indx & dgh2_indz
dg_x[dgh2_ind] = -1.
# vertical part at surface
dgv2_ind = sgv2_ind.copy()
dg_z[dgv2_ind] = 1.
# assemble the source
dg = np.hstack([dg_x,dg_y,dg_z])
dg_p = [FDEM.Src.RawVec_e([],_,dg/mesh.area) for _ in freqs]
# ------------ Problem and Survey ---------------
survey = FDEM.Survey(sg_p + dg_p)
mapping = [('sigma', Maps.IdentityMap(mesh))]
problem = FDEM.Problem3D_h(mesh, mapping=mapping)
problem.pair(survey)
# ------------- Solve ---------------------------
t0 = time.time()
fieldsCasing = problem.fields(sigCasing)
print 'Time to solve 2 sources', time.time() - t0
# Plot current
# current density
jn0 = fieldsCasing[dg_p,'j']
jn1 = fieldsCasing[sg_p,'j']
# current
in0 = [mesh.area*fieldsCasing[dg_p,'j'][:,i] for i in range(len(freqs))]
in1 = [mesh.area*fieldsCasing[sg_p,'j'][:,i] for i in range(len(freqs))]
in0 = np.vstack(in0).T
in1 = np.vstack(in1).T
# integrate to get z-current inside casing
inds_inx = (mesh.gridFz[:,0] >= casing_a) & (mesh.gridFz[:,0] <= casing_b)
inds_inz = (mesh.gridFz[:,2] >= dsz ) & (mesh.gridFz[:,2] <= 0)
inds_fz = inds_inx & inds_inz
indsx = [False]*mesh.nFx
inds = list(indsx) + list(inds_fz)
in0_in = in0[np.r_[inds]]
in1_in = in1[np.r_[inds]]
z_in = mesh.gridFz[inds_fz,2]
in0_in = in0_in.reshape([in0_in.shape[0]/3,3])
in1_in = in1_in.reshape([in1_in.shape[0]/3,3])
z_in = z_in.reshape([z_in.shape[0]/3,3])
I0 = in0_in.sum(1).real
I1 = in1_in.sum(1).real
z_in = z_in[:,0]
if plotIt is True:
fig, ax = plt.subplots(1,2,figsize=(12,4))
ax[0].plot(z_in,np.absolute(I0), z_in,np.absolute(I1))
ax[0].legend(['top casing', 'bottom casing'],loc='best')
ax[0].set_title('Magnitude of Vertical Current in Casing')
ax[1].semilogy(z_in,np.absolute(I0), z_in,np.absolute(I1))
ax[1].legend(['top casing', 'bottom casing'],loc='best')
ax[1].set_title('Magnitude of Vertical Current in Casing')
ax[1].set_ylim([1e-2, 1.])
plt.show()
if __name__ == '__main__':
run()
+124
View File
@@ -0,0 +1,124 @@
from SimPEG import *
def run(N=100, plotIt=True):
"""
Inversion: Linear Problem
=========================
Here we go over the basics of creating a linear problem and inversion.
"""
np.random.seed(1)
std_noise = 1e-2
mesh = Mesh.TensorMesh([N])
m0 = np.ones(mesh.nC) * 1e-4
mref = np.zeros(mesh.nC)
nk = 10
jk = np.linspace(1.,nk,nk)
p = -2.
q = 1.
g = lambda k: np.exp(p*jk[k]*mesh.vectorCCx)*np.cos(np.pi*q*jk[k]*mesh.vectorCCx)
G = np.empty((nk, mesh.nC))
for i in range(nk):
G[i,:] = g(i)
mtrue = np.zeros(mesh.nC)
mtrue[mesh.vectorCCx > 0.3] = 1.
mtrue[mesh.vectorCCx > 0.45] = -0.5
mtrue[mesh.vectorCCx > 0.6] = 0
prob = Problem.LinearProblem(mesh, G)
survey = Survey.LinearSurvey()
survey.pair(prob)
survey.dobs = prob.fields(mtrue) + std_noise * np.random.randn(nk)
#survey.makeSyntheticData(mtrue, std=std_noise)
wd = np.ones(nk) * std_noise
#print survey.std[0]
#M = prob.mesh
# Distance weighting
wr = np.sum(prob.G**2.,axis=0)**0.5
wr = ( wr/np.max(wr) )
# reg = Regularization.Simple(mesh)
# reg.mref = mref
# reg.cell_weights = wr
#
dmis = DataMisfit.l2_DataMisfit(survey)
dmis.Wd = 1./wd
#
# opt = Optimization.ProjectedGNCG(maxIter=20,lower=-2.,upper=2., maxIterCG= 10, tolCG = 1e-4)
# invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
# invProb.curModel = m0
#
# beta = Directives.BetaSchedule(coolingFactor=2, coolingRate=1)
# target = Directives.TargetMisfit()
#
betaest = Directives.BetaEstimate_ByEig()
# inv = Inversion.BaseInversion(invProb, directiveList=[beta, betaest, target])
#
#
# mrec = inv.run(m0)
# ml2 = mrec
# print "Final misfit:" + str(invProb.dmisfit.eval(mrec))
#
# # Switch regularization to sparse
# phim = invProb.phi_m_last
# phid = invProb.phi_d
reg = Regularization.Sparse(mesh)
reg.mref = mref
reg.cell_weights = wr
reg.mref = np.zeros(mesh.nC)
eps_p = 5e-2
eps_q = 5e-2
norms = [0., 0., 2., 2.]
opt = Optimization.ProjectedGNCG(maxIter=100 ,lower=-2.,upper=2., maxIterLS = 20, maxIterCG= 10, tolCG = 1e-3)
invProb = InvProblem.BaseInvProblem(dmis, reg, opt)
update_Jacobi = Directives.Update_lin_PreCond()
IRLS = Directives.Update_IRLS( norms=norms, eps_p=eps_p, eps_q=eps_q)
inv = Inversion.BaseInversion(invProb, directiveList=[IRLS,betaest,update_Jacobi])
# Run inversion
mrec = inv.run(m0)
print "Final misfit:" + str(invProb.dmisfit.eval(mrec))
if plotIt:
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1,2,figsize=(12*1.2,4*1.2))
for i in range(prob.G.shape[0]):
axes[0].plot(prob.G[i,:])
axes[0].set_title('Columns of matrix G')
axes[1].plot(mesh.vectorCCx, mtrue, 'b-')
axes[1].plot(mesh.vectorCCx, reg.l2model, 'r-')
#axes[1].legend(('True Model', 'Recovered Model'))
axes[1].set_ylim(-1.0,1.25)
axes[1].plot(mesh.vectorCCx, mrec, 'k-',lw = 2)
axes[1].legend(('True Model', 'Smooth l2-l2',
'Sparse lp:' + str(reg.norms[0]) + ', lqx:' + str(reg.norms[1]) ), fontsize = 12)
plt.show()
return prob, survey, mesh, mrec
if __name__ == '__main__':
run()
+31 -25
View File
@@ -1,9 +1,11 @@
import SimPEG as simpeg
import numpy as np
import SimPEG.MT as MT
from SimPEG import NSEM
from scipy.constants import mu_0
import matplotlib.pyplot as plt
np.random.seed(1983)
def run(plotIt=True):
"""
MT: 1D: Inversion
@@ -17,13 +19,13 @@ def run(plotIt=True):
## Setup the forward modeling
# Setting up 1D mesh and conductivity models to forward model data.
# Frequency
nFreq = 31
freqs = np.logspace(3,-3,nFreq)
nFreq = 26
freqs = np.logspace(2,-3,nFreq)
# Set mesh parameters
ct = 20
air = simpeg.Utils.meshTensor([(ct,16,1.4)])
ct = 10
air = simpeg.Utils.meshTensor([(ct,25,1.4)])
core = np.concatenate( ( np.kron(simpeg.Utils.meshTensor([(ct,10,-1.3)]),np.ones((5,))) , simpeg.Utils.meshTensor([(ct,5)]) ) )
bot = simpeg.Utils.meshTensor([(core[0],10,-1.4)])
bot = simpeg.Utils.meshTensor([(core[0],25,-1.4)])
x0 = -np.array([np.sum(np.concatenate((core,bot)))])
# Make the model
m1d = simpeg.Mesh.TensorMesh([np.concatenate((bot,core,air))], x0=x0)
@@ -33,7 +35,7 @@ def run(plotIt=True):
layer1 = (m1d.vectorCCx<-500.) & (m1d.vectorCCx>=-800.)
layer2 = (m1d.vectorCCx<-3500.) & (m1d.vectorCCx>=-5000.)
# Set the conductivity values
sig_half = 2e-3
sig_half = 1e-2
sig_air = 1e-8
sig_layer1 = .2
sig_layer2 = .2
@@ -50,38 +52,38 @@ def run(plotIt=True):
m_0 = np.log(sigma_0[active])
# Set the mapping
actMap = simpeg.Maps.ActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx)
actMap = simpeg.Maps.InjectActiveCells(m1d, active, np.log(1e-8), nC=m1d.nCx)
mappingExpAct = simpeg.Maps.ExpMap(m1d) * actMap
## Setup the layout of the survey, set the sources and the connected receivers
# Receivers
rxList = []
for rxType in ['z1dr','z1di']:
rxList.append(MT.Rx(simpeg.mkvc(np.array([0.0]),2).T,rxType))
rxList.append(NSEM.Rx(simpeg.mkvc(np.array([-0.5]),2).T,rxType))
# Source list
srcList =[]
for freq in freqs:
srcList.append(MT.SrcMT.polxy_1Dprimary(rxList,freq))
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,freq))
# Make the survey
survey = MT.Survey(srcList)
survey = NSEM.Survey(srcList)
survey.mtrue = m_true
## Set the problem
problem = MT.Problem1D.eForm_psField(m1d,sigmaPrimary=sigma_0,mapping=mappingExpAct)
problem = NSEM.Problem1D_ePrimSec(m1d,sigmaPrimary=sigma_0,mapping=mappingExpAct)
problem.pair(survey)
## Forward model data
# Project the data
survey.dtrue = survey.dpred(m_true)
survey.dobs = survey.dtrue + 0.025*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
survey.dobs = survey.dtrue + 0.01*abs(survey.dtrue)*np.random.randn(*survey.dtrue.shape)
if plotIt:
fig = MT.Utils.dataUtils.plotMT1DModelData(problem)
fig = NSEM.Utils.dataUtils.plotMT1DModelData(problem,[])
fig.suptitle('Target - smooth true')
# Assign uncertainties
std = 0.05 # 5% std
std = 0.025 # 5% std
survey.std = np.abs(survey.dobs*std)
# Assign the data weight
Wd = 1./survey.std
@@ -90,30 +92,33 @@ def run(plotIt=True):
# Define a counter
C = simpeg.Utils.Counter()
# Set the optimization
opt = simpeg.Optimization.InexactGaussNewton(maxIter = 30)
opt = simpeg.Optimization.ProjectedGNCG(maxIter = 25)
opt.counter = C
opt.LSshorten = 0.5
opt.lower = np.log(1e-4)
opt.upper = np.log(5)
opt.LSshorten = 0.1
opt.remember('xc')
# Data misfit
dmis = simpeg.DataMisfit.l2_DataMisfit(survey)
dmis.Wd = Wd
# Regularization - with a regularization mesh
regMesh = simpeg.Mesh.TensorMesh([m1d.hx[problem.mapping.sigmaMap.maps[-1].indActive]],m1d.x0)
regMesh = simpeg.Mesh.TensorMesh([m1d.hx[active]],m1d.x0)
reg = simpeg.Regularization.Tikhonov(regMesh)
reg.smoothModel = True
reg.alpha_s = 1e-7
reg.mrefInSmooth = True
reg.alpha_s = 1e-1
reg.alpha_x = 1.
# Inversion problem
invProb = simpeg.InvProblem.BaseInvProblem(dmis, reg, opt)
invProb.counter = C
# Beta cooling
beta = simpeg.Directives.BetaSchedule()
beta.coolingRate = 4
betaest = simpeg.Directives.BetaEstimate_ByEig(beta0_ratio=0.75)
beta.coolingRate = 4.
beta.coolingFactor = 4.
betaest = simpeg.Directives.BetaEstimate_ByEig(beta0_ratio=1.)
betaest.beta0 = 1.
targmis = simpeg.Directives.TargetMisfit()
targmis.target = survey.nD
saveModel = simpeg.Directives.SaveModelEveryIteration()
saveModel.fileName = 'Inversion_TargMisEqnD_smoothTrue'
# Create an inversion object
inv = simpeg.Inversion.BaseInversion(invProb, directiveList=[beta,betaest,targmis])
@@ -121,8 +126,9 @@ def run(plotIt=True):
mopt = inv.run(m_0)
if plotIt:
fig = MT.Utils.dataUtils.plotMT1DModelData(problem,[mopt])
fig = NSEM.Utils.dataUtils.plotMT1DModelData(problem,[mopt])
fig.suptitle('Target - smooth true')
fig.axes[0].set_ylim([-10000,500])
plt.show()
if __name__ == '__main__':
@@ -0,0 +1,428 @@
from scipy.constants import epsilon_0, mu_0
import matplotlib.pyplot as plt
import numpy as np
from ipywidgets import *
from SimPEG.EM.Utils import k, omega
"""
MT1D: n layered earth problem
*****************************
Author: Thibaut Astic
Contact: thast@eos.ubc.ca
Date: January 2016
This code compute the analytic response of a n-layered Earth to a plane wave (Magneto-Tellurics).
We start by looking at Maxwell's equations in the electric
field \\\(\\\mathbf{E}\\) and the magnetic flux
\\\(\\\mathbf{H}\\) to write the wave equations
\\(\\ \nabla ^2 \mathbf{E_x} + k^2 \mathbf{E_x} = 0 \\) &
\\(\\ \nabla ^2 \mathbf{H_y} + k^2 \mathbf{H_y} = 0 \\)
Then solving the equations in each layer "j" between z_{j-1} and z_j in the form of
\\(\\ E_{x,j} (z) = U_j e^{i k (z-z_{j-1})} + D_j e^{-i k (z-z_{j-1})} \\)
\\(\\ H_{y,j} (z) = \frac{1}{Z_j} (D_j e^{-i k (z-z_{j-1})} - U_j e^{i k (z-z_{j-1})}) \\)
With U and D the Up and Down components of the E-field.
The iteration from one layer to another is ensure by:
\\(\\ \left(\begin{matrix} E_{x,j} \\ H_{y,j} \end{matrix} \right) =
P_j T_j P^{-1}_J \left(\begin{matrix} E_{x,j+1} \\ H_{y,j+1} \end{matrix} \right) \\)
And the Boundary Condition is set for the E-field in the last layer, with no Up component (=0)
and only a down component (=1 then normalized by the highest amplitude to ensure numeric stability)
The layer 0 is assumed to be the air layer.
"""
#Define a frquency range for a survey
frange = lambda minfreq, maxfreq, step: np.logspace(minfreq,maxfreq,num = step, base = 10.)
#Functions to create random physical Perties for a n-layered earth
thick = lambda minthick, maxthick, nlayer: np.append(np.array([1.2*10.**5]),
np.ndarray.round(minthick + (maxthick-minthick)* np.random.rand(nlayer-1,1)
,decimals =1))
sig = lambda minsig, maxsig, nlayer: np.append(np.array([0.]),
np.ndarray.round(10.**minsig + (10.**maxsig-10.**minsig)* np.random.rand(nlayer,1)
,decimals=3))
mu = lambda minmu, maxmu, nlayer: np.append(np.array([1.]),
np.ndarray.round(minmu + (maxmu-minmu)* np.random.rand(nlayer,1)
,decimals=1))
eps = lambda mineps, maxeps, nlayer: np.append(np.array([1.]),
np.ndarray.round(mineps + (maxeps-mineps)* np.random.rand(nlayer,1)
,decimals=1))
#Evaluate Impedance Z of a layer
ImpZ = lambda f, mu, k: omega(f)*mu*mu_0/k
#Complex Cole-Cole Conductivity - EM utils
PCC= lambda siginf,m,t,c,f: siginf*(1.-(m/(1.+(1j*omega(f)*t)**c)))
#Converted thickness array into top of layer array
top = lambda thick: np.cumsum(thick)
#Propagation Matrix and theirs inverses
#matrix T for transition of Up and Down components accross a layer
T = lambda h,k: np.matrix([[np.exp(1j*k*h),0.],[0.,np.exp(-1j*k*h)]],dtype='complex_')
Tinv = lambda h,k: np.matrix([[np.exp(-1j*k*h),0.],[0.,np.exp(1j*k*h)]],dtype='complex_')
#transition of Up and Down components accross a layer
UD_Z = lambda UD,z,zj,k : T((z-zj),k)*UD
#matrix P relating Up and Down components with E and H fields
P = lambda z: np.matrix([[1.,1,],[-1./z,1./z]],dtype='complex_')
Pinv = lambda z: np.matrix([[1.,-z],[1.,z]],dtype='complex_')/2.
#Time Variation of E and H
E_ZT = lambda U,D,f,t : np.exp(1j*omega(f)*t)*(U+D)
H_ZT = lambda U,D,Z,f,t : (1./Z)*np.exp(1j*omega(f)*t)*(D-U)
#Plot the configuration of the problem
def PlotConfiguration(thick,sig,eps,mu,ax,widthg,z):
topn = top(thick)
widthn = np.arange(-widthg,widthg+widthg/10.,widthg/10.)
ax.set_ylim([z.min(),z.max()])
ax.set_xlim([-widthg,widthg])
ax.set_ylabel("Depth (m)", fontsize=16.)
ax.yaxis.tick_right()
ax.yaxis.set_label_position("right")
#define filling for the different layers
hatches=['/' , '+', 'x', '|' , '\\', '-' , 'o' , 'O' , '.' , '*' ]
#Write the physical properties of air
ax.annotate(("Air, $\sigma$ =%1.0f mS/m")%(sig[0]*10**(3)),
xy=(-widthg/2., -np.abs(z.max())/2.), xycoords='data',
xytext=(-widthg/2., -np.abs(z.max())/2.), textcoords='data',
fontsize=14.)
ax.annotate(("$\epsilon_r$= %1i")%(eps[0]),
xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data',
xytext=(-widthg/2., -np.abs(z.max())/3.), textcoords='data',
fontsize=14.)
ax.annotate(("$\mu_r$= %1i")%(mu[0]),
xy=(-widthg/2., -np.abs(z.max())/3.), xycoords='data',
xytext=(0, -np.abs(z.max())/3.), textcoords='data',
fontsize=14.)
#Write the physical properties of the differents layers up to the (n-1)-th and fill it with pattern
for i in range(1,len(topn)-1,1):
if topn[i] == topn[i+1]:
pass
else:
ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[i]*10**(3)),
xy=(0., (2.*topn[i]+topn[i+1])/3), xycoords='data',
xytext=(0., (2.*topn[i]+topn[i+1])/3), textcoords='data',
fontsize=14.)
ax.annotate(("$\epsilon_r$= %1i")%(eps[i]),
xy=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), xycoords='data',
xytext=(-widthg/1.1, (2.*topn[i]+topn[i+1])/3), textcoords='data',
fontsize=14.)
ax.annotate(("$\mu_r$= %1.2f")%(mu[i]),
xy=(-widthg/2., (2.*topn[i]+topn[i+1])/3), xycoords='data',
xytext=(-widthg/2., (2.*topn[i]+topn[i+1])/3), textcoords='data',
fontsize=14.)
ax.plot(widthn,topn[i]*np.ones_like(widthn),color='black')
ax.fill_between(widthn,topn[i],topn[i+1],alpha=0.3,color="none",edgecolor='black', hatch=hatches[(i-1)%10])
#Write the physical properties of the n-th layer and fill it with pattern
ax.plot(widthn,topn[-1]*np.ones_like(widthn),color='black')
ax.fill_between(widthn,topn[-1],z.max(),alpha=0.3,color="none",edgecolor='black', hatch=hatches[(len(topn)-2)%10])
ax.annotate(("$\sigma$ =%3.3f mS/m")%(sig[-1]*10**(3)),
xy=(0., (2.*topn[-1]+z.max())/3), xycoords='data',
xytext=(0., (2.*topn[-1]+z.max())/3), textcoords='data',
fontsize=14.)
ax.annotate(("$\epsilon_r$= %1i")%(eps[-1]),
xy=(-widthg/1.1, (2.*topn[-1]+z.max())/3), xycoords='data',
xytext=(-widthg/1.1, (2.*topn[-1]+z.max())/3), textcoords='data',
fontsize=14.)
ax.annotate(("$\mu_r$= %1.2f")%(mu[-1]),
xy=(-widthg/2., (2.*topn[-1]+z.max())/3), xycoords='data',
xytext=(-widthg/2., (2.*topn[-1]+z.max())/3), textcoords='data',
fontsize=14.)
#plot Trees!
ax.annotate("",
xy=(widthg/2., -1.*z.max()/5.), xycoords='data',
xytext=(widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
)
ax.annotate("",
xy=(widthg/2., -3./4.*z.max()/5.), xycoords='data',
xytext=(widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
)
ax.annotate("",
xy=(widthg/2., -1./2.*z.max()/5.), xycoords='data',
xytext=(widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.2*widthg/2., -1.*z.max()/5.), xycoords='data',
xytext=(1.2*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.2*widthg/2., -3./4.*z.max()/5.), xycoords='data',
xytext=(1.2*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.2*widthg/2., -1./2.*z.max()/5.), xycoords='data',
xytext=(1.2*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.5*widthg/2., -1.*z.max()/5.), xycoords='data',
xytext=(1.5*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.2,head_length=1.2',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.5*widthg/2., -3./4.*z.max()/5.), xycoords='data',
xytext=(1.5*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.4,head_length=1.4',color='green',linewidth=2.)
)
ax.annotate("",
xy=(1.5*widthg/2., -1./2.*z.max()/5.), xycoords='data',
xytext=(1.5*widthg/2., 0.), textcoords='data',
arrowprops=dict(arrowstyle='->, head_width=1.6,head_length=1.6',color='green',linewidth=2.)
)
ax.invert_yaxis()
return ax
#Propagate Up and Down component for a certain frequency & evaluate E and H field
def Propagate(f,H,sig,chg,taux,c,mu,eps,n):
sigcm = np.zeros_like(sig,dtype='complex_')
for j in range(1,len(sig)):
sigcm[j]=PCC(sig[j],chg[j],taux[j],c[j],f)
K = k(f, sigcm, mu, eps)
Z = ImpZ(f,mu,K)
EH = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_')
UD = np.matrix(np.zeros((2,n+1),dtype = 'complex_'),dtype = 'complex_')
UD[1,-1] = 1.
for i in range(-2,-(n+2),-1):
UD[:,i] = Tinv(H[i+1],K[i])*Pinv(Z[i])*P(Z[i+1])*UD[:,i+1]
UD = UD/((np.abs(UD[0,:]+UD[1,:])).max())
for j in range(0,n+1):
EH[:,j] = np.matrix([[1.,1,],[-1./Z[j],1./Z[j]]])*UD[:,j]
return UD, EH, Z ,K
#Evaluate the apparent resistivity and phase for a frequency range
def appres(F,H,sig,chg,taux,c,mu,eps,n):
Res = np.zeros_like(F)
Phase = np.zeros_like(F)
App_ImpZ= np.zeros_like(F,dtype='complex_')
for i in range(0,len(F)):
UD,EH,Z ,K = Propagate(F[i],H,sig,chg,taux,c,mu,eps,n)
App_ImpZ[i] = EH[0,1]/EH[1,1]
Res[i] = np.abs(App_ImpZ[i])**2./(mu_0*omega(F[i]))
Phase[i] = np.angle(App_ImpZ[i], deg = True)
return Res,Phase
#Evaluate Up, Down components, E and H field, for a frequency range,
#a discretized depth range and a time range (use to calculate envelope)
def calculateEHzt(F,H,sig,chg,taux,c,mu,eps,n,zsample,tsample):
topc = top(H)
layer = np.zeros(len(zsample),dtype=np.int)-1
Exzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
Hyzt = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
Uz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
Dz = np.matrix(np.zeros((len(zsample),len(tsample)),dtype = 'complex_'),dtype = 'complex_')
UDaux = np.matrix(np.zeros((2,len(zsample)),dtype = 'complex_'),dtype = 'complex_')
for i in range(0,n+1,1):
layer = layer+(zsample>=topc[i])*1
for j in range(0,len(F)):
UD,EH,Z ,K = Propagate(F[j],H,sig,chg,taux,c,mu,eps,n)
for p in range(0,len(zsample)):
UDaux[:,p] = UD_Z(UD[:,layer[p]],zsample[p],topc[layer[p]],K[layer[p]])
for q in range(0,len(tsample)):
Exzt[p,q] = Exzt[p,q] + E_ZT(UDaux[0,p],UDaux[1,p],F[j],tsample[q])/len(F)
Hyzt[p,q] = Hyzt[p,q] + H_ZT(UDaux[0,p],UDaux[1,p],Z[layer[p]],F[j],tsample[q])/len(F)
Uz[p,q] = Uz[p,q] + UDaux[0,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F)
Dz[p,q] = Dz[p,q] + UDaux[1,p]*np.exp(1j*omega(F[j])*tsample[q])/len(F)
return Exzt,Hyzt,Uz,Dz,UDaux,layer
#Function to Plot Apparent Resistivity and Phase
def PlotAppRes(F,H,sig,chg,taux,c,mu,eps,n,fenvelope,PlotEnvelope):
Res, Phase = appres(F,H,sig,chg,taux,c,mu,eps,n)
fig,ax = plt.subplots(1,2,figsize=(16,10))
ax[0].scatter(Res,F,color='black')
ax[0].set_xscale('Log')
ax[0].set_yscale('Log')
ax[0].set_xlim([10.**(np.log10(Res.min())-1.),10.**(np.log10(Res.max())+1.)])
ax[0].set_ylim([F.min(),F.max()])
ax[0].set_xlabel('Apparent Resistivity (Ohm*m)',fontsize=16.,color="black")
ax[0].set_ylabel('Frequency (Hz)',fontsize=16.)
ax[0].grid(which='major')
ax0 = ax[0].twiny()
ax0.set_xlim([0.,90.])
ax0.set_ylim([F.min(),F.max()])
ax0.scatter(Phase,F,color='purple')
ax0.set_xlabel('Phase (Degrees)',fontsize=16.,color="purple")
zc=np.arange(-(H[1:].max()+10)*n,(H[1:].max()+10)*n,10.)
ax[0].tick_params(labelsize=16)
ax[1].tick_params(labelsize=16)
ax0.tick_params(labelsize=16)
if PlotEnvelope:
widthn=np.logspace(np.log10(Res.min())-1., np.log10(Res.max())+1., num=100, endpoint=True, base=10.0)
fenvelope1n=np.ones(100)*fenvelope
ax[0].plot(widthn,fenvelope1n,linestyle='dashed',color='black')
tc=np.arange(0.,1./fenvelope,0.01/(fenvelope))
Exzt,Hyzt,Uz,Dz,UDaux,layer = calculateEHzt(np.array([fenvelope]),H,sig,chg,taux,c,mu,eps,n,zc,tc)
ax1=ax[1].twiny()
ax[1].tick_params(labelsize=16)
ax1.tick_params(labelsize=16)
ax[1].set_xlabel('Amplitude Electric Field E (V/m)',color='blue',fontsize=16)
ax1.set_xlabel('Amplitude Magnetic Field H (A/m)',color='red',fontsize=16)
ax[1].fill_betweenx(zc,np.squeeze(np.asarray(np.real(Exzt.min(axis=1)))),
np.squeeze(np.asarray(np.real(Exzt.max(axis=1)))),
color='blue', alpha=0.1)
ax1.fill_betweenx(zc,np.squeeze(np.asarray(np.real(Hyzt.min(axis=1)))),
np.squeeze(np.asarray(np.real(Hyzt.max(axis=1)))),
color='red', alpha=0.1)
ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],(1.5*np.abs(Exzt).max()),zc)
ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()])
ax1.set_xlim([-1.5*np.abs(Hyzt).max(),1.5*np.abs(Hyzt).max()])
else:
print 'No envelop (if True, might be slow)'
ax[1] = PlotConfiguration(H,sig,eps,mu,ax[1],1.,zc)
ax[1].get_xaxis().set_ticks([])
plt.show()
#Interactive MT for Notebook
def PlotAppRes3LayersInteract(h1,h2,sigl1,sigl2,sigl3,mul1,mul2,mul3,epsl1,epsl2,epsl3,PlotEnvelope,F_Envelope):
frangn=frange(-5,5,100.)
sig3= np.array([0.,0.001,0.1, 0.001])
thick3 = np.array([120000.,50.,50.])
eps3=np.array([1.,1.,1.,1])
mu3=np.array([1.,1.,1.,1])
chg3=np.array([0.,0.1,0.,0.2])
chg3_0=np.array([0.,0.1,0.,0.])
taux3=np.array([0.,0.1,0.,0.1])
c3=np.array([1.,1.,1.,1.])
sig3[1]=sigl1
sig3[1]=10.**sig3[1]
sig3[2]=sigl2
sig3[2]=10.**sig3[2]
sig3[3]=sigl3
sig3[3]=10.**sig3[3]
mu3[1]=mul1
mu3[2]=mul2
mu3[3]=mul3
eps3[1]=epsl1
eps3[2]=epsl2
eps3[3]=epsl3
thick3[1]=h1
thick3[2]=h2
PlotAppRes(frangn,thick3,sig3,chg3_0,taux3,c3,mu3,eps3,3,F_Envelope,PlotEnvelope)
def run(n=3,plotIt=True):
# something to make a plot
F = frange(-5.,5.,20)
H = thick(50.,100.,n)
sign = sig(-5.,0.,n)
mun = mu(1.,2.,n)
epsn = eps(1.,9.,n)
chg = np.zeros_like(sign)
taux = np.zeros_like(sign)
c = np.zeros_like(sign)
Res, Phase = appres(F,H,sign,chg,taux,c,mun,epsn,n)
if plotIt:
PlotAppRes(F, H, sign, chg, taux, c, mun, epsn, n, fenvelope=1000., PlotEnvelope=True)
return Res, Phase
if __name__ == '__main__':
run()
+6 -6
View File
@@ -2,7 +2,7 @@
# Import
import SimPEG as simpeg
from SimPEG import MT
from SimPEG import NSEM
import numpy as np
try:
from pymatsolver import MumpsSolver as Solver
@@ -37,16 +37,16 @@ def run(plotIt=True, nFreq=1):
for loc in rx_loc:
# NOTE: loc has to be a (1,3) np.ndarray otherwise errors accure
for rxType in ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi','tzxr','tzxi','tzyr','tzyi']:
rxList.append(MT.Rx(simpeg.mkvc(loc,2).T,rxType))
rxList.append(NSEM.Rx(simpeg.mkvc(loc,2).T,rxType))
# Source list
srcList =[]
for freq in np.logspace(3,-3,nFreq):
srcList.append(MT.SrcMT.polxy_1Dprimary(rxList,freq))
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,freq))
# Survey MT
survey = MT.Survey(srcList)
survey = NSEM.Survey(srcList)
## Setup the problem object
problem = MT.Problem3D.eForm_ps(M, sigmaPrimary=sigBG)
problem = NSEM.Problem3D_ePrimSec(M, sigmaPrimary=sigBG)
problem.pair(survey)
problem.Solver = Solver
@@ -55,7 +55,7 @@ def run(plotIt=True, nFreq=1):
dataVec = survey.eval(fields)
# Make the data
mtData = MT.Data(survey,dataVec)
mtData = NSEM.Data(survey,dataVec)
# Add plots
if plotIt:
pass
@@ -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()
+41
View File
@@ -0,0 +1,41 @@
from SimPEG import *
from SimPEG.Utils import surface2ind_topo
def run(plotIt=False, nx = 5, ny = 5):
"""
Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below
a topographic surface.
"""
mesh = Mesh.TensorMesh([nx,ny], x0='CC') # 2D mesh
xtopo = np.linspace(mesh.gridN[:,0].min(), mesh.gridN[:,0].max())
topo = 0.4*np.sin(xtopo*5) # define a topographic surface
Topo = np.hstack([Utils.mkvc(xtopo,2),Utils.mkvc(topo,2)]) #make it an array
indcc = surface2ind_topo(mesh, Topo,'CC')
if plotIt:
from matplotlib.pylab import plt
from scipy.interpolate import interp1d
fig, ax = plt.subplots(1,1,figsize=(6,6))
mesh.plotGrid(ax=ax, nodes=True, centers=True)
ax.plot(xtopo,topo,'k',linewidth=1)
# ax.plot(mesh.vectorNx, interp1d(xtopo,topo)(mesh.vectorNx),'--k',linewidth=3)
ax.plot(mesh.vectorCCx, interp1d(xtopo,topo)(mesh.vectorCCx),'--k',linewidth=3)
aveN2CC = Utils.sdiag(mesh.aveN2CC.T.sum(1))*mesh.aveN2CC.T
a = aveN2CC * indcc
a[a > 0] = 1.
a[a < 0.25] = np.nan
a = a.reshape(mesh.vnN, order='F')
masked_array = np.ma.array(a, mask=np.isnan(a))
ax.pcolor(mesh.vectorNx,mesh.vectorNy,masked_array.T, cmap = plt.cm.gray,alpha=0.2)
plt.show()
if __name__ == '__main__':
run(plotIt=True)
+17 -13
View File
@@ -1,25 +1,29 @@
# Run this file to add imports.
##### AUTOIMPORTS #####
import DC_Analytic_Dipole
import DC_Forward_PseudoSection
import EM_FDEM_1D_Inversion
import EM_FDEM_Analytic_MagDipoleWholespace
import EM_TDEM_1D_Inversion
import FLOW_Richards_1D_Celia1990
import Forward_BasicDirectCurrent
import Inversion_Linear
import Mesh_Basic_PlotImage
import Mesh_Basic_Types
import Mesh_Operators_CahnHilliard
import Mesh_QuadTree_Creation
import EM_TDEM_1D_Inversion
import Mesh_QuadTree_FaceDiv
import Mesh_QuadTree_HangingNodes
import Mesh_Tensor_Creation
import MT_1D_ForwardAndInversion
import FLOW_Richards_1D_Celia1990
import DC_Forward_PseudoSection
import Mesh_Operators_CahnHilliard
import Mesh_Basic_Types
import Inversion_IRLS
import Inversion_Linear
import EM_Schenkel_Morrison_Casing
import MT_3D_Foward
import Mesh_Basic_ForwardDC
import MT_1D_ForwardAndInversion
import Utils_surface2ind_topo
import MT_1D_analytic_nlayer_Earth
import EM_FDEM_Analytic_MagDipoleWholespace
import Mesh_Basic_PlotImage
import DC_Analytic_Dipole
import Mesh_QuadTree_HangingNodes
__examples__ = ["DC_Analytic_Dipole", "DC_Forward_PseudoSection", "EM_FDEM_1D_Inversion", "EM_FDEM_Analytic_MagDipoleWholespace", "EM_TDEM_1D_Inversion", "FLOW_Richards_1D_Celia1990", "Forward_BasicDirectCurrent", "Inversion_Linear", "Mesh_Basic_PlotImage", "Mesh_Basic_Types", "Mesh_Operators_CahnHilliard", "Mesh_QuadTree_Creation", "Mesh_QuadTree_FaceDiv", "Mesh_QuadTree_HangingNodes", "Mesh_Tensor_Creation", "MT_1D_ForwardAndInversion", "MT_3D_Foward"]
__examples__ = ["EM_FDEM_1D_Inversion", "Mesh_QuadTree_Creation", "EM_TDEM_1D_Inversion", "Mesh_QuadTree_FaceDiv", "Mesh_Tensor_Creation", "FLOW_Richards_1D_Celia1990", "DC_Forward_PseudoSection", "Mesh_Operators_CahnHilliard", "Mesh_Basic_Types", "Inversion_IRLS", "Inversion_Linear", "EM_Schenkel_Morrison_Casing", "MT_3D_Foward", "Mesh_Basic_ForwardDC", "MT_1D_ForwardAndInversion", "Utils_surface2ind_topo", "MT_1D_analytic_nlayer_Earth", "EM_FDEM_Analytic_MagDipoleWholespace", "Mesh_Basic_PlotImage", "DC_Analytic_Dipole", "Mesh_QuadTree_HangingNodes"]
##### AUTOIMPORTS #####
+3 -1
View File
@@ -33,7 +33,9 @@ class BaseInversion(object):
self._directiveList = value
self._directiveList.inversion = self
def __init__(self, invProb, directiveList=[], **kwargs):
def __init__(self, invProb, directiveList=None, **kwargs):
if directiveList is None:
directiveList = []
self.directiveList = directiveList
Utils.setKwargs(self, **kwargs)
-132
View File
@@ -1,132 +0,0 @@
from SimPEG import SolverLU as SimpegSolver, PropMaps, Utils, mkvc, sp, np
from SimPEG.EM.FDEM.FDEM import BaseFDEMProblem
from SurveyMT import Survey, Data
from FieldsMT import BaseMTFields
class BaseMTProblem(BaseFDEMProblem):
"""
Base class for all Natural source problems.
"""
def __init__(self, mesh, **kwargs):
BaseFDEMProblem.__init__(self, mesh, **kwargs)
Utils.setKwargs(self, **kwargs)
# Set the default pairs of the problem
surveyPair = Survey
dataPair = Data
fieldsPair = BaseMTFields
# Set the solver
Solver = SimpegSolver
solverOpts = {}
verbose = False
# Notes:
# Use the forward and devs from BaseFDEMProblem
# Might need to add more stuff here.
## NEED to clean up the Jvec and Jtvec to use Zero and Identities for None components.
def Jvec(self, m, v, f=None):
"""
Function to calculate the data sensitivities dD/dm times a vector.
:param numpy.ndarray m (nC, 1) - conductive model
:param numpy.ndarray v (nC, 1) - random vector
:param MTfields object (optional) - MT fields object, if not given it is calculated
:rtype: MTdata object
:return: Data sensitivities wrt m
"""
# Calculate the fields
if f is None:
f= self.fields(m)
# Set current model
self.curModel = m
# Initiate the Jv object
Jv = self.dataPair(self.survey)
# Loop all the frequenies
for freq in self.survey.freqs:
dA_du = self.getA(freq) #
dA_duI = self.Solver(dA_du, **self.solverOpts)
for src in self.survey.getSrcByFreq(freq):
# We need fDeriv_m = df/du*du/dm + df/dm
# Construct du/dm, it requires a solve
# NOTE: need to account for the 2 polarizations in the derivatives.
f_src = f[src,:]
# dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by dA_duI. The 2 columns are each of the polarizations.
dA_dm = self.getADeriv_m(freq, f_src, v) # Size: nE,2 (u_px,u_py) in the columns.
dRHS_dm = self.getRHSDeriv_m(freq, v) # Size: nE,2 (u_px,u_py) in the columns.
if dRHS_dm is None:
du_dm = dA_duI * ( -dA_dm )
else:
du_dm = dA_duI * ( -dA_dm + dRHS_dm )
# Calculate the projection derivatives
for rx in src.rxList:
# Get the projection derivative
# v should be of size 2*nE (for 2 polarizations)
PDeriv_u = lambda t: rx.evalDeriv(src, self.mesh, f, t) # wrt u, we don't have have PDeriv wrt m
Jv[src, rx] = PDeriv_u(mkvc(du_dm))
dA_duI.clean()
# Return the vectorized sensitivities
return mkvc(Jv)
def Jtvec(self, m, v, f=None):
"""
Function to calculate the transpose of the data sensitivities (dD/dm)^T times a vector.
:param numpy.ndarray m (nC, 1) - conductive model
:param numpy.ndarray v (nD, 1) - vector
:param MTfields object u (optional) - MT fields object, if not given it is calculated
:rtype: MTdata object
:return: Data sensitivities wrt m
"""
if f is None:
f = self.fields(m)
self.curModel = m
# Ensure v is a data object.
if not isinstance(v, self.dataPair):
v = self.dataPair(self.survey, v)
Jtv = np.zeros(m.size)
for freq in self.survey.freqs:
AT = self.getA(freq).T
ATinv = self.Solver(AT, **self.solverOpts)
for src in self.survey.getSrcByFreq(freq):
ftype = self._fieldType + 'Solution'
f_src = f[src, :]
for rx in src.rxList:
# Get the adjoint evalDeriv
# PTv needs to be nE,
PTv = rx.evalDeriv(src, self.mesh, f, mkvc(v[src, rx],2), adjoint=True) # wrt u, need possibility wrt m
# Get the
dA_duIT = ATinv * PTv
dA_dmT = self.getADeriv_m(freq, f_src, mkvc(dA_duIT), adjoint=True)
dRHS_dmT = self.getRHSDeriv_m(freq, mkvc(dA_duIT), adjoint=True)
# Make du_dmT
if dRHS_dmT is None:
du_dmT = -dA_dmT
else:
du_dmT = -dA_dmT + dRHS_dmT
# Select the correct component
# du_dmT needs to be of size nC,
real_or_imag = rx.projComp
if real_or_imag == 'real':
Jtv += du_dmT.real
elif real_or_imag == 'imag':
Jtv += -du_dmT.real
else:
raise Exception('Must be real or imag')
# Clean the factorization, clear memory.
ATinv.clean()
return Jtv
-291
View File
@@ -1,291 +0,0 @@
from SimPEG.EM.Utils import omega
from SimPEG import mkvc
from scipy.constants import mu_0
from SimPEG.MT.BaseMT import BaseMTProblem
from SimPEG.MT.SurveyMT import Survey, Data
from SimPEG.MT.FieldsMT import Fields1D_e
from SimPEG.MT.Utils.MT1Danalytic import getEHfields
import numpy as np
import multiprocessing, sys, time
class eForm_psField(BaseMTProblem):
"""
A MT problem soving a e formulation and primary/secondary fields decomposion.
By eliminating the magnetic flux density using
.. math ::
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} \\right)
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
.. math ::
\\left(\mathbf{C}^T \mathbf{M^e_{\mu^{-1}}} \mathbf{C} + i \omega \mathbf{M^f_\sigma}] \mathbf{e}_{s} =& i \omega \mathbf{M^f_{\delta \sigma}} \mathbf{e}_{p}
which we solve for \\\(\\\mathbf{e_s}\\\). The total field \\\mathbf{e}\\ = \\\mathbf{e_p}\\ + \\\mathbf{e_s}\\.
The primary field is estimated from a background model (commonly half space ).
"""
# From FDEMproblem: Used to project the fields. Currently not used for MTproblem.
_fieldType = 'e_1d'
_eqLocs = 'EF'
_sigmaPrimary = None
def __init__(self, mesh, **kwargs):
BaseMTProblem.__init__(self, mesh, **kwargs)
self.fieldsPair = Fields1D_e
# self._sigmaPrimary = sigmaPrimary
@property
def MeMui(self):
"""
Edge inner product matrix
"""
if getattr(self, '_MeMui', None) is None:
self._MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
return self._MeMui
@property
def MfSigma(self):
"""
Edge inner product matrix
"""
if getattr(self, '_MfSigma', None) is None:
self._MfSigma = self.mesh.getFaceInnerProduct(self.curModel.sigma)
return self._MfSigma
@property
def sigmaPrimary(self):
"""
A background model, use for the calculation of the primary fields.
"""
return self._sigmaPrimary
@sigmaPrimary.setter
def sigmaPrimary(self, val):
# Note: TODO add logic for val, make sure it is the correct size.
self._sigmaPrimary = val
def getA(self, freq):
"""
Function to get the A matrix.
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
"""
# Note: need to use the code above since in the 1D problem I want
# e to live on Faces(nodes) and h on edges(cells). Might need to rethink this
# Possible that _fieldType and _eqLocs can fix this
MeMui = self.MeMui
MfSigma = self.MfSigma
C = self.mesh.nodalGrad
# Make A
A = C.T*MeMui*C + 1j*omega(freq)*MfSigma
# Either return full or only the inner part of A
return A
def getADeriv_m(self, freq, u, v, adjoint=False):
"""
The derivative of A wrt sigma
"""
dsig_dm = self.curModel.sigmaDeriv
MeMui = self.MeMui
#
u_src = u['e_1dSolution']
dMfSigma_dm = self.mesh.getFaceInnerProductDeriv(self.curModel.sigma)(u_src) * self.curModel.sigmaDeriv
if adjoint:
return 1j * omega(freq) * ( dMfSigma_dm.T * v )
# Note: output has to be nN/nF, not nC/nE.
# v should be nC
return 1j * omega(freq) * ( dMfSigma_dm * v )
def getRHS(self, freq):
"""
Function to return the right hand side for the system.
:param float freq: Frequency
:rtype: numpy.ndarray (nF, 1), numpy.ndarray (nF, 1)
:return: RHS for 1 polarizations, primary fields
"""
# Get sources for the frequncy(polarizations)
Src = self.survey.getSrcByFreq(freq)[0]
S_e = Src.S_e(self)
return -1j * omega(freq) * S_e
def getRHSDeriv_m(self, freq, v, adjoint=False):
"""
The derivative of the RHS wrt sigma
"""
Src = self.survey.getSrcByFreq(freq)[0]
S_eDeriv = Src.S_eDeriv_m(self, v, adjoint)
return -1j * omega(freq) * S_eDeriv
def fields(self, m):
'''
Function to calculate all the fields for the model m.
:param np.ndarray (nC,) m: Conductivity model
'''
# Set the current model
self.curModel = m
F = Fields1D_e(self.mesh, self.survey)
for freq in self.survey.freqs:
if self.verbose:
startTime = time.time()
print 'Starting work for {:.3e}'.format(freq)
sys.stdout.flush()
A = self.getA(freq)
rhs = self.getRHS(freq)
Ainv = self.Solver(A, **self.solverOpts)
e_s = Ainv * rhs
# Store the fields
Src = self.survey.getSrcByFreq(freq)[0]
# NOTE: only store the e_solution(secondary), all other components calculated in the fields object
F[Src, 'e_1dSolution'] = e_s[:,-1] # Only storing the yx polarization as 1d
# Note curl e = -iwb so b = -curl e /iw
# b = -( self.mesh.nodalGrad * e )/( 1j*omega(freq) )
# F[Src, 'b_1d'] = b[:,1]
if self.verbose:
print 'Ran for {:f} seconds'.format(time.time()-startTime)
sys.stdout.flush()
return F
# Note this is not fully functional.
# Missing:
# Fields class corresponding to the fields
# Update Jvec and Jtvec to include all the derivatives components
# Other things ...
class eForm_TotalField(BaseMTProblem):
"""
A MT problem solving a e formulation and a Total bondary domain decompostion.
Solves the equation:
Math:
"""
# From FDEMproblem: Used to project the fields. Currently not used for MTproblem.
_fieldType = 'e'
_eqLocs = 'EF'
def __init__(self, mesh, **kwargs):
BaseMTProblem.__init__(self, mesh, **kwargs)
@property
def MeMui(self):
"""
Edge inner product matrix
"""
if getattr(self, '_MeMui', None) is None:
self._MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
return self._MeMui
@property
def MfSigma(self):
"""
Edge inner product matrix
"""
if getattr(self, '_MfSigma', None) is None:
self._MfSigma = self.mesh.getFaceInnerProduct(self.curModel.sigma)
return self._MfSigma
def getA(self, freq, full=False):
"""
Function to get the A matrix.
:param float freq: Frequency
:param logic full: Return full A or the inner part
:rtype: scipy.sparse.csr_matrix
:return: A
"""
MeMui = self.MeMui
MfSigma = self.MfSigma
# Note: need to use the code above since in the 1D problem I want
# e to live on Faces(nodes) and h on edges(cells). Might need to rethink this
# Possible that _fieldType and _eqLocs can fix this
# MeMui = self.MfMui
# MfSigma = self.MfSigma
C = self.mesh.nodalGrad
# Make A
A = C.T*MeMui*C + 1j*omega(freq)*MfSigma
# Either return full or only the inner part of A
if full:
return A
else:
return A[1:-1,1:-1]
def getADeriv_m(self, freq, u, v, adjoint=False):
raise NotImplementedError('getADeriv is not implemented')
def getRHS(self, freq):
"""
Function to return the right hand side for the system.
:param float freq: Frequency
:rtype: numpy.ndarray (nE, 2), numpy.ndarray (nE, 2)
:return: RHS for both polarizations, primary fields
"""
# Get sources for the frequency
# NOTE: Need to use the source information, doesn't really apply in 1D
src = self.survey.getSrcByFreq(freq)
# Get the full A
A = self.getA(freq,full=True)
# Define the outer part of the solution matrix
Aio = A[1:-1,[0,-1]]
Ed, Eu, Hd, Hu = getEHfields(self.mesh,self.curModel.sigma,freq,self.mesh.vectorNx)
Etot = (Ed + Eu)
sourceAmp = 1.0
Etot = ((Etot/Etot[-1])*sourceAmp) # Scale the fields to be equal to sourceAmp at the top
## Note: The analytic solution is derived with e^iwt
eBC = np.r_[Etot[0],Etot[-1]]
# The right hand side
return -Aio*eBC, eBC
def getRHSderiv_m(self, freq, backSigma, u, v, adjoint=False):
raise NotImplementedError('getRHSDeriv not implemented yet')
return None
def fields(self, m):
'''
Function to calculate all the fields for the model m.
:param np.ndarray (nC,) m: Conductivity model
:param np.ndarray (nC,) m_back: Background conductivity model
'''
self.curModel = m
# RHS, CalcFields = self.getRHS(freq,m_back), self.calcFields
F = Fields1D_e(self.mesh, self.survey)
for freq in self.survey.freqs:
if self.verbose:
startTime = time.time()
print 'Starting work for {:.3e}'.format(freq)
sys.stdout.flush()
A = self.getA(freq)
rhs, e_o = self.getRHS(freq)
Ainv = self.Solver(A, **self.solverOpts)
e_i = Ainv * rhs
e = mkvc(np.r_[e_o[0], e_i, e_o[1]],2)
# Store the fields
Src = self.survey.getSrcByFreq(freq)
# NOTE: only store e fields
F[Src, 'e_1dSolution'] = e[:,0]
if self.verbose:
print 'Ran for {:f} seconds'.format(time.time()-startTime)
sys.stdout.flush()
return F
-1
View File
@@ -1 +0,0 @@
from Probs import eForm_TotalField, eForm_psField
View File
-1
View File
@@ -1 +0,0 @@
pass
-138
View File
@@ -1,138 +0,0 @@
from SimPEG import Survey, Problem, Utils, Models, np, sp, mkvc, SolverLU as SimpegSolver
from SimPEG.EM.Utils import omega
from scipy.constants import mu_0
from SimPEG.MT.BaseMT import BaseMTProblem
from SimPEG.MT.SurveyMT import Survey, Data
from SimPEG.MT.FieldsMT import Fields3D_e
import multiprocessing, sys, time
class eForm_ps(BaseMTProblem):
"""
A MT problem solving a e formulation and a primary/secondary fields decompostion.
By eliminating the magnetic flux density using
.. math ::
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} \\right)
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
.. math ::
\\left(\mathbf{C}^T \mathbf{M^f_{\mu^{-1}}} \mathbf{C} + i \omega \mathbf{M^e_\sigma}] \mathbf{e}_{s} =& i \omega \mathbf{M^e_{\delta \sigma}} \mathbf{e}_{p}
which we solve for \\\(\\\mathbf{e_s}\\\). The total field \\\mathbf{e}\\ = \\\mathbf{e_p}\\ + \\\mathbf{e_s}\\.
The primary field is estimated from a background model (commonly as a 1D model).
"""
# From FDEMproblem: Used to project the fields. Currently not used for MTproblem.
_fieldType = 'e'
_eqLocs = 'FE'
fieldsPair = Fields3D_e
_sigmaPrimary = None
def __init__(self, mesh, **kwargs):
BaseMTProblem.__init__(self, mesh, **kwargs)
@property
def sigmaPrimary(self):
"""
A background model, use for the calculation of the primary fields.
"""
return self._sigmaPrimary
@sigmaPrimary.setter
def sigmaPrimary(self, val):
# Note: TODO add logic for val, make sure it is the correct size.
self._sigmaPrimary = val
def getA(self, freq):
"""
Function to get the A system.
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
"""
Mmui = self.MfMui
Msig = self.MeSigma
C = self.mesh.edgeCurl
return C.T*Mmui*C + 1j*omega(freq)*Msig
def getADeriv_m(self, freq, u, v, adjoint=False):
"""
Calculate the derivative of A wrt m.
"""
# This considers both polarizations and returns a nE,2 matrix for each polarization
if adjoint:
dMe_dsigV = sp.hstack(( self.MeSigmaDeriv( u['e_pxSolution'] ).T, self.MeSigmaDeriv(u['e_pySolution'] ).T ))*v
else:
# Need a nE,2 matrix to be returned
dMe_dsigV = np.hstack(( mkvc(self.MeSigmaDeriv( u['e_pxSolution'] )*v,2), mkvc( self.MeSigmaDeriv(u['e_pySolution'] )*v,2) ))
return 1j * omega(freq) * dMe_dsigV
def getRHS(self, freq):
"""
Function to return the right hand side for the system.
:param float freq: Frequency
:rtype: numpy.ndarray (nE, 2), numpy.ndarray (nE, 2)
:return: RHS for both polarizations, primary fields
"""
# Get sources for the frequncy(polarizations)
Src = self.survey.getSrcByFreq(freq)[0]
S_e = Src.S_e(self)
return -1j * omega(freq) * S_e
def getRHSDeriv_m(self, freq, v, adjoint=False):
"""
The derivative of the RHS with respect to sigma
"""
Src = self.survey.getSrcByFreq(freq)[0]
S_eDeriv = Src.S_eDeriv_m(self, v, adjoint)
return -1j * omega(freq) * S_eDeriv
def fields(self, m):
'''
Function to calculate all the fields for the model m.
:param np.ndarray (nC,) m: Conductivity model
'''
# Set the current model
self.curModel = m
F = Fields3D_e(self.mesh, self.survey)
for freq in self.survey.freqs:
if self.verbose:
startTime = time.time()
print 'Starting work for {:.3e}'.format(freq)
sys.stdout.flush()
A = self.getA(freq)
rhs = self.getRHS(freq)
# Solve the system
Ainv = self.Solver(A, **self.solverOpts)
e_s = Ainv * rhs
# Store the fields
Src = self.survey.getSrcByFreq(freq)[0]
# Store the fieldss
F[Src, 'e_pxSolution'] = e_s[:,0]
F[Src, 'e_pySolution'] = e_s[:,1]
# Note curl e = -iwb so b = -curl/iw
if self.verbose:
print 'Ran for {:f} seconds'.format(time.time()-startTime)
sys.stdout.flush()
Ainv.clean()
return F
-1
View File
@@ -1 +0,0 @@
from Probs import eForm_ps
-4
View File
@@ -1,4 +0,0 @@
from MT1Dsolutions import * # Add the names of the functions
from MT1Danalytic import *
from dataUtils import *
from ediFilesUtils import *
-46
View File
@@ -1,46 +0,0 @@
import SimPEG as simpeg, numpy as np
def homo1DModelSource(mesh,freq,m_back):
'''
Function that calculates and return background fields for a 3D mesh and model.
The calculuations use 1D field solution for a vertical slice throught model (south-western most column),
which is assigned at the fields everywhere for the respective polarizations.2
:param Simpeg mesh object mesh: Holds information on the discretization
:param float freq: The frequency to solve at
:param np.array m_back: Background model of conductivity to base the calculations on.
:rtype: numpy.ndarray (mesh.nE,2)
:return: eBG_bp, E fields for the background model at both polarizations.
'''
# import
from SimPEG.MT.Utils import get1DEfields
# Get a 1d solution for a halfspace background
mesh1d = simpeg.Mesh.TensorMesh([mesh.hz],np.array([mesh.x0[2]]))
# Note: Everything is using e^iwt
e0_1d = get1DEfields(mesh1d,mesh.r(m_back,'CC','CC','M')[0,0,:],freq)
# Setup x (east) polarization (_x)
ex_px = np.zeros(mesh.vnEx,dtype=complex)
ey_px = np.zeros((mesh.nEy,1),dtype=complex)
ez_px = np.zeros((mesh.nEz,1),dtype=complex)
# Assign the source to ex_x
for i in np.arange(mesh.vnEx[0]):
for j in np.arange(mesh.vnEx[1]):
ex_px[i,j,:] = -e0_1d
eBG_px = np.vstack((simpeg.Utils.mkvc(ex_px,2),ey_px,ez_px))
# Setup y (north) polarization (_py)
ex_py = np.zeros((mesh.nEx,1), dtype='complex128')
ey_py = np.zeros(mesh.vnEy, dtype='complex128')
ez_py = np.zeros((mesh.nEz,1), dtype='complex128')
# Assign the source to ey_py
for i in np.arange(mesh.vnEy[0]):
for j in np.arange(mesh.vnEy[1]):
ey_py[i,j,:] = e0_1d
# ey_py[1:-1,1:-1,1:-1] = 0
eBG_py = np.vstack((ex_py,simpeg.Utils.mkvc(ey_py,2),ez_py))
# Return the electric fields
eBG_bp = np.hstack((eBG_px,eBG_py))
return eBG_bp
-5
View File
@@ -1,5 +0,0 @@
import Utils
from SurveyMT import Rx, Survey, Data
from FieldsMT import Fields1D_e, Fields3D_e
import Problem1D, Problem2D, Problem3D
import SrcMT
+26 -88
View File
@@ -533,83 +533,6 @@ class ActiveCells(InjectActiveCells):
FutureWarning)
InjectActiveCells.__init__(self, mesh, indActive, valInactive, nC)
class InjectActiveCellsTopo(IdentityMap):
"""
Active model parameters. Extend for cells on topography to air cell (only works for tensor mesh)
"""
indActive = None #: Active Cells
valInactive = None #: Values of inactive Cells
nC = None #: Number of cells in the full model
def __init__(self, mesh, indActive, nC=None):
self.mesh = mesh
self.nC = nC or mesh.nC
if indActive.dtype is not bool:
z = np.zeros(self.nC,dtype=bool)
z[indActive] = True
indActive = z
self.indActive = indActive
self.indInactive = np.logical_not(indActive)
inds = np.nonzero(self.indActive)[0]
self.P = sp.csr_matrix((np.ones(inds.size),(inds, range(inds.size))), shape=(self.nC, self.nP))
@property
def shape(self):
return (self.nC, self.nP)
@property
def nP(self):
"""Number of parameters in the model."""
return self.indActive.sum()
def _transform(self, m):
val_temp = np.zeros(self.mesh.nC)
val_temp[self.indActive] = m
valInactive = np.zeros(self.mesh.nC)
#1D
if self.mesh.dim == 1:
z_temp = self.mesh.gridCC
val_temp[~self.indActive] = val_temp[np.argmax(z_temp[self.indActive])]
#2D
elif self.mesh.dim == 2:
act_temp = self.indActive.reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
val_temp = val_temp.reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
y_temp = self.mesh.gridCC[:,1].reshape((self.mesh.nCx, self.mesh.nCy), order = 'F')
for i in range(self.mesh.nCx):
act_tempx = act_temp[i,:] == 1
val_temp[i,~act_tempx] = val_temp[i,np.argmax(y_temp[i,act_tempx])]
valInactive[~self.indActive] = Utils.mkvc(val_temp)[~self.indActive]
#3D
elif self.mesh.dim == 3:
act_temp = self.indActive.reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
val_temp = val_temp.reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
z_temp = self.mesh.gridCC[:,2].reshape((self.mesh.nCx*self.mesh.nCy, self.mesh.nCz), order = 'F')
for i in range(self.mesh.nCx*self.mesh.nCy):
act_tempxy = act_temp[i,:] == 1
val_temp[i,~act_tempxy] = val_temp[i,np.argmax(z_temp[i,act_tempxy])]
valInactive[~self.indActive] = Utils.mkvc(val_temp)[~self.indActive]
self.valInactive = valInactive
return self.P*m + self.valInactive
def inverse(self, D):
return self.P.T*D
def deriv(self, m):
return self.P
class ActiveCellsTopo(InjectActiveCellsTopo):
def __init__(self, mesh, indActive, valInactive, nC=None):
warnings.warn(
"`ActiveCellsTopo` is deprecated and will be removed in future versions. Use `InjectActiveCellsTopo` instead",
FutureWarning)
InjectActiveCellsTopo.__init__(self, mesh, indActive, valInactive, nC)
class Weighting(IdentityMap):
"""
@@ -759,15 +682,29 @@ class PolyMap(IdentityMap):
m = [\sigma_1, \sigma_2, c]
Can take in an actInd vector to account for topography.
"""
def __init__(self, mesh, order, logSigma=True, normal='X'):
def __init__(self, mesh, order, logSigma=True, normal='X', actInd = None):
IdentityMap.__init__(self, mesh)
self.logSigma = logSigma
self.order = order
self.normal = normal
self.actInd = actInd
if getattr(self, 'actInd', None) is None:
self.actInd = range(self.mesh.nC)
self.nC = self.mesh.nC
else:
self.nC = len(self.actInd)
slope = 1e4
@property
def shape(self):
return (self.nC, self.nP)
@property
def nP(self):
if np.isscalar(self.order):
@@ -785,8 +722,8 @@ class PolyMap(IdentityMap):
sig1, sig2 = np.exp(sig1), np.exp(sig2)
#2D
if self.mesh.dim == 2:
X = self.mesh.gridCC[:,0]
Y = self.mesh.gridCC[:,1]
X = self.mesh.gridCC[self.actInd,0]
Y = self.mesh.gridCC[self.actInd,1]
if self.normal =='X':
f = polynomial.polyval(Y, c) - X
elif self.normal =='Y':
@@ -795,9 +732,9 @@ class PolyMap(IdentityMap):
raise(Exception("Input for normal = X or Y or Z"))
#3D
elif self.mesh.dim == 3:
X = self.mesh.gridCC[:,0]
Y = self.mesh.gridCC[:,1]
Z = self.mesh.gridCC[:,2]
X = self.mesh.gridCC[self.actInd,0]
Y = self.mesh.gridCC[self.actInd,1]
Z = self.mesh.gridCC[self.actInd,2]
if self.normal =='X':
f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X
elif self.normal =='Y':
@@ -806,6 +743,7 @@ class PolyMap(IdentityMap):
f = polynomial.polyval2d(X, Y, c.reshape((self.order[0]+1,self.order[1]+1))) - Z
else:
raise(Exception("Input for normal = X or Y or Z"))
else:
raise(Exception("Only supports 2D"))
@@ -819,8 +757,8 @@ class PolyMap(IdentityMap):
sig1, sig2 = np.exp(sig1), np.exp(sig2)
#2D
if self.mesh.dim == 2:
X = self.mesh.gridCC[:,0]
Y = self.mesh.gridCC[:,1]
X = self.mesh.gridCC[self.actInd,0]
Y = self.mesh.gridCC[self.actInd,1]
if self.normal =='X':
f = polynomial.polyval(Y, c) - X
@@ -832,9 +770,9 @@ class PolyMap(IdentityMap):
raise(Exception("Input for normal = X or Y or Z"))
#3D
elif self.mesh.dim == 3:
X = self.mesh.gridCC[:,0]
Y = self.mesh.gridCC[:,1]
Z = self.mesh.gridCC[:,2]
X = self.mesh.gridCC[self.actInd,0]
Y = self.mesh.gridCC[self.actInd,1]
Z = self.mesh.gridCC[self.actInd,2]
if self.normal =='X':
f = polynomial.polyval2d(Y, Z, c.reshape((self.order[0]+1,self.order[1]+1))) - X
-61
View File
@@ -1,5 +1,4 @@
import numpy as np
import scipy.sparse as sp
from SimPEG import Utils
@@ -595,63 +594,3 @@ class BaseRectangularMesh(BaseMesh):
return out
else:
return switchKernal(x)
def getInterpolationMatMesh2Mesh(self, mesh2, locType='CC', locTypeFrom=None):
"""
Interpolates variables from the current mesh to a new mesh (mesh2)
:param Mesh mesh2: SimPEG mesh which we interpolate values to
:param string locType: location of variables 'CC', 'E', 'F', 'N'
:rtype: scipy.sparse.csr_matrix
:return P: interpolation matrix
"""
# import warnings
# warnings.warn(
# "`getInterpolationMatMesh2Mesh` will be slow. If you want to interpolate a vector from one mesh to another, use `InterpolateVecMesh2Mesh`",
# RuntimeWarning)
if locTypeFrom is None:
locTypeFrom = locType # assume that we are interpolating to and from the same place
# Error Checking
if self._meshType == 'CYL':
assert self.isSymmetric, "Currently, we do not support non-symmetric cyl meshes"
if mesh2._meshType == 'CYL':
assert self._meshType == 'CYL', "Interpolation from 3D mesh to Cyl mesh is not supported"
# if Cyl to cart call
if self._meshType == 'CYL' and mesh2._meshType != 'CYL':
return self.getInterpolationMatCartMesh(mesh2, locType)
# Scalars
if locType in ['CC', 'CCVx', 'CCVy', 'CCVz', 'N', 'Fx', 'Fy', 'Fz', 'Ex', 'Ey', 'Ez']:
grid = getattr(mesh2, 'grid%s'%locTypeFrom)
return self.getInterpolationMat(grid, locType)
# Vectors
else:
if self._meshType == 'CYL':
if locType == 'F':
X = self.getInterpolationMatMesh2Mesh(mesh2, locType='Fx', locTypeFrom=locTypeFrom+'x')
Z = self.getInterpolationMatMesh2Mesh(mesh2, locType='Fz', locTypeFrom=locTypeFrom+'z')
return sp.block_diag([X, Z])
elif locType == 'E':
return self.getInterpolationMatMesh2Mesh(mesh2, locType='Ey', locTypeFrom=locTypeFrom+'y')
if self.dim == 1:
return self.getInterpolationMatMesh2Mesh(mesh2, locType='%sx'%locType, locTypeFrom=locTypeFrom+'x')
elif self.dim == 2:
X = self.getInterpolationMatMesh2Mesh(mesh2, locType='%sx'%locType, locTypeFrom=locTypeFrom+'x')
Y = self.getInterpolationMatMesh2Mesh(mesh2, locType='%sy'%locType, locTypeFrom=locTypeFrom+'y')
return sp.block_diag([X, Y])
elif self.dim == 3:
X = self.getInterpolationMatMesh2Mesh(mesh2, locType='%sx'%locType, locTypeFrom=locTypeFrom+'x')
Y = self.getInterpolationMatMesh2Mesh(mesh2, locType='%sy'%locType, locTypeFrom=locTypeFrom+'y')
Z = self.getInterpolationMatMesh2Mesh(mesh2, locType='%sz'%locType, locTypeFrom=locTypeFrom+'z')
return sp.block_diag([X, Y, Z])
+2 -97
View File
@@ -2,6 +2,7 @@ from SimPEG import Utils, np
from BaseMesh import BaseRectangularMesh
from DiffOperators import DiffOperators
from InnerProducts import InnerProducts
from View import CurvView
# Some helper functions.
length2D = lambda x: (x[:, 0]**2 + x[:, 1]**2)**0.5
@@ -10,7 +11,7 @@ normalize2D = lambda x: x/np.kron(np.ones((1, 2)), Utils.mkvc(length2D(x), 2))
normalize3D = lambda x: x/np.kron(np.ones((1, 3)), Utils.mkvc(length3D(x), 2))
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts, CurvView):
"""
CurvilinearMesh is a mesh class that deals with curvilinear meshes.
@@ -330,102 +331,6 @@ class CurvilinearMesh(BaseRectangularMesh, DiffOperators, InnerProducts):
#############################################
# Plotting Functions #
#############################################
def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False):
"""Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions.
.. plot::
:include-source:
from SimPEG import Mesh, Utils
X, Y = Utils.exampleLrmGrid([3,3],'rotate')
M = Mesh.CurvilinearMesh([X, Y])
M.plotGrid(showIt=True)
"""
import matplotlib.pyplot as plt
import matplotlib
from mpl_toolkits.mplot3d import Axes3D
mkvc = Utils.mkvc
axOpts = {'projection':'3d'} if self.dim == 3 else {}
if ax is None: ax = plt.subplot(111, **axOpts)
NN = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
if lines:
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
X = np.r_[X1, X2]
Y = np.r_[Y1, Y2]
ax.plot(X, Y, 'b-')
if centers:
ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro')
# Nx = self.r(self.normals, 'F', 'Fx', 'V')
# Ny = self.r(self.normals, 'F', 'Fy', 'V')
# Tx = self.r(self.tangents, 'E', 'Ex', 'V')
# Ty = self.r(self.tangents, 'E', 'Ey', 'V')
# ax.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
# nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
# nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
# ax.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
# ax.plot(nX, nY, 'r-')
# nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
# nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
# #ax.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
# ax.plot(nX, nY, 'g-')
# tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
# tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
# ax.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
# ax.plot(tX, tY, 'r-')
# nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
# nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
# #ax.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
# ax.plot(nX, nY, 'g-')
elif self.dim == 3:
X1 = np.c_[mkvc(NN[0][:-1, :, :]), mkvc(NN[0][1:, :, :]), mkvc(NN[0][:-1, :, :])*np.nan].flatten()
Y1 = np.c_[mkvc(NN[1][:-1, :, :]), mkvc(NN[1][1:, :, :]), mkvc(NN[1][:-1, :, :])*np.nan].flatten()
Z1 = np.c_[mkvc(NN[2][:-1, :, :]), mkvc(NN[2][1:, :, :]), mkvc(NN[2][:-1, :, :])*np.nan].flatten()
X2 = np.c_[mkvc(NN[0][:, :-1, :]), mkvc(NN[0][:, 1:, :]), mkvc(NN[0][:, :-1, :])*np.nan].flatten()
Y2 = np.c_[mkvc(NN[1][:, :-1, :]), mkvc(NN[1][:, 1:, :]), mkvc(NN[1][:, :-1, :])*np.nan].flatten()
Z2 = np.c_[mkvc(NN[2][:, :-1, :]), mkvc(NN[2][:, 1:, :]), mkvc(NN[2][:, :-1, :])*np.nan].flatten()
X3 = np.c_[mkvc(NN[0][:, :, :-1]), mkvc(NN[0][:, :, 1:]), mkvc(NN[0][:, :, :-1])*np.nan].flatten()
Y3 = np.c_[mkvc(NN[1][:, :, :-1]), mkvc(NN[1][:, :, 1:]), mkvc(NN[1][:, :, :-1])*np.nan].flatten()
Z3 = np.c_[mkvc(NN[2][:, :, :-1]), mkvc(NN[2][:, :, 1:]), mkvc(NN[2][:, :, :-1])*np.nan].flatten()
X = np.r_[X1, X2, X3]
Y = np.r_[Y1, Y2, Y3]
Z = np.r_[Z1, Z2, Z3]
ax.plot(X, Y, 'b', zs=Z)
ax.set_zlabel('x3')
ax.grid(True)
ax.set_xlabel('x1')
ax.set_ylabel('x2')
if showIt: plt.show()
if __name__ == '__main__':
nc = 5
h1 = np.cumsum(np.r_[0, np.ones(nc)/(nc)])
+12 -9
View File
@@ -330,7 +330,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
raise NotImplementedError('wrapping in the averaging is not yet implemented')
return self._aveF2CCV
def getInterpolationMatCartMesh(self, Mrect, locType='CC'):
def getInterpolationMatCartMesh(self, Mrect, locType='CC', locTypeTo=None):
"""
Takes a cartesian mesh and returns a projection to translate onto the cartesian grid.
"""
@@ -338,19 +338,22 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
assert self.isSymmetric, "Currently we have not taken into account other projections for more complicated CylMeshes"
if locTypeTo is None:
locTypeTo = locType
if locType == 'F':
# do this three times for each component
X = self.getInterpolationMatCartMesh(Mrect, locType='Fx')
Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy')
Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz')
X = self.getInterpolationMatCartMesh(Mrect, locType='Fx', locTypeTo=locTypeTo+'x')
Y = self.getInterpolationMatCartMesh(Mrect, locType='Fy', locTypeTo=locTypeTo+'y')
Z = self.getInterpolationMatCartMesh(Mrect, locType='Fz', locTypeTo=locTypeTo+'z')
return sp.vstack((X,Y,Z))
if locType == 'E':
X = self.getInterpolationMatCartMesh(Mrect, locType='Ex')
Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey')
Z = spzeros(Mrect.nEz, self.nE)
X = self.getInterpolationMatCartMesh(Mrect, locType='Ex', locTypeTo=locTypeTo+'x')
Y = self.getInterpolationMatCartMesh(Mrect, locType='Ey', locTypeTo=locTypeTo+'y')
Z = spzeros(getattr(Mrect, 'n' + locTypeTo + 'z'), self.nE)
return sp.vstack((X,Y,Z))
grid = getattr(Mrect, 'grid' + locType)
grid = getattr(Mrect, 'grid' + locTypeTo)
# This is unit circle stuff, 0 to 2*pi, starting at x-axis, rotating counter clockwise in an x-y slice
theta = - np.arctan2(grid[:,0] - self.cartesianOrigin[0], grid[:,1] - self.cartesianOrigin[1]) + np.pi/2
theta[theta < 0] += np.pi*2.0
@@ -366,7 +369,7 @@ class CylMesh(BaseTensorMesh, BaseRectangularMesh, InnerProducts, CylView):
'Ex': Mrect.tangents[:Mrect.nEx,:],
'Ey': Mrect.tangents[Mrect.nEx:(Mrect.nEx+Mrect.nEy),:],
'Ez': Mrect.tangents[-Mrect.nEz:,:],
}[locType]
}[locTypeTo]
if 'F' in locType:
normals = np.c_[np.cos(theta), np.sin(theta), np.zeros(theta.size)]
proj = ( normals * dotMe ).sum(axis=1)
+109 -30
View File
@@ -307,24 +307,28 @@ class DiffOperators(object):
return BC
_cellGradBC_list = 'neumann'
def _cellGradStencil(self):
BC = self.setCellGradBC(self._cellGradBC_list)
n = self.vnC
if(self.dim == 1):
G = ddxCellGrad(n[0], BC[0])
elif(self.dim == 2):
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0]))
G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0]))
G = sp.vstack((G1, G2), format="csr")
elif(self.dim == 3):
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0]))
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0]))
G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0]))
G = sp.vstack((G1, G2, G3), format="csr")
return G
def cellGrad():
doc = "The cell centered Gradient, takes you to cell faces."
def fget(self):
if(self._cellGrad is None):
BC = self.setCellGradBC(self._cellGradBC_list)
n = self.vnC
if(self.dim == 1):
G = ddxCellGrad(n[0], BC[0])
elif(self.dim == 2):
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC[0]))
G2 = sp.kron(ddxCellGrad(n[1], BC[1]), speye(n[0]))
G = sp.vstack((G1, G2), format="csr")
elif(self.dim == 3):
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC[0]))
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC[1]), speye(n[0]))
G3 = kron3(ddxCellGrad(n[2], BC[2]), speye(n[1]), speye(n[0]))
G = sp.vstack((G1, G2, G3), format="csr")
G = self._cellGradStencil()
# Compute areas of cell faces & volumes
S = self.area
V = self.aveCC2F*self.vol # Average volume between adjacent cells
@@ -361,19 +365,24 @@ class DiffOperators(object):
_cellGradBC = None
cellGradBC = property(**cellGradBC())
def _cellGradxStencil(self):
BC = ['neumann', 'neumann']
n = self.vnC
if(self.dim == 1):
G1 = ddxCellGrad(n[0], BC)
elif(self.dim == 2):
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC))
elif(self.dim == 3):
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC))
return G1
def cellGradx():
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
def fget(self):
if getattr(self, '_cellGradx', None) is None:
BC = ['neumann', 'neumann']
n = self.vnC
if(self.dim == 1):
G1 = ddxCellGrad(n[0], BC)
elif(self.dim == 2):
G1 = sp.kron(speye(n[1]), ddxCellGrad(n[0], BC))
elif(self.dim == 3):
G1 = kron3(speye(n[2]), speye(n[1]), ddxCellGrad(n[0], BC))
G1 = self._cellGradxStencil()
# Compute areas of cell faces & volumes
V = self.aveCC2F*self.vol
L = self.r(self.area/V, 'F','Fx', 'V')
@@ -382,17 +391,22 @@ class DiffOperators(object):
return locals()
cellGradx = property(**cellGradx())
def _cellGradyStencil(self):
if self.dim < 2: return None
BC = ['neumann', 'neumann']
n = self.vnC
if(self.dim == 2):
G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0]))
elif(self.dim == 3):
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0]))
return G2
def cellGrady():
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
def fget(self):
if self.dim < 2: return None
if getattr(self, '_cellGrady', None) is None:
BC = ['neumann', 'neumann']
n = self.vnC
if(self.dim == 2):
G2 = sp.kron(ddxCellGrad(n[1], BC), speye(n[0]))
elif(self.dim == 3):
G2 = kron3(speye(n[2]), ddxCellGrad(n[1], BC), speye(n[0]))
G2 = self._cellGradyStencil()
# Compute areas of cell faces & volumes
V = self.aveCC2F*self.vol
L = self.r(self.area/V, 'F','Fy', 'V')
@@ -401,14 +415,19 @@ class DiffOperators(object):
return locals()
cellGrady = property(**cellGrady())
def _cellGradzStencil(self):
if self.dim < 3: return None
BC = ['neumann', 'neumann']
n = self.vnC
G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0]))
return G3
def cellGradz():
doc = "Cell centered Gradient in the x dimension. Has neumann boundary conditions."
def fget(self):
if self.dim < 3: return None
if getattr(self, '_cellGradz', None) is None:
BC = ['neumann', 'neumann']
n = self.vnC
G3 = kron3(ddxCellGrad(n[2], BC), speye(n[1]), speye(n[0]))
G3 = self._cellGradzStencil()
# Compute areas of cell faces & volumes
V = self.aveCC2F*self.vol
L = self.r(self.area/V, 'F','Fz', 'V')
@@ -565,7 +584,67 @@ class DiffOperators(object):
return Pbc, Pin, Pout
def getBCProjWF_simple(self, discretization='CC'):
"""
The weak form boundary condition projection matrices
when mixed boundary condition is used
"""
if discretization is not 'CC':
raise NotImplementedError('Boundary conditions only implemented for CC discretization.')
def projBC(n):
ij = ([0,n], [0,1])
vals = [0,0]
vals[0] = 1
vals[1] = 1
return sp.csr_matrix((vals, ij), shape=(n+1,2))
def projDirichlet(n, bc):
bc = checkBC(bc)
ij = ([0,n], [0,1])
vals = [0,0]
if(bc[0] == 'dirichlet'):
vals[0] = -1
if(bc[1] == 'dirichlet'):
vals[1] = 1
return sp.csr_matrix((vals, ij), shape=(n+1,2))
BC = [['dirichlet','dirichlet'],['dirichlet','dirichlet'],['dirichlet','dirichlet']]
n = self.vnC
indF = self.faceBoundaryInd
if(self.dim == 1):
Pbc = projDirichlet(n[0], BC[0])
B = projBC(n[0])
indF = indF[0] | indF[1]
Pbc = Pbc*sdiag(self.area[indF])
elif(self.dim == 2):
Pbc1 = sp.kron(speye(n[1]), projDirichlet(n[0], BC[0]))
Pbc2 = sp.kron(projDirichlet(n[1], BC[1]), speye(n[0]))
Pbc = sp.block_diag((Pbc1, Pbc2), format="csr")
B1 = sp.kron(speye(n[1]), projBC(n[0]))
B2 = sp.kron(projBC(n[1]), speye(n[0]))
B = sp.block_diag((B1, B2), format="csr")
indF = np.r_[(indF[0] | indF[1]), (indF[2] | indF[3])]
Pbc = Pbc*sdiag(self.area[indF])
elif(self.dim == 3):
Pbc1 = kron3(speye(n[2]), speye(n[1]), projDirichlet(n[0], BC[0]))
Pbc2 = kron3(speye(n[2]), projDirichlet(n[1], BC[1]), speye(n[0]))
Pbc3 = kron3(projDirichlet(n[2], BC[2]), speye(n[1]), speye(n[0]))
Pbc = sp.block_diag((Pbc1, Pbc2, Pbc3), format="csr")
B1 = kron3(speye(n[2]), speye(n[1]), projBC(n[0]))
B2 = kron3(speye(n[2]), projBC(n[1]), speye(n[0]))
B3 = kron3(projBC(n[2]), speye(n[1]), speye(n[0]))
B = sp.block_diag((B1, B2, B3), format="csr")
indF = np.r_[(indF[0] | indF[1]), (indF[2] | indF[3]), (indF[4] | indF[5])]
Pbc = Pbc*sdiag(self.area[indF])
return Pbc, B.T
# --------------- Averaging ---------------------
@property
+45 -3
View File
@@ -21,10 +21,9 @@ class TensorMeshIO(object):
if '*' in seg:
st = seg
sp = seg.split('*')
re = np.array(sp[0],dtype=int)*(' ' + sp[1])
re = int(sp[0])*(' ' + sp[1])
line = line.replace(st,re.strip())
return np.array(line.split(),dtype=float)
# Read the file as line strings, remove lines with comment = !
msh = np.genfromtxt(fileName,delimiter='\n',dtype=np.str,comments='!')
@@ -141,7 +140,6 @@ class TensorMeshIO(object):
vtkObj.GetCellData().AddArray(vtkDoubleArr)
# Set the active scalar
vtkObj.GetCellData().SetActiveScalars(models.keys()[0])
# vtkObj.Update()
# Check the extension of the fileName
ext = os.path.splitext(fileName)[1]
@@ -158,6 +156,50 @@ class TensorMeshIO(object):
vtrWriteFilter.SetFileName(fileName)
vtrWriteFilter.Update()
def _toVTRObj(mesh,models=None):
"""
Makes and saves a VTK rectilinear file (vtr) for a simpeg Tensor mesh and model.
Input:
:param str, path to the output vtk file
:param mesh, SimPEG TensorMesh object - mesh to be transfer to VTK
:param models, dictionary of numpy.array - Name('s) and array('s). Match number of cells
"""
# Import
from vtk import vtkRectilinearGrid as rectGrid, VTK_VERSION
from vtk.util.numpy_support import numpy_to_vtk
# Deal with dimensionalities
if mesh.dim >= 1:
vX = mesh.vectorNx
xD = mesh.nNx
yD,zD = 1,1
vY, vZ = np.array([0,0])
if mesh.dim >= 2:
vY = mesh.vectorNy
yD = mesh.nNy
if mesh.dim == 3:
vZ = mesh.vectorNz
zD = mesh.nNz
# Use rectilinear VTK grid.
# Assign the spatial information.
vtkObj = rectGrid()
vtkObj.SetDimensions(xD,yD,zD)
vtkObj.SetXCoordinates(numpy_to_vtk(vX,deep=1))
vtkObj.SetYCoordinates(numpy_to_vtk(vY,deep=1))
vtkObj.SetZCoordinates(numpy_to_vtk(vZ,deep=1))
# Assign the model('s) to the object
if models is not None:
for item in models.iteritems():
# Convert numpy array
vtkDoubleArr = numpy_to_vtk(item[1],deep=1)
vtkDoubleArr.SetName(item[0])
vtkObj.GetCellData().AddArray(vtkDoubleArr)
# Set the active scalar
vtkObj.GetCellData().SetActiveScalars(models.keys()[0])
return vtkObj
def readModelUBC(mesh, fileName):
"""
+9 -3
View File
@@ -2131,10 +2131,16 @@ class TreeMesh(BaseTensorMesh, InnerProducts, TreeMeshIO):
def plotSlice(self, v, vType='CC',
normal='Z', ind=None, grid=True, view='real',
ax=None, clim=None, showIt=False,
pcolorOpts={},
streamOpts={'color':'k'},
gridOpts={'color':'k', 'alpha':0.5}):
pcolorOpts=None,
streamOpts=None,
gridOpts=None):
if pcolorOpts is None:
pcolorOpts = {}
if streamOpts is None:
streamOpts = {'color':'k'}
if gridOpts is None:
gridOpts = {'color':'k', 'alpha':0.5}
assert vType in ['CC','F','E']
assert self.dim == 3
+106 -50
View File
@@ -42,9 +42,9 @@ class TensorView(object):
def plotImage(self, v, vType='CC', grid=False, view='real',
ax=None, clim=None, showIt=False,
pcolorOpts={},
streamOpts={'color':'k'},
gridOpts={'color':'k'},
pcolorOpts=None,
streamOpts=None,
gridOpts=None,
numbering=True, annotationColor='w'
):
"""
@@ -84,6 +84,12 @@ class TensorView(object):
M.plotImage(v, annotationColor='k', showIt=True)
"""
if pcolorOpts is None:
pcolorOpts = {}
if streamOpts is None:
streamOpts = {'color':'k'}
if gridOpts is None:
gridOpts = {'color':'k'}
if ax is None:
fig = plt.figure()
@@ -174,9 +180,9 @@ class TensorView(object):
def plotSlice(self, v, vType='CC',
normal='Z', ind=None, grid=False, view='real',
ax=None, clim=None, showIt=False,
pcolorOpts={},
streamOpts={'color':'k'},
gridOpts={'color':'k', 'alpha':0.5}
pcolorOpts=None,
streamOpts=None,
gridOpts=None
):
"""
@@ -197,6 +203,12 @@ class TensorView(object):
M.plotSlice(M.cellGrad*b, 'F', view='vec', grid=True, showIt=True, pcolorOpts={'alpha':0.8})
"""
if pcolorOpts is None:
pcolorOpts = {}
if streamOpts is None:
streamOpts = {'color':'k'}
if gridOpts is None:
gridOpts = {'color':'k', 'alpha':0.5}
if type(vType) in [list, tuple]:
assert ax is None, "cannot specify an axis to plot on with this function."
fig, axs = plt.subplots(1,len(vType))
@@ -206,7 +218,7 @@ class TensorView(object):
return out
viewOpts = ['real','imag','abs','vec']
normalOpts = ['X', 'Y', 'Z']
vTypeOpts = ['CC', 'CCv','F','E','Fx','Fy','Fz','E','Ex','Ey','Ez']
vTypeOpts = ['CC', 'CCv','N','F','E','Fx','Fy','Fz','E','Ex','Ey','Ez']
# Some user error checking
assert vType in vTypeOpts, "vType must be in ['%s']" % "','".join(vTypeOpts)
@@ -289,11 +301,17 @@ class TensorView(object):
def _plotImage2D(self, v, vType='CC', grid=False, view='real',
ax=None, clim=None, showIt=False,
pcolorOpts={},
streamOpts={'color':'k'},
gridOpts={'color':'k'}
pcolorOpts=None,
streamOpts=None,
gridOpts=None
):
if pcolorOpts is None:
pcolorOpts = {}
if streamOpts is None:
streamOpts = {'color':'k'}
if gridOpts is None:
gridOpts = {'color':'k'}
vTypeOptsCC = ['N','CC','Fx','Fy','Ex','Ey']
vTypeOptsV = ['CCv','F','E']
vTypeOpts = vTypeOptsCC + vTypeOptsV
@@ -534,7 +552,8 @@ class CurvView(object):
def __init__(self):
pass
def plotGrid(self, length=0.05, showIt=False):
def plotGrid(self, ax=None, nodes=False, faces=False, centers=False, edges=False, lines=True, showIt=False):
"""Plot the nodal, cell-centered and staggered grids for 1,2 and 3 dimensions.
@@ -542,60 +561,63 @@ class CurvView(object):
:include-source:
from SimPEG import Mesh, Utils
X, Y = Utils.exampleCurvGird([3,3],'rotate')
X, Y = Utils.exampleLrmGrid([3,3],'rotate')
M = Mesh.CurvilinearMesh([X, Y])
M.plotGrid(showIt=True)
"""
import matplotlib.pyplot as plt
import matplotlib
from mpl_toolkits.mplot3d import Axes3D
axOpts = {'projection':'3d'} if self.dim == 3 else {}
if ax is None: ax = plt.subplot(111, **axOpts)
NN = self.r(self.gridN, 'N', 'N', 'M')
if self.dim == 2:
fig = plt.figure(2)
fig.clf()
ax = plt.subplot(111)
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
if lines:
X1 = np.c_[mkvc(NN[0][:-1, :]), mkvc(NN[0][1:, :]), mkvc(NN[0][:-1, :])*np.nan].flatten()
Y1 = np.c_[mkvc(NN[1][:-1, :]), mkvc(NN[1][1:, :]), mkvc(NN[1][:-1, :])*np.nan].flatten()
X = np.r_[X1, X2]
Y = np.r_[Y1, Y2]
X2 = np.c_[mkvc(NN[0][:, :-1]), mkvc(NN[0][:, 1:]), mkvc(NN[0][:, :-1])*np.nan].flatten()
Y2 = np.c_[mkvc(NN[1][:, :-1]), mkvc(NN[1][:, 1:]), mkvc(NN[1][:, :-1])*np.nan].flatten()
plt.plot(X, Y)
X = np.r_[X1, X2]
Y = np.r_[Y1, Y2]
plt.hold(True)
Nx = self.r(self.normals, 'F', 'Fx', 'V')
Ny = self.r(self.normals, 'F', 'Fy', 'V')
Tx = self.r(self.tangents, 'E', 'Ex', 'V')
Ty = self.r(self.tangents, 'E', 'Ey', 'V')
ax.plot(X, Y, 'b-')
if centers:
ax.plot(self.gridCC[:,0],self.gridCC[:,1],'ro')
plt.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
# Nx = self.r(self.normals, 'F', 'Fx', 'V')
# Ny = self.r(self.normals, 'F', 'Fy', 'V')
# Tx = self.r(self.tangents, 'E', 'Ex', 'V')
# Ty = self.r(self.tangents, 'E', 'Ey', 'V')
nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
plt.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
plt.plot(nX, nY, 'r-')
# ax.plot(self.gridN[:, 0], self.gridN[:, 1], 'bo')
nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
#plt.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
plt.plot(nX, nY, 'g-')
# nX = np.c_[self.gridFx[:, 0], self.gridFx[:, 0] + Nx[0]*length, self.gridFx[:, 0]*np.nan].flatten()
# nY = np.c_[self.gridFx[:, 1], self.gridFx[:, 1] + Nx[1]*length, self.gridFx[:, 1]*np.nan].flatten()
# ax.plot(self.gridFx[:, 0], self.gridFx[:, 1], 'rs')
# ax.plot(nX, nY, 'r-')
tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
plt.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
plt.plot(tX, tY, 'r-')
# nX = np.c_[self.gridFy[:, 0], self.gridFy[:, 0] + Ny[0]*length, self.gridFy[:, 0]*np.nan].flatten()
# nY = np.c_[self.gridFy[:, 1], self.gridFy[:, 1] + Ny[1]*length, self.gridFy[:, 1]*np.nan].flatten()
# #ax.plot(self.gridFy[:, 0], self.gridFy[:, 1], 'gs')
# ax.plot(nX, nY, 'g-')
nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
#plt.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
plt.plot(nX, nY, 'g-')
plt.axis('equal')
# tX = np.c_[self.gridEx[:, 0], self.gridEx[:, 0] + Tx[0]*length, self.gridEx[:, 0]*np.nan].flatten()
# tY = np.c_[self.gridEx[:, 1], self.gridEx[:, 1] + Tx[1]*length, self.gridEx[:, 1]*np.nan].flatten()
# ax.plot(self.gridEx[:, 0], self.gridEx[:, 1], 'r^')
# ax.plot(tX, tY, 'r-')
# nX = np.c_[self.gridEy[:, 0], self.gridEy[:, 0] + Ty[0]*length, self.gridEy[:, 0]*np.nan].flatten()
# nY = np.c_[self.gridEy[:, 1], self.gridEy[:, 1] + Ty[1]*length, self.gridEy[:, 1]*np.nan].flatten()
# #ax.plot(self.gridEy[:, 0], self.gridEy[:, 1], 'g^')
# ax.plot(nX, nY, 'g-')
elif self.dim == 3:
fig = plt.figure(3)
fig.clf()
ax = fig.add_subplot(111, projection='3d')
X1 = np.c_[mkvc(NN[0][:-1, :, :]), mkvc(NN[0][1:, :, :]), mkvc(NN[0][:-1, :, :])*np.nan].flatten()
Y1 = np.c_[mkvc(NN[1][:-1, :, :]), mkvc(NN[1][1:, :, :]), mkvc(NN[1][:-1, :, :])*np.nan].flatten()
Z1 = np.c_[mkvc(NN[2][:-1, :, :]), mkvc(NN[2][1:, :, :]), mkvc(NN[2][:-1, :, :])*np.nan].flatten()
@@ -612,16 +634,50 @@ class CurvView(object):
Y = np.r_[Y1, Y2, Y3]
Z = np.r_[Z1, Z2, Z3]
plt.plot(X, Y, 'b', zs=Z)
ax.plot(X, Y, 'b', zs=Z)
ax.set_zlabel('x3')
ax.grid(True)
ax.hold(False)
ax.set_xlabel('x1')
ax.set_ylabel('x2')
if showIt: plt.show()
def plotImage(self, I, ax=None, showIt=False, grid=False, clim=None):
if self.dim == 3: raise NotImplementedError('This is not yet done!')
import matplotlib.pyplot as plt
import matplotlib
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.colors as colors
import matplotlib.cm as cmx
if ax is None: ax = plt.subplot(111)
jet = cm = plt.get_cmap('jet')
cNorm = colors.Normalize(
vmin=I.min() if clim is None else clim[0],
vmax=I.max() if clim is None else clim[1])
scalarMap = cmx.ScalarMappable(norm=cNorm, cmap=jet)
# ax.set_xlim((self.x0[0], self.h[0].sum()))
# ax.set_ylim((self.x0[1], self.h[1].sum()))
Nx = self.r(self.gridN[:,0],'N','N','M')
Ny = self.r(self.gridN[:,1],'N','N','M')
cell = self.r(I,'CC','CC','M')
for ii in range(self.nCx):
for jj in range(self.nCy):
I = [ii,ii+1,ii+1,ii]
J = [jj,jj,jj+1,jj+1]
ax.add_patch(plt.Polygon(np.c_[Nx[I,J],Ny[I,J]], facecolor=scalarMap.to_rgba(cell[ii,jj]), edgecolor='k' if grid else 'none'))
scalarMap._A = [] # http://stackoverflow.com/questions/8342549/matplotlib-add-colorbar-to-a-sequence-of-line-plots
ax.set_xlabel('x')
ax.set_ylabel('y')
if showIt: plt.show()
return [scalarMap]
if __name__ == '__main__':
from SimPEG import *
@@ -4,18 +4,21 @@ import sys
from numpy.lib import recfunctions as recFunc
from SimPEG.EM.Utils import omega
##############
### Fields ###
##############
class BaseMTFields(Problem.Fields):
"""Field Storage for a MT survey."""
class BaseNSEMFields(Problem.Fields):
"""Field Storage for a NSEM survey."""
knownFields = {}
dtype = complex
class Fields1D_e(BaseMTFields):
###########
# 1D Fields
###########
class Fields1D_ePrimSec(BaseNSEMFields):
"""
Fields storage for the 1D MT solution.
Fields storage for the 1D NSEM solution.
"""
knownFields = {'e_1dSolution':'F'}
aliasFields = {
@@ -28,7 +31,119 @@ class Fields1D_e(BaseMTFields):
}
def __init__(self,mesh,survey,**kwargs):
BaseMTFields.__init__(self,mesh,survey,**kwargs)
BaseNSEMFields.__init__(self,mesh,survey,**kwargs)
def _ePrimary(self, eSolution, srcList):
ePrimary = np.zeros_like(eSolution)
for i, src in enumerate(srcList):
ep = src.ePrimary(self.survey.prob)
if ep is not None:
ePrimary[:,i] = ep[:,-1]
return ePrimary
def _eSecondary(self, eSolution, srcList):
return eSolution
def _e(self, eSolution, srcList):
return self._ePrimary(eSolution,srcList) + self._eSecondary(eSolution,srcList)
def _eDeriv_u(self, src, du_dm_v, adjoint = False):
return Utils.Identity()*du_dm_v
def _eDeriv_m(self, src, v, adjoint = False):
# assuming primary does not depend on the model
return Utils.Zero()
def _bPrimary(self, eSolution, srcList):
bPrimary = np.zeros([self.survey.mesh.nE,eSolution.shape[1]], dtype = complex)
for i, src in enumerate(srcList):
bp = src.bPrimary(self.survey.prob)
if bp is not None:
bPrimary[:,i] += bp[:,-1]
return bPrimary
def _bSecondary(self, eSolution, srcList):
C = self.mesh.nodalGrad
b = (C * eSolution)
for i, src in enumerate(srcList):
b[:,i] *= - 1./(1j*omega(src.freq))
# There is no magnetic source in the MT problem
# S_m, _ = src.eval(self.survey.prob)
# if S_m is not None:
# b[:,i] += 1./(1j*omega(src.freq)) * S_m
return b
def _b(self, eSolution, srcList):
return self._bPrimary(eSolution, srcList) + self._bSecondary(eSolution, srcList)
def _bSecondaryDeriv_u(self, src, v, adjoint = False):
C = self.mesh.nodalGrad
if adjoint:
return - 1./(1j*omega(src.freq)) * (C.T * v)
return - 1./(1j*omega(src.freq)) * (C * v)
def _bSecondaryDeriv_m(self, src, v, adjoint = False):
# Doesn't depend on m
# _, S_eDeriv = src.evalDeriv(self.survey.prob, adjoint)
# S_eDeriv = S_eDeriv(v)
# if S_eDeriv is not None:
# return 1./(1j * omega(src.freq)) * S_eDeriv
return None
def _bDeriv_u(self, src, v, adjoint=False):
# Primary does not depend on u
return self._bSecondaryDeriv_u(src, v, adjoint)
def _bDeriv_m(self, src, v, adjoint=False):
# Assuming the primary does not depend on the model
return self._bSecondaryDeriv_m(src, v, adjoint)
def _fDeriv_u(self, src, v, adjoint=False):
"""
Derivative of the fields object wrt u.
:param NSEMsrc src: NSEM source
:param numpy.ndarray v: random vector of f_sol.size
This function stacks the fields derivatives appropriately
return a vector of size (nreEle+nrbEle)
"""
de_du = v #Utils.spdiag(np.ones((self.nF,)))
db_du = self._bDeriv_u(src, v, adjoint)
# Return the stack
# This doesn't work...
return np.vstack((de_du,db_du))
def _fDeriv_m(self, src, v, adjoint=False):
"""
Derivative of the fields object wrt m.
This function stacks the fields derivatives appropriately
"""
return None
class Fields1D_eTotal(BaseNSEMFields):
"""
Fields storage for the 1D NSEM solution solved with for a total domain formulation.
Used in conjuction with Problem1D_eTotal.
"""
knownFields = {'e_1dSolution':'F'}
aliasFields = {
'e_1d' : ['e_1dSolution','F','_e'],
'e_1dPrimary' : ['e_1dSolution','F','_ePrimary'],
'e_1dSecondary' : ['e_1dSolution','F','_eSecondary'],
'b_1d' : ['e_1dSolution','E','_b'],
'b_1dPrimary' : ['e_1dSolution','E','_bPrimary'],
'b_1dSecondary' : ['e_1dSolution','E','_bSecondary']
}
def __init__(self,mesh,survey,**kwargs):
BaseNSEMFields.__init__(self,mesh,survey,**kwargs)
def _ePrimary(self, eSolution, srcList):
ePrimary = np.zeros_like(eSolution)
@@ -99,7 +214,7 @@ class Fields1D_e(BaseMTFields):
"""
Derivative of the fields object wrt u.
:param MTsrc src: MT source
:param NSEMsrc src: NSEM source
:param numpy.ndarray v: random vector of f_sol.size
This function stacks the fields derivatives appropriately
@@ -120,9 +235,18 @@ class Fields1D_e(BaseMTFields):
"""
return None
class Fields3D_e(BaseMTFields):
###########
# 2D Fields
###########
###########
# 3D Fields
###########
class Fields3D_ePrimSec(BaseNSEMFields):
"""
Fields storage for the 3D MT solution. Labels polarizations by px and py.
Fields storage for the 3D NSEM solution. Labels polarizations by px and py.
:param SimPEG object mesh: The solution mesh
:param SimPEG object survey: A survey object
@@ -147,7 +271,7 @@ class Fields3D_e(BaseMTFields):
}
def __init__(self,mesh,survey,**kwargs):
BaseMTFields.__init__(self,mesh,survey,**kwargs)
BaseNSEMFields.__init__(self,mesh,survey,**kwargs)
def _e_pxPrimary(self, e_pxSolution, srcList):
e_pxPrimary = np.zeros_like(e_pxSolution)
@@ -228,7 +352,7 @@ class Fields3D_e(BaseMTFields):
b = (C * e_pxSolution)
for i, src in enumerate(srcList):
b[:,i] *= - 1./(1j*omega(src.freq))
# There is no magnetic source in the MT problem
# There is no magnetic source in the NSEM problem
# S_m, _ = src.eval(self.survey.prob)
# if S_m is not None:
# b[:,i] += 1./(1j*omega(src.freq)) * S_m
@@ -239,7 +363,7 @@ class Fields3D_e(BaseMTFields):
b = (C * e_pySolution)
for i, src in enumerate(srcList):
b[:,i] *= - 1./(1j*omega(src.freq))
# There is no magnetic source in the MT problem
# There is no magnetic source in the NSEM problem
# S_m, _ = src.eval(self.survey.prob)
# if S_m is not None:
# b[:,i] += 1./(1j*omega(src.freq)) * S_m
@@ -302,7 +426,7 @@ class Fields3D_e(BaseMTFields):
"""
Derivative of the fields object wrt u.
:param MTsrc src: MT source
:param NSEMsrc src: NSEM source
:param numpy.ndarray v: random vector of f_sol.size
This function stacks the fields derivatives appropriately
@@ -319,7 +443,7 @@ class Fields3D_e(BaseMTFields):
"""
Derivative of the fields object wrt u.
:param MTsrc src: MT source
:param NSEMsrc src: NSEM source
:param numpy.ndarray v: random vector of f_sol.size
This function stacks the fields derivatives appropriately
+560
View File
@@ -0,0 +1,560 @@
from SimPEG.EM.Utils.EMUtils import omega, mu_0
from SimPEG import SolverLU as SimpegSolver, PropMaps, Utils, mkvc, sp, np
from SimPEG.EM.FDEM.ProblemFDEM import BaseFDEMProblem
from SurveyNSEM import Survey, Data
from FieldsNSEM import BaseNSEMFields, Fields1D_ePrimSec, Fields3D_ePrimSec
from SimPEG.NSEM.Utils.MT1Danalytic import getEHfields
import time, sys
class BaseNSEMProblem(BaseFDEMProblem):
"""
Base class for all Natural source problems.
"""
def __init__(self, mesh, **kwargs):
BaseFDEMProblem.__init__(self, mesh, **kwargs)
Utils.setKwargs(self, **kwargs)
# Set the default pairs of the problem
surveyPair = Survey
dataPair = Data
fieldsPair = BaseNSEMFields
# Set the solver
Solver = SimpegSolver
solverOpts = {}
verbose = False
# Notes:
# Use the forward and devs from BaseFDEMProblem
# Might need to add more stuff here.
## NEED to clean up the Jvec and Jtvec to use Zero and Identities for None components.
def Jvec(self, m, v, f=None):
"""
Function to calculate the data sensitivities dD/dm times a vector.
:param numpy.ndarray m (nC, 1) - conductive model
:param numpy.ndarray v (nC, 1) - random vector
:param NSEMfields object (optional) - NSEM fields object, if not given it is calculated
:rtype: NSEMdata object
:return: Data sensitivities wrt m
"""
# Calculate the fields
if f is None:
f= self.fields(m)
# Set current model
self.curModel = m
# Initiate the Jv object
Jv = self.dataPair(self.survey)
# Loop all the frequenies
for freq in self.survey.freqs:
dA_du = self.getA(freq) #
dA_duI = self.Solver(dA_du, **self.solverOpts)
for src in self.survey.getSrcByFreq(freq):
# We need fDeriv_m = df/du*du/dm + df/dm
# Construct du/dm, it requires a solve
# NOTE: need to account for the 2 polarizations in the derivatives.
u_src = f[src,:] # u should be a vector by definition. Need to fix this...
# dA_dm and dRHS_dm should be of size nE,2, so that we can multiply by dA_duI. The 2 columns are each of the polarizations.
dA_dm = self.getADeriv_m(freq, u_src, v) # Size: nE,2 (u_px,u_py) in the columns.
dRHS_dm = self.getRHSDeriv_m(freq, v) # Size: nE,2 (u_px,u_py) in the columns.
if dRHS_dm is None:
du_dm = dA_duI * ( -dA_dm )
else:
du_dm = dA_duI * ( -dA_dm + dRHS_dm )
# Calculate the projection derivatives
for rx in src.rxList:
# Get the projection derivative
# v should be of size 2*nE (for 2 polarizations)
PDeriv_u = lambda t: rx.evalDeriv(src, self.mesh, f, t) # wrt u, we don't have have PDeriv wrt m
Jv[src, rx] = PDeriv_u(mkvc(du_dm))
dA_duI.clean()
# Return the vectorized sensitivities
return mkvc(Jv)
def Jtvec(self, m, v, f=None):
"""
Function to calculate the transpose of the data sensitivities (dD/dm)^T times a vector.
:param numpy.ndarray m (nC, 1) - conductive model
:param numpy.ndarray v (nD, 1) - vector
:param NSEMfields object f (optional) - NSEM fields object, if not given it is calculated
:rtype: NSEMdata object
:return: Data sensitivities wrt m
"""
if f is None:
f = self.fields(m)
self.curModel = m
# Ensure v is a data object.
if not isinstance(v, self.dataPair):
v = self.dataPair(self.survey, v)
Jtv = np.zeros(m.size)
for freq in self.survey.freqs:
AT = self.getA(freq).T
ATinv = self.Solver(AT, **self.solverOpts)
for src in self.survey.getSrcByFreq(freq):
ftype = self._solutionType
f_src = f[src, :] # Need to fix this...
for rx in src.rxList:
# Get the adjoint evalDeriv
# PTv needs to be nE,
PTv = rx.evalDeriv(src, self.mesh, f, mkvc(v[src, rx],2), adjoint=True) # wrt u, need possibility wrt m
# Get the
dA_duIT = ATinv * PTv
dA_dmT = self.getADeriv_m(freq, f_src, mkvc(dA_duIT), adjoint=True)
dRHS_dmT = self.getRHSDeriv_m(freq, mkvc(dA_duIT), adjoint=True)
# Make du_dmT
if dRHS_dmT is None:
du_dmT = -dA_dmT
else:
du_dmT = -dA_dmT + dRHS_dmT
# Select the correct component
# du_dmT needs to be of size nC,
real_or_imag = rx.projComp
if real_or_imag == 'real':
Jtv += du_dmT.real
elif real_or_imag == 'imag':
Jtv += -du_dmT.real
else:
raise Exception('Must be real or imag')
# Clean the factorization, clear memory.
ATinv.clean()
return Jtv
###################################
## 1D problems
###################################
class Problem1D_ePrimSec(BaseNSEMProblem):
"""
A NSEM problem soving a e formulation and primary/secondary fields decomposion.
By eliminating the magnetic flux density using
.. math ::
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} \\right)
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
.. math ::
\\left(\mathbf{C}^T \mathbf{M^e_{\mu^{-1}}} \mathbf{C} + i \omega \mathbf{M^f_\sigma}] \mathbf{e}_{s} =& i \omega \mathbf{M^f_{\delta \sigma}} \mathbf{e}_{p}
which we solve for \\\(\\\mathbf{e_s}\\\). The total field \\\mathbf{e}\\ = \\\mathbf{e_p}\\ + \\\mathbf{e_s}\\.
The primary field is estimated from a background model (commonly half space ).
"""
# From FDEMproblem: Used to project the fields. Currently not used for NSEMproblem.
_solutionType = 'e_1dSolution'
_formulation = 'EF'
fieldsPair = Fields1D_ePrimSec
# Initiate properties
_sigmaPrimary = None
def __init__(self, mesh, **kwargs):
BaseNSEMProblem.__init__(self, mesh, **kwargs)
# self._sigmaPrimary = sigmaPrimary
@property
def MeMui(self):
"""
Edge inner product matrix
"""
if getattr(self, '_MeMui', None) is None:
self._MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
return self._MeMui
@property
def MfSigma(self):
"""
Edge inner product matrix
"""
if getattr(self, '_MfSigma', None) is None:
self._MfSigma = self.mesh.getFaceInnerProduct(self.curModel.sigma)
return self._MfSigma
@property
def sigmaPrimary(self):
"""
A background model, use for the calculation of the primary fields.
"""
return self._sigmaPrimary
@sigmaPrimary.setter
def sigmaPrimary(self, val):
# Note: TODO add logic for val, make sure it is the correct size.
self._sigmaPrimary = val
def getA(self, freq):
"""
Function to get the A matrix.
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
"""
# Note: need to use the code above since in the 1D problem I want
# e to live on Faces(nodes) and h on edges(cells). Might need to rethink this
# Possible that _fieldType and _eqLocs can fix this
MeMui = self.MeMui
MfSigma = self.MfSigma
C = self.mesh.nodalGrad
# Make A
A = C.T*MeMui*C + 1j*omega(freq)*MfSigma
# Either return full or only the inner part of A
return A
def getADeriv_m(self, freq, u, v, adjoint=False):
"""
The derivative of A wrt sigma
"""
dsig_dm = self.curModel.sigmaDeriv
MeMui = self.MeMui
#
u_src = u['e_1dSolution']
dMfSigma_dm = self.mesh.getFaceInnerProductDeriv(self.curModel.sigma)(u_src) * self.curModel.sigmaDeriv
if adjoint:
return 1j * omega(freq) * ( dMfSigma_dm.T * v )
# Note: output has to be nN/nF, not nC/nE.
# v should be nC
return 1j * omega(freq) * ( dMfSigma_dm * v )
def getRHS(self, freq):
"""
Function to return the right hand side for the system.
:param float freq: Frequency
:rtype: numpy.ndarray (nF, 1), numpy.ndarray (nF, 1)
:return: RHS for 1 polarizations, primary fields
"""
# Get sources for the frequncy(polarizations)
Src = self.survey.getSrcByFreq(freq)[0]
S_e = Src.S_e(self)
return -1j * omega(freq) * S_e
def getRHSDeriv_m(self, freq, v, adjoint=False):
"""
The derivative of the RHS wrt sigma
"""
Src = self.survey.getSrcByFreq(freq)[0]
S_eDeriv = Src.S_eDeriv_m(self, v, adjoint)
return -1j * omega(freq) * S_eDeriv
def fields(self, m):
'''
Function to calculate all the fields for the model m.
:param np.ndarray (nC,) m: Conductivity model
'''
# Set the current model
self.curModel = m
# Make the fields object
F = self.fieldsPair(self.mesh, self.survey)
# Loop over the frequencies
for freq in self.survey.freqs:
if self.verbose:
startTime = time.time()
print 'Starting work for {:.3e}'.format(freq)
sys.stdout.flush()
A = self.getA(freq)
rhs = self.getRHS(freq)
Ainv = self.Solver(A, **self.solverOpts)
e_s = Ainv * rhs
# Store the fields
Src = self.survey.getSrcByFreq(freq)[0]
# NOTE: only store the e_solution(secondary), all other components calculated in the fields object
F[Src, 'e_1dSolution'] = e_s[:,-1] # Only storing the yx polarization as 1d
# Note curl e = -iwb so b = -curl e /iw
# b = -( self.mesh.nodalGrad * e )/( 1j*omega(freq) )
# F[Src, 'b_1d'] = b[:,1]
if self.verbose:
print 'Ran for {:f} seconds'.format(time.time()-startTime)
sys.stdout.flush()
return F
# Note this is not fully functional.
# Missing:
# Fields class corresponding to the fields
# Update Jvec and Jtvec to include all the derivatives components
# Other things ...
class Problem1D_eTotal(BaseNSEMProblem):
"""
A NSEM problem solving a e formulation and a Total bondary domain decompostion.
Solves the equation:
Math:
Have to do this...
Not implement correctly.......
"""
# From FDEMproblem: Used to project the fields. Currently not used for NSEMproblem.
_solutionType = 'e_1dSolution'
_formulation = 'EF'
# fieldsPair = Fields1D_eTotal
def __init__(self, mesh, **kwargs):
BaseNSEMProblem.__init__(self, mesh, **kwargs)
@property
def MeMui(self):
"""
Edge inner product matrix
"""
if getattr(self, '_MeMui', None) is None:
self._MeMui = self.mesh.getEdgeInnerProduct(1.0/mu_0)
return self._MeMui
@property
def MfSigma(self):
"""
Edge inner product matrix
"""
if getattr(self, '_MfSigma', None) is None:
self._MfSigma = self.mesh.getFaceInnerProduct(self.curModel.sigma)
return self._MfSigma
def getA(self, freq, full=False):
"""
Function to get the A matrix.
:param float freq: Frequency
:param logic full: Return full A or the inner part
:rtype: scipy.sparse.csr_matrix
:return: A
"""
MeMui = self.MeMui
MfSigma = self.MfSigma
# Note: need to use the code above since in the 1D problem I want
# e to live on Faces(nodes) and h on edges(cells). Might need to rethink this
# Possible that _fieldType and _eqLocs can fix this
# MeMui = self.MfMui
# MfSigma = self.MfSigma
C = self.mesh.nodalGrad
# Make A
A = C.T*MeMui*C + 1j*omega(freq)*MfSigma
# Either return full or only the inner part of A
if full:
return A
else:
return A[1:-1,1:-1]
def getADeriv_m(self, freq, u, v, adjoint=False):
raise NotImplementedError('getADeriv is not implemented')
def getRHS(self, freq):
"""
Function to return the right hand side for the system.
:param float freq: Frequency
:rtype: numpy.ndarray (nE, 2), numpy.ndarray (nE, 2)
:return: RHS for both polarizations, primary fields
"""
# Get sources for the frequency
# NOTE: Need to use the source information, doesn't really apply in 1D
src = self.survey.getSrcByFreq(freq)
# Get the full A
A = self.getA(freq,full=True)
# Define the outer part of the solution matrix
Aio = A[1:-1,[0,-1]]
Ed, Eu, Hd, Hu = getEHfields(self.mesh,self.curModel.sigma,freq,self.mesh.vectorNx)
Etot = (Ed + Eu)
sourceAmp = 1.0
Etot = ((Etot/Etot[-1])*sourceAmp) # Scale the fields to be equal to sourceAmp at the top
## Note: The analytic solution is derived with e^iwt
eBC = np.r_[Etot[0],Etot[-1]]
# The right hand side
return -Aio*eBC, eBC
def getRHSderiv_m(self, freq, backSigma, u, v, adjoint=False):
raise NotImplementedError('getRHSDeriv not implemented yet')
return None
def fields(self, m):
'''
Function to calculate all the fields for the model m.
:param np.ndarray (nC,) m: Conductivity model
:param np.ndarray (nC,) m_back: Background conductivity model
'''
self.curModel = m
# RHS, CalcFields = self.getRHS(freq,m_back), self.calcFields
F = Fields1D_eTotal(self.mesh, self.survey)
for freq in self.survey.freqs:
if self.verbose:
startTime = time.time()
print 'Starting work for {:.3e}'.format(freq)
sys.stdout.flush()
A = self.getA(freq)
rhs, e_o = self.getRHS(freq)
Ainv = self.Solver(A, **self.solverOpts)
e_i = Ainv * rhs
e = mkvc(np.r_[e_o[0], e_i, e_o[1]],2)
# Store the fields
Src = self.survey.getSrcByFreq(freq)
# NOTE: only store e fields
F[Src, 'e_1dSolution'] = e[:,0]
if self.verbose:
print 'Ran for {:f} seconds'.format(time.time()-startTime)
sys.stdout.flush()
return F
###################################
## 3D problems
###################################
class Problem3D_ePrimSec(BaseNSEMProblem):
"""
A NSEM problem solving a e formulation and a primary/secondary fields decompostion.
By eliminating the magnetic flux density using
.. math ::
\mathbf{b} = \\frac{1}{i \omega}\\left(-\mathbf{C} \mathbf{e} \\right)
we can write Maxwell's equations as a second order system in \\\(\\\mathbf{e}\\\) only:
.. math ::
\\left(\mathbf{C}^T \mathbf{M^f_{\mu^{-1}}} \mathbf{C} + i \omega \mathbf{M^e_\sigma}] \mathbf{e}_{s} =& i \omega \mathbf{M^e_{\delta \sigma}} \mathbf{e}_{p}
which we solve for \\\(\\\mathbf{e_s}\\\). The total field \\\mathbf{e}\\ = \\\mathbf{e_p}\\ + \\\mathbf{e_s}\\.
The primary field is estimated from a background model (commonly as a 1D model).
"""
# From FDEMproblem: Used to project the fields. Currently not used for NSEMproblem.
_solutionType = [ 'e_pxSolution', 'e_pySolution'] # Forces order on the object
_formulation = 'EB'
fieldsPair = Fields3D_ePrimSec
# Initiate properties
_sigmaPrimary = None
def __init__(self, mesh, **kwargs):
BaseNSEMProblem.__init__(self, mesh, **kwargs)
@property
def sigmaPrimary(self):
"""
A background model, use for the calculation of the primary fields.
"""
return self._sigmaPrimary
@sigmaPrimary.setter
def sigmaPrimary(self, val):
# Note: TODO add logic for val, make sure it is the correct size.
self._sigmaPrimary = val
def getA(self, freq):
"""
Function to get the A system.
:param float freq: Frequency
:rtype: scipy.sparse.csr_matrix
:return: A
"""
Mmui = self.MfMui
Msig = self.MeSigma
C = self.mesh.edgeCurl
return C.T*Mmui*C + 1j*omega(freq)*Msig
def getADeriv_m(self, freq, u, v, adjoint=False):
"""
Calculate the derivative of A wrt m.
"""
# Fix u to be a matrix nE,2
# This considers both polarizations and returns a nE,2 matrix for each polarization
if adjoint:
dMe_dsigV = sp.hstack(( self.MeSigmaDeriv( u['e_pxSolution'] ).T, self.MeSigmaDeriv(u['e_pySolution'] ).T ))*v
else:
# Need a nE,2 matrix to be returned
dMe_dsigV = np.hstack(( mkvc(self.MeSigmaDeriv( u['e_pxSolution'] )*v,2), mkvc( self.MeSigmaDeriv(u['e_pySolution'] )*v,2) ))
return 1j * omega(freq) * dMe_dsigV
def getRHS(self, freq):
"""
Function to return the right hand side for the system.
:param float freq: Frequency
:rtype: numpy.ndarray (nE, 2), numpy.ndarray (nE, 2)
:return: RHS for both polarizations, primary fields
"""
# Get sources for the frequncy(polarizations)
Src = self.survey.getSrcByFreq(freq)[0]
S_e = Src.S_e(self)
return -1j * omega(freq) * S_e
def getRHSDeriv_m(self, freq, v, adjoint=False):
"""
The derivative of the RHS with respect to sigma
"""
Src = self.survey.getSrcByFreq(freq)[0]
S_eDeriv = Src.S_eDeriv_m(self, v, adjoint)
return -1j * omega(freq) * S_eDeriv
def fields(self, m):
'''
Function to calculate all the fields for the model m.
:param np.ndarray (nC,) m: Conductivity model
'''
# Set the current model
self.curModel = m
F = self.fieldsPair(self.mesh, self.survey)
for freq in self.survey.freqs:
if self.verbose:
startTime = time.time()
print 'Starting work for {:.3e}'.format(freq)
sys.stdout.flush()
A = self.getA(freq)
rhs = self.getRHS(freq)
# Solve the system
Ainv = self.Solver(A, **self.solverOpts)
e_s = Ainv * rhs
# Store the fields
Src = self.survey.getSrcByFreq(freq)[0]
# Store the fields
# Use self._solutionType
F[Src, 'e_pxSolution'] = e_s[:,0]
F[Src, 'e_pySolution'] = e_s[:,1]
# Note curl e = -iwb so b = -curl/iw
if self.verbose:
print 'Ran for {:f} seconds'.format(time.time()-startTime)
sys.stdout.flush()
Ainv.clean()
return F
+13 -13
View File
@@ -11,9 +11,9 @@ import sys
### Sources ###
#################
class BaseMTSrc(FDEMBaseSrc):
class BaseNSEMSrc(FDEMBaseSrc):
'''
Sources for the MT problem.
Sources for the NSEM problem.
Use the SimPEG BaseSrc, since the source fields share properties with the transmitters.
:param float freq: The frequency of the source
@@ -29,28 +29,28 @@ class BaseMTSrc(FDEMBaseSrc):
FDEMBaseSrc.__init__(self, rxList)
# 1D sources
class polxy_1DhomotD(BaseMTSrc):
class polxy_1DhomotD(BaseNSEMSrc):
"""
MT source for both polarizations (x and y) for the total Domain.
NSEM source for both polarizations (x and y) for the total Domain.
It calculates fields calculated based on conditions on the boundary of the domain.
"""
def __init__(self, rxList, freq):
BaseMTSrc.__init__(self, rxList, freq)
BaseNSEMSrc.__init__(self, rxList, freq)
# TODO: need to add the primary fields calc and source terms into the problem.
# Need to implement such that it works for all dims.
class polxy_1Dprimary(BaseMTSrc):
class polxy_1Dprimary(BaseNSEMSrc):
"""
MT source for both polarizations (x and y) given a 1D primary models.
NSEM source for both polarizations (x and y) given a 1D primary models.
It assigns fields calculated from the 1D model as fields in the full space of the problem.
"""
def __init__(self, rxList, freq):
# assert mkvc(self.mesh.hz.shape,1) == mkvc(sigma1d.shape,1),'The number of values in the 1D background model does not match the number of vertical cells (hz).'
self.sigma1d = None
BaseMTSrc.__init__(self, rxList, freq)
BaseNSEMSrc.__init__(self, rxList, freq)
# Hidden property of the ePrimary
self._ePrimary = None
@@ -86,7 +86,7 @@ class polxy_1Dprimary(BaseMTSrc):
Get the electrical field source
"""
e_p = self.ePrimary(problem)
Map_sigma_p = Maps.Vertical1DMap(problem.mesh)
Map_sigma_p = Maps.SurjectVertical1D(problem.mesh)
sigma_p = Map_sigma_p._transform(self.sigma1d)
# Make mass matrix
# Note: M(sig) - M(sig_p) = M(sig - sig_p)
@@ -128,15 +128,15 @@ class polxy_1Dprimary(BaseMTSrc):
# v should be nC size
return MsigmaDeriv * v
class polxy_3Dprimary(BaseMTSrc):
class polxy_3Dprimary(BaseNSEMSrc):
"""
MT source for both polarizations (x and y) given a 3D primary model. It assigns fields calculated from the 1D model
NSEM source for both polarizations (x and y) given a 3D primary model. It assigns fields calculated from the 1D model
as fields in the full space of the problem.
"""
def __init__(self, rxList, freq):
# assert mkvc(self.mesh.hz.shape,1) == mkvc(sigma1d.shape,1),'The number of values in the 1D background model does not match the number of vertical cells (hz).'
self.sigmaPrimary = None
BaseMTSrc.__init__(self, rxList, freq)
BaseNSEMSrc.__init__(self, rxList, freq)
# Hidden property of the ePrimary
self._ePrimary = None
@@ -163,7 +163,7 @@ class polxy_3Dprimary(BaseMTSrc):
Get the electrical field source
"""
e_p = self.ePrimary(problem)
Map_sigma_p = Maps.Vertical1DMap(problem.mesh)
Map_sigma_p = Maps.SurjectVertical1D(problem.mesh)
sigma_p = Map_sigma_p._transform(self.sigma1d)
# Make mass matrix
# Note: M(sig) - M(sig_p) = M(sig - sig_p)
@@ -4,7 +4,7 @@ from SimPEG.EM.Utils import omega
from scipy.constants import mu_0
from numpy.lib import recfunctions as recFunc
from Utils import rec2ndarr
import SrcMT
import SrcNSEM
import sys
#################
@@ -63,9 +63,9 @@ class Rx(SimPEGsurvey.BaseRx):
'''
Project the fields to natural source data.
:param SrcMT src: The source of the fields to project
:param SrcNSEM src: The source of the fields to project
:param SimPEG.Mesh mesh:
:param FieldsMT f: Natural source fields object to project
:param FieldsNSEM f: Natural source fields object to project
'''
## NOTE: Assumes that e is on t
@@ -143,9 +143,9 @@ class Rx(SimPEGsurvey.BaseRx):
"""
The derivative of the projection wrt u
:param MTsrc src: MT source
:param NSEMsrc src: NSEM source
:param TensorMesh mesh: Mesh defining the topology of the problem
:param MTfields f: MT fields object of the source
:param NSEMfields f: NSEM fields object of the source
:param numpy.ndarray v: Random vector of size
"""
@@ -390,12 +390,12 @@ class Rx(SimPEGsurvey.BaseRx):
#################
class Survey(SimPEGsurvey.BaseSurvey):
"""
Survey class for MT. Contains all the sources associated with the survey.
Survey class for NSEM. Contains all the sources associated with the survey.
:param list srcList: List of sources associated with the survey
"""
srcPair = SrcMT.BaseMTSrc
srcPair = SrcNSEM.BaseNSEMSrc
def __init__(self, srcList, **kwargs):
# Sort these by frequency
@@ -443,7 +443,7 @@ class Survey(SimPEGsurvey.BaseSurvey):
#################
class Data(SimPEGsurvey.Data):
'''
Data class for MTdata. Stores the data vector indexed by the survey.
Data class for NSEMdata. Stores the data vector indexed by the survey.
:param SimPEG survey object survey:
:param v vector of the data in order matching of the survey
@@ -461,7 +461,7 @@ class Data(SimPEGsurvey.Data):
def toRecArray(self,returnType='RealImag'):
'''
Function that returns a numpy.recarray for a SimpegMT impedance data object.
Function that returns a numpy.recarray for a SimpegNSEM impedance data object.
:param str returnType: Switches between returning a rec array where the impedance is split to real and imaginary ('RealImag') or is a complex ('Complex')
@@ -483,7 +483,7 @@ class Data(SimPEGsurvey.Data):
locs = np.hstack((np.array([[0.0]]),locs))
tArrRec = np.concatenate((src.freq*np.ones((locs.shape[0],1)),locs,np.nan*np.ones((locs.shape[0],12))),axis=1).view(dtRI)
# np.array([(src.freq,rx.locs[0,0],rx.locs[0,1],rx.locs[0,2],np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ,np.nan ) for rx in src.rxList],dtype=dtRI)
# Get the type and the value for the DataMT object as a list
# Get the type and the value for the DataNSEM object as a list
typeList = [[rx.rxType.replace('z1d','zyx'),self[src,rx]] for rx in src.rxList]
# Insert the values to the temp array
for nr,(key,val) in enumerate(typeList):
@@ -517,17 +517,17 @@ class Data(SimPEGsurvey.Data):
@classmethod
def fromRecArray(cls, recArray, srcType='primary'):
"""
Class method that reads in a numpy record array to MTdata object.
Class method that reads in a numpy record array to NSEMdata object.
Only imports the impedance data.
"""
if srcType=='primary':
src = SrcMT.polxy_1Dprimary
src = SrcNSEM.polxy_1Dprimary
elif srcType=='total':
src = SrcMT.polxy_1DhomotD
src = SrcNSEM.polxy_1DhomotD
else:
raise NotImplementedError('{:s} is not a valid source type for MTdata')
raise NotImplementedError('{:s} is not a valid source type for NSEMdata')
# Find all the frequencies in recArray
uniFreq = np.unique(recArray['freq'])
@@ -3,7 +3,7 @@
import numpy as np, SimPEG as simpeg
from scipy.constants import mu_0, epsilon_0 as eps_0
def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
def getEHfields(m1d,sigma,freq,zd,scaleUD=True,scaleValue=1):
'''Analytic solution for MT 1D layered earth. Returns E and H fields.
:param SimPEG.mesh, object m1d: Mesh object with the 1D spatial information.
@@ -12,7 +12,7 @@ def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
:param numpy array, vector zd: location to calculate EH fields at
:param bollean, scaleUD: scales the output to be 1 at the top, increases numeracal stability.
Assumes a halfspace with the same conductive as the last cell below.
Assumes a halfspace with the same conductive as the deepest cell.
'''
# Note add an error check for the mesh and sigma are the same size.
@@ -29,7 +29,7 @@ def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
# Initiate the propagation matrix, in the order down up.
UDp = np.zeros((2,m1d.nC+1),dtype=complex)
UDp[1,0] = 1. # Set the wave amplitude as 1 into the half-space at the bottom of the mesh
UDp[1,0] = scaleValue # Set the wave amplitude as 1 into the half-space at the bottom of the mesh
# Loop over all the layers, starting at the bottom layer
for lnr, h in enumerate(m1d.hx): # lnr-number of layer, h-thickness of the layer
# Calculate
@@ -38,9 +38,9 @@ def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
# Build the propagation matrix
# Convert fields to down/up going components in layer below current layer
Pj1 = np.array([[1,1],[yp1,-yp1]])
Pj1 = np.array([[1,1],[yp1,-yp1]],dtype=complex)
# Convert fields to down/up going components in current layer
Pjinv = 1./2*np.array([[1,zp],[1,-zp]])
Pjinv = 1./2*np.array([[1,zp],[1,-zp]],dtype=complex)
# Propagate down and up components through the current layer
elamh = np.array([[np.exp(-1j*k[lnr+1]*h),0],[0,np.exp(1j*k[lnr+1]*h)]])
@@ -48,7 +48,14 @@ def getEHfields(m1d,sigma,freq,zd,scaleUD=True):
UDp[:,lnr+1] = elamh.dot(Pjinv.dot(Pj1)).dot(UDp[:,lnr])
if scaleUD:
UDp[:,lnr+1::-1] = UDp[:,lnr+1::-1]/UDp[1,lnr+1]
# Scale the values such that 1 at the top
scaleVal = UDp[:,lnr+1::-1]/UDp[1,lnr+1]
if np.any(np.isnan(scaleVal)):
# If there is a nan (thickness very great), rebuild the move up cell
scaleVal = np.zeros_like(UDp[:,lnr+1::-1],dtype=complex)
scaleVal[1,0] = scaleValue
UDp[:,lnr+1::-1] = scaleVal
# Calculate the fields
Ed = np.empty((zd.size,),dtype=complex)
+5
View File
@@ -0,0 +1,5 @@
from MT1Dsolutions import get1DEfields # Add the names of the functions
from MT1Danalytic import getEHfields, getImpedance
from dataUtils import *
from ediFilesUtils import *
from testUtils import *
@@ -5,25 +5,25 @@ import numpy.lib.recfunctions as recFunc
from scipy.constants import mu_0
from scipy import interpolate as sciint
def getAppRes(MTdata):
def getAppRes(NSEMdata):
# Make impedance
zList = []
for src in MTdata.survey.srcList:
for src in NSEMdata.survey.srcList:
zc = [src.freq]
for rx in src.rxList:
if 'i' in rx.rxType:
m=1j
else:
m = 1
zc.append(m*MTdata[src,rx])
zc.append(m*NSEMdata[src,rx])
zList.append(zc)
return [appResPhs(zList[i][0],np.sum(zList[i][1:3])) for i in np.arange(len(zList))]
def rotateData(MTdata,rotAngle):
def rotateData(NSEMdata,rotAngle):
'''
Function that rotates clockwist by rotAngle (- negative for a counter-clockwise rotation)
'''
recData = MTdata.toRecArray('Complex')
recData = NSEMdata.toRecArray('Complex')
impData = rec2ndarr(recData[['zxx','zxy','zyx','zyy']],complex)
# Make the rotation matrix
# c,s,zxx,zxy,zyx,zyy = sympy.symbols('c,s,zxx,zxy,zyx,zyy')
@@ -40,8 +40,8 @@ def rotateData(MTdata,rotAngle):
for nr,comp in enumerate(['zxx','zxy','zyx','zyy']):
outRec[comp] = rotData[:,nr]
from SimPEG import MT
return MT.Data.fromRecArray(outRec)
from SimPEG import NSEM
return NSEM.Data.fromRecArray(outRec)
def appResPhs(freq,z):
@@ -57,10 +57,10 @@ def rec2ndarr(x,dt=float):
return x.view((dt, len(x.dtype.names)))
def makeAnalyticSolution(mesh,model,elev,freqs):
from SimPEG import MT
from SimPEG import NSEM
data1D = []
for freq in freqs:
anaEd, anaEu, anaHd, anaHu = MT.Utils.MT1Danalytic.getEHfields(mesh,model,freq,elev)
anaEd, anaEu, anaHd, anaHu = NSEM.Utils.MT1Danalytic.getEHfields(mesh,model,freq,elev)
anaE = anaEd+anaEu
anaH = anaHd+anaHu
@@ -71,7 +71,7 @@ def makeAnalyticSolution(mesh,model,elev,freqs):
return dataRec
def plotMT1DModelData(problem,models,symList=None):
from SimPEG import MT
from SimPEG import NSEM
# Setup the figure
fontSize = 15
@@ -79,7 +79,7 @@ def plotMT1DModelData(problem,models,symList=None):
axM = fig.add_axes([0.075,.1,.25,.875])
axM.set_xlabel('Resistivity [Ohm*m]',fontsize=fontSize)
axM.set_xlim(1e-1,1e5)
axM.set_ylim(-10000,5000)
# axM.set_ylim(-10000,5000)
axM.set_ylabel('Depth [km]',fontsize=fontSize)
axR = fig.add_axes([0.42,.575,.5,.4])
axR.set_xscale('log')
@@ -132,38 +132,94 @@ def plotMT1DModelData(problem,models,symList=None):
freq = simpeg.mkvc(data1D['freq'],2)
res, phs = appResPhs(freq,allData)
stdCol = 'gray'
axRtw = axR.twinx()
axRtw.set_ylabel('Std of log10',color=stdCol)
[(t.set_color(stdCol), t.set_rotation(-45)) for t in axRtw.get_yticklabels()]
axPtw = axP.twinx()
axPtw.set_ylabel('Std ',color=stdCol)
[t.set_color(stdCol) for t in axPtw.get_yticklabels()]
axRtw.plot(freq, np.std(np.log10(res),1),'--',color=stdCol)
axPtw.plot(freq, np.std(phs,1),'--',color=stdCol)
if False:
stdCol = 'gray'
axRtw = axR.twinx()
axRtw.set_ylabel('Std of log10',color=stdCol)
[(t.set_color(stdCol), t.set_rotation(-45)) for t in axRtw.get_yticklabels()]
axPtw = axP.twinx()
axPtw.set_ylabel('Std ',color=stdCol)
[t.set_color(stdCol) for t in axPtw.get_yticklabels()]
axRtw.plot(freq, np.std(np.log10(res),1),'--',color=stdCol)
axPtw.plot(freq, np.std(phs,1),'--',color=stdCol)
# Fix labels and ticks
yMtick = [l/1000 for l in axM.get_yticks().tolist()]
axM.set_yticklabels(yMtick)
# yMtick = [l/1000 for l in axM.get_yticks().tolist()]
# axM.set_yticklabels(yMtick)
[ l.set_rotation(90) for l in axM.get_yticklabels()]
[ l.set_rotation(90) for l in axR.get_yticklabels()]
[(t.set_color(stdCol), t.set_rotation(-45)) for t in axRtw.get_yticklabels()]
[t.set_color(stdCol) for t in axPtw.get_yticklabels()]
# [(t.set_color(stdCol), t.set_rotation(-45)) for t in axRtw.get_yticklabels()]
# [t.set_color(stdCol) for t in axPtw.get_yticklabels()]
for ax in [axM,axR,axP]:
ax.xaxis.set_tick_params(labelsize=fontSize)
ax.yaxis.set_tick_params(labelsize=fontSize)
return fig
def plotImpAppRes(dataArrays,plotLoc,textStr=[]):
''' Plots amplitude impedance and phase'''
# fig = plt.figure(1,(7, 7))
import plotDataTypes as pDt
# axes = ImageGrid(fig, (0.05,0.05,0.875,0.875),nrows_ncols = (2, 2),axes_pad = 0.25,add_all=True,share_all=True,label_mode = "L")
# Make the figure and axes
fig,axT=plt.subplots(2,2,sharex=True)
axes = axT.ravel()
fig.set_size_inches((13.5,7.0))
fig.suptitle('{:s}\nStation at: {:.1f}x ; {:.1f}y'.format(textStr,plotLoc[0],plotLoc[1]))
# Have to deal with axes
# Set log
for ax in axes.ravel():
ax.set_xscale('log')
axes[0].invert_xaxis()
axes[0].set_yscale('log')
axes[2].set_yscale('log')
# Set labels
axes[2].set_xlabel('Frequency [Hz]')
axes[3].set_xlabel('Frequency [Hz]')
axes[0].set_ylabel('Apperent resistivity [Ohm m]')
axes[1].set_ylabel('Apperent phase [degrees]')
axes[1].set_ylim(-180,180)
axes[2].set_ylabel('Impedance amplitude [V/A]')
axes[3].set_ylim(-180,180)
axes[3].set_ylabel('Impedance angle [degrees]')
# Plot the data
for nr,dataArray in enumerate(dataArrays):
if nr==1:
parSym = '*'
else:
parSym = 's'
# app res
pDt.plotIsoStaImpedance(axes[0],plotLoc,dataArray,'zxy',par='res',pSym=parSym)
pDt.plotIsoStaImpedance(axes[0],plotLoc,dataArray,'zyx',par='res',pSym=parSym)
# app phs
pDt.plotIsoStaImpedance(axes[1],plotLoc,dataArray,'zxy',par='phs',pSym=parSym)
pDt.plotIsoStaImpedance(axes[1],plotLoc,dataArray,'zyx',par='phs',pSym=parSym)
# imp abs
pDt.plotIsoStaImpedance(axes[2],plotLoc,dataArray,'zxx',par='abs',pSym=parSym)
pDt.plotIsoStaImpedance(axes[2],plotLoc,dataArray,'zxy',par='abs',pSym=parSym)
pDt.plotIsoStaImpedance(axes[2],plotLoc,dataArray,'zyx',par='abs',pSym=parSym)
pDt.plotIsoStaImpedance(axes[2],plotLoc,dataArray,'zyy',par='abs',pSym=parSym)
# imp abs
pDt.plotIsoStaImpedance(axes[3],plotLoc,dataArray,'zxx',par='phs',pSym=parSym)
pDt.plotIsoStaImpedance(axes[3],plotLoc,dataArray,'zxy',par='phs',pSym=parSym)
pDt.plotIsoStaImpedance(axes[3],plotLoc,dataArray,'zyx',par='phs',pSym=parSym)
pDt.plotIsoStaImpedance(axes[3],plotLoc,dataArray,'zyy',par='phs',pSym=parSym)
return fig,axes
def printTime():
import time
print time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())
def convert3Dto1Dobject(MTdata,rxType3D='zyx'):
from SimPEG import MT
def convert3Dto1Dobject(NSEMdata,rxType3D='zyx'):
from SimPEG import NSEM
# Find the unique locations
# Need to find the locations
recDataTemp = MTdata.toRecArray()
recDataTemp = NSEMdata.toRecArray()
# Check if survey.std has been assigned.
## NEED TO: write this...
# Calculte and add the DET of the tensor to the recArray
@@ -185,24 +241,24 @@ def convert3Dto1Dobject(MTdata,rxType3D='zyx'):
# Make the receiver list
rx1DList = []
for rxType in ['z1dr','z1di']:
rx1DList.append(MT.Rx(simpeg.mkvc(loc,2).T,rxType))
rx1DList.append(NSEM.Rx(simpeg.mkvc(loc,2).T,rxType))
# Source list
locrecData = recData[np.sqrt(np.sum( (rec2ndarr(recData[['x','y','z']]).data - loc )**2,axis=1)) < 1e-5]
dat1DList = []
src1DList = []
for freq in locrecData['freq']:
src1DList.append(MT.SrcMT.src_polxy_1Dprimary(rx1DList,freq))
src1DList.append(NSEM.SrcNSEM.src_polxy_1Dprimary(rx1DList,freq))
for comp in ['r','i']:
dat1DList.append( corr * locrecData[rxType3D+comp][locrecData['freq']== freq].data )
# Make the survey
sur1D = MT.Survey(src1DList)
sur1D = NSEM.Survey(src1DList)
# Make the data
dataVec = np.hstack(dat1DList)
dat1D = MT.Data(sur1D,dataVec)
dat1D = NSEM.Data(sur1D,dataVec)
sur1D.dobs = dataVec
# Need to take MTdata.survey.std and split it as well.
# Need to take NSEMdata.survey.std and split it as well.
std=0.05
sur1D.std = np.abs(sur1D.dobs*std) #+ 0.01*np.linalg.norm(sur1D.dobs)
mtData1DList.append(dat1D)
@@ -210,29 +266,29 @@ def convert3Dto1Dobject(MTdata,rxType3D='zyx'):
# Return the the list of data.
return mtData1DList
def resampleMTdataAtFreq(MTdata,freqs):
def resampleNSEMdataAtFreq(NSEMdata,freqs):
"""
Function to resample MTdata at set of frequencies
Function to resample NSEMdata at set of frequencies
"""
from SimPEG import MT
from SimPEG import NSEM
# Make a rec array
MTrec = MTdata.toRecArray().data
NSEMrec = NSEMdata.toRecArray().data
# Find unique locations
uniLoc = np.unique(MTrec[['x','y','z']])
uniFreq = MTdata.survey.freqs
uniLoc = np.unique(NSEMrec[['x','y','z']])
uniFreq = NSEMdata.survey.freqs
# Get the comps
dNames = MTrec.dtype
dNames = NSEMrec.dtype
# Loop over all the locations and interpolate
for loc in uniLoc:
# Find the index of the station
ind = np.sqrt(np.sum((rec2ndarr(MTrec[['x','y','z']]) - rec2ndarr(loc))**2,axis=1)) < 1. # Find dist of 1 m accuracy
ind = np.sqrt(np.sum((rec2ndarr(NSEMrec[['x','y','z']]) - rec2ndarr(loc))**2,axis=1)) < 1. # Find dist of 1 m accuracy
# Make a temporary recArray and interpolate all the components
tArrRec = np.concatenate((simpeg.mkvc(freqs,2),np.ones((len(freqs),1))*rec2ndarr(loc),np.nan*np.ones((len(freqs),12))),axis=1).view(dNames)
for comp in ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi','tzxr','tzxi','tzyr','tzyi']:
int1d = sciint.interp1d(MTrec[ind]['freq'],MTrec[ind][comp],bounds_error=False)
int1d = sciint.interp1d(NSEMrec[ind]['freq'],NSEMrec[ind][comp],bounds_error=False)
tArrRec[comp] = simpeg.mkvc(int1d(freqs),2)
# Join together
@@ -241,5 +297,5 @@ def resampleMTdataAtFreq(MTdata,freqs):
except NameError as e:
outRecArr = tArrRec
# Make the MTdata and return
return MT.Data.fromRecArray(outRecArr)
# Make the NSEMdata and return
return NSEM.Data.fromRecArray(outRecArr)
@@ -2,22 +2,21 @@
from SimPEG import mkvc
from scipy.constants import mu_0
from numpy.lib import recfunctions as recFunc
from SimPEG.MT.Utils.dataUtils import rec2ndarr
from SimPEG.NSEM.Utils.dataUtils import rec2ndarr
# Import modules
import numpy as np
import os, sys, re
try:
import osr
except ImportError as e:
print 'Could not import osr, missing the gdal package'
pass
class EDIimporter:
"""
A class to import EDIfiles.
"""
# Define data converters
_impUnitEDI2SI = 4*np.pi*1e-4 # Convert Z[mV/km/nT] (as in EDI)to Z[V/A] SI unit
_impUnitSI2EDI = 1./_impUnitEDI2SI # ConvertZ[V/A] SI unit to Z[mV/km/nT] (as in EDI)
@@ -26,8 +25,8 @@ class EDIimporter:
comps = None
# Hidden properties
_outEPSG = None
_2out = None
_outEPSG = None # Project info
_2out = None # The projection operator
def __init__(self, EDIfilesList, compList=None, outEPSG=None):
@@ -113,6 +112,12 @@ class EDIimporter:
# nOutData=length(obj.data);
# obj.data(nOutData+1:nOutData+length(TEMP.data),:) = TEMP.data;
def _transfromPoints(self,longD,latD):
# Import the coordinate projections
try:
import osr
except ImportError as e:
print 'Could not import osr, missing the gdal package\nCan not project coordinates'
raise e
# Coordinates convertor
if self._2out is None:
src = osr.SpatialReference()
@@ -12,7 +12,7 @@ def homo1DModelSource(mesh,freq,sigma_1d):
'''
# import
from SimPEG.MT.Utils import get1DEfields
from SimPEG.NSEM.Utils import get1DEfields
# Get a 1d solution for a halfspace background
if mesh.dim == 1:
mesh1d = mesh
@@ -77,7 +77,7 @@ def analytic1DModelSource(mesh,freq,sigma_1d):
'''
# import
from SimPEG.MT.Utils import getEHfields
from SimPEG.NSEM.Utils import getEHfields
# Get a 1d solution for a halfspace background
if mesh.dim == 1:
mesh1d = mesh
+198
View File
@@ -0,0 +1,198 @@
import unittest
import sys
from scipy.constants import mu_0
import SimPEG as simpeg
from SimPEG.Utils import meshTensor
import numpy as np
np.random.seed(1100)
# Define the tolerances
TOLr = 5e-2
TOLp = 5e-2
def getAppResPhs(NSEMdata):
# Make impedance
from SimPEG.NSEM.Utils import appResPhs
zList = []
for src in NSEMdata.survey.srcList:
zc = [src.freq]
for rx in src.rxList:
if 'i' in rx.rxType:
m=1j
else:
m = 1
zc.append(m*NSEMdata[src,rx])
zList.append(zc)
return [appResPhs(zList[i][0],np.sum(zList[i][1:3])) for i in np.arange(len(zList))]
def setup1DSurvey(sigmaHalf,tD=True,structure=False):
from SimPEG import NSEM
# Frequency
nFreq = 33
freqs = np.logspace(3,-3,nFreq)
# Make the mesh
ct = 5
air = meshTensor([(ct,25,1.3)])
# coreT0 = meshTensor([(ct,15,1.2)])
# coreT1 = np.kron(meshTensor([(coreT0[-1],15,1.3)]),np.ones((7,)))
core = np.concatenate( ( np.kron(meshTensor([(ct,15,-1.2)]),np.ones((10,))) , meshTensor([(ct,20)]) ) )
bot = meshTensor([(core[0],20,-1.3)])
x0 = -np.array([np.sum(np.concatenate((core,bot)))])
m1d = simpeg.Mesh.TensorMesh([np.concatenate((bot,core,air))], x0=x0)
# Make the model
sigma = np.zeros(m1d.nC) + sigmaHalf
sigma[m1d.gridCC > 0 ] = 1e-8
sigmaBack = sigma.copy()
# Add structure
if structure:
shallow = (m1d.gridCC < -200) * (m1d.gridCC > -600)
deep = (m1d.gridCC < -3000) * (m1d.gridCC > -5000)
sigma[shallow] = 1
sigma[deep] = 0.1
rxList = []
for rxType in ['z1dr','z1di']:
rxList.append(NSEM.Rx(simpeg.mkvc(np.array([0.0]),2).T,rxType))
# Source list
srcList =[]
if tD:
for freq in freqs:
srcList.append(NSEM.SrcNSEM.polxy_1DhomotD(rxList,freq))
else:
for freq in freqs:
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,freq))
survey = NSEM.Survey(srcList)
return survey, sigma, m1d
def setupSimpegNSEM_ePrimSec(inputSetup,comp='Imp',singleFreq=False,expMap=True):
from SimPEG import NSEM
M,freqs,sig,sigBG,rx_loc = inputSetup
# Make a receiver list
rxList = []
if comp == 'All':
for rxType in ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi','tzxr','tzxi','tzyr','tzyi']:
rxList.append(NSEM.Rx(rx_loc,rxType))
elif comp == 'Imp':
for rxType in ['zxxr','zxxi','zxyr','zxyi','zyxr','zyxi','zyyr','zyyi']:
rxList.append(NSEM.Rx(rx_loc,rxType))
elif comp == 'Tip':
for rxType in ['tzxr','tzxi','tzyr','tzyi']:
rxList.append(NSEM.Rx(rx_loc,rxType))
else:
rxList.append(NSEM.Rx(rx_loc,comp))
# Source list
srcList =[]
if singleFreq:
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,singleFreq))
else:
for freq in freqs:
srcList.append(NSEM.SrcNSEM.polxy_1Dprimary(rxList,freq))
# Survey NSEM
survey = NSEM.Survey(srcList)
## Setup the problem object
sigma1d = M.r(sigBG,'CC','CC','M')[0,0,:]
if expMap:
problem = NSEM.Problem3D_ePrimSec(M,sigmaPrimary= np.log(sigma1d) )
problem.mapping = simpeg.Maps.ExpMap(problem.mesh)
problem.curModel = np.log(sig)
else:
problem = NSEM.Problem3D_ePrimSec(M,sigmaPrimary= sigma1d)
problem.curModel = sig
problem.pair(survey)
problem.verbose = False
try:
from pymatsolver import MumpsSolver
problem.Solver = MumpsSolver
except:
pass
return (survey, problem)
def getInputs():
"""
Function that returns Mesh, freqs, rx_loc, elev.
"""
# Make a mesh
# M = simpeg.Mesh.TensorMesh([[(100,5,-1.5),(100.,10),(100,5,1.5)],[(100,5,-1.5),(100.,10),(100,5,1.5)],[(100,5,1.6),(100.,10),(100,3,2)]], x0=['C','C',-3529.5360])
# M = simpeg.Mesh.TensorMesh([[(1000,6,-1.5),(1000.,6),(1000,6,1.5)],[(1000,6,-1.5),(1000.,2),(1000,6,1.5)],[(1000,6,-1.3),(1000.,6),(1000,6,1.3)]], x0=['C','C','C'])# Setup the model
M = simpeg.Mesh.TensorMesh([[(200,6,-1.5),(200.,4),(200,6,1.5)],[(200,6,-1.5),(200.,4),(200,6,1.5)],[(200,8,-1.5),(200.,8),(200,8,1.5)]], x0=['C','C','C'])# Setup the model
# Set the frequencies
freqs = np.logspace(1,-3,5)
elev = 0
## Setup the the survey object
# Receiver locations
rx_x, rx_y = np.meshgrid(np.arange(-350,350,200),np.arange(-350,350,200))
rx_loc = np.hstack((simpeg.Utils.mkvc(rx_x,2),simpeg.Utils.mkvc(rx_y,2),elev+np.zeros((np.prod(rx_x.shape),1))))
return M, freqs, rx_loc, elev
def random(conds):
''' Returns a halfspace model based on the inputs'''
M, freqs, rx_loc, elev = getInputs()
# Backround
sigBG = np.ones(M.nC)*conds
# Add randomness to the model (10% of the value).
sig = np.exp( np.log(sigBG) + np.random.randn(M.nC)*(conds)*1e-1 )
return (M, freqs, sig, sigBG, rx_loc)
def halfSpace(conds):
''' Returns a halfspace model based on the inputs'''
M, freqs, rx_loc, elev = getInputs()
# Model
ccM = M.gridCC
# conds = [1e-2]
groundInd = ccM[:,2] < elev
sig = np.zeros(M.nC) + 1e-8
sig[groundInd] = conds
# Set the background, not the same as the model
sigBG = np.zeros(M.nC) + 1e-8
sigBG[groundInd] = conds
return (M, freqs, sig, sigBG, rx_loc)
def blockInhalfSpace(conds):
''' Returns a halfspace model based on the inputs'''
M, freqs, rx_loc, elev = getInputs()
# Model
ccM = M.gridCC
# conds = [1e-2]
groundInd = ccM[:,2] < elev
sig = simpeg.Utils.ModelBuilder.defineBlock(M.gridCC,np.array([-1000,-1000,-1500]),np.array([1000,1000,-1000]),conds)
sig[~groundInd] = 1e-8
# Set the background, not the same as the model
sigBG = np.zeros(M.nC) + 1e-8
sigBG[groundInd] = conds[1]
return (M, freqs, sig, sigBG, rx_loc)
def twoLayer(conds):
''' Returns a 2 layer model based on the conductivity values given'''
M, freqs, rx_loc, elev = getInputs()
# Model
ccM = M.gridCC
groundInd = ccM[:,2] < elev
botInd = ccM[:,2] < -3000
sig = np.zeros(M.nC) + 1e-8
sig[groundInd] = conds[1]
sig[botInd] = conds[0]
# Set the background, not the same as the model
sigBG = np.zeros(M.nC) + 1e-8
sigBG[groundInd] = conds[1]
return (M, freqs, sig, sigBG, rx_loc)
+5
View File
@@ -0,0 +1,5 @@
import Utils
from SurveyNSEM import Rx, Survey, Data
from FieldsNSEM import Fields1D_ePrimSec, Fields3D_ePrimSec
from ProblemNSEM import Problem1D_ePrimSec, Problem3D_ePrimSec
import SrcNSEM
+19 -1
View File
@@ -888,6 +888,8 @@ class ProjectedGNCG(BFGS, Minimize, Remember):
maxIterCG = 5
tolCG = 1e-1
stepOffBoundsFact = 0.1 # perturbation of the inactive set off the bounds
lower = -np.inf
upper = np.inf
@@ -990,4 +992,20 @@ class ProjectedGNCG(BFGS, Minimize, Remember):
cgFlag = 1
# End CG Iterations
return delx
# Take a gradient step on the active cells if exist
if temp != self.xc.size:
rhs_a = (Active) * -self.g
dm_i = max( abs( delx ) )
dm_a = max( abs(rhs_a) )
# perturb inactive set off of bounds so that they are included in the step
delx = delx + self.stepOffBoundsFact * (rhs_a * dm_i / dm_a)
# Only keep gradients going in the right direction on the active set
indx = ((self.xc<=self.lower) & (delx < 0)) | ((self.xc>=self.upper) & (delx > 0))
delx[indx] = 0.
return delx
+2 -2
View File
@@ -74,7 +74,7 @@ class Property(object):
if linkedMap is None:
return None
linkMap = linkMapClass(None) * linkedMap
m = getattr(self, '%s'%linkName)
m = getattr(self, '%sModel'%linkName)
return linkMap.deriv( m )
m = getattr(self, '%sModel'%prop.name)
@@ -239,7 +239,7 @@ class PropMap(object):
setattr(self, '%sMap'%name, mapping)
setattr(self, '%sIndex'%name, slices.get(name, slice(nP, nP + mapping.nP)))
nP += mapping.nP
self.nP = nP
self.nP = nP
@property
def defaultInvProp(self):
+797 -319
View File
File diff suppressed because it is too large Load Diff
+35 -44
View File
@@ -82,14 +82,14 @@ class OrderTest(unittest.TestCase):
_meshType = meshTypes[0]
meshDimension = 3
def makeMesh(self, nc, meshType=_meshType, meshDimension=meshDimension):
def setupMesh(self, nc):
"""
For a given number of cells nc, generate a TensorMesh with uniform cells with edge length h=1/nc.
"""
if 'TensorMesh' in meshType:
if 'uniform' in meshType:
if 'TensorMesh' in self._meshType:
if 'uniform' in self._meshType:
h = [nc, nc, nc]
elif 'random' in meshType:
elif 'random' in self._meshType:
h1 = np.random.rand(nc)*nc*0.5 + nc*0.5
h2 = np.random.rand(nc)*nc*0.5 + nc*0.5
h3 = np.random.rand(nc)*nc*0.5 + nc*0.5
@@ -97,46 +97,46 @@ class OrderTest(unittest.TestCase):
else:
raise Exception('Unexpected meshType')
M = TensorMesh(h[:meshDimension])
max_h = max([np.max(hi) for hi in M.h])
return M, max_h
self.M = TensorMesh(h[:self.meshDimension])
max_h = max([np.max(hi) for hi in self.M.h])
return max_h
elif 'CylMesh' in meshType:
if 'uniform' in meshType:
elif 'CylMesh' in self._meshType:
if 'uniform' in self._meshType:
h = [nc, nc, nc]
else:
raise Exception('Unexpected meshType')
if meshDimension == 2:
M = CylMesh([h[0], 1, h[2]])
max_h = max([np.max(hi) for hi in [M.hx, M.hz]])
elif meshDimension == 3:
M = CylMesh(h)
max_h = max([np.max(hi) for hi in M.h])
return M, max_h
if self.meshDimension == 2:
self.M = CylMesh([h[0], 1, h[2]])
max_h = max([np.max(hi) for hi in [self.M.hx, self.M.hz]])
elif self.meshDimension == 3:
self.M = CylMesh(h)
max_h = max([np.max(hi) for hi in self.M.h])
return max_h
elif 'Curv' in meshType:
if 'uniform' in meshType:
elif 'Curv' in self._meshType:
if 'uniform' in self._meshType:
kwrd = 'rect'
elif 'rotate' in meshType:
elif 'rotate' in self._meshType:
kwrd = 'rotate'
else:
raise Exception('Unexpected meshType')
if meshDimension == 1:
if self.meshDimension == 1:
raise Exception('Lom not supported for 1D')
elif meshDimension == 2:
elif self.meshDimension == 2:
X, Y = Utils.exampleLrmGrid([nc, nc], kwrd)
M = CurvilinearMesh([X, Y])
elif meshDimension == 3:
self.M = CurvilinearMesh([X, Y])
elif self.meshDimension == 3:
X, Y, Z = Utils.exampleLrmGrid([nc, nc, nc], kwrd)
M = CurvilinearMesh([X, Y, Z])
return M, 1./nc
self.M = CurvilinearMesh([X, Y, Z])
return 1./nc
elif 'Tree' in meshType:
elif 'Tree' in self._meshType:
nc *= 2
if 'uniform' in meshType or 'notatree' in meshType:
if 'uniform' in self._meshType or 'notatree' in self._meshType:
h = [nc, nc, nc]
elif 'random' in meshType:
elif 'random' in self._meshType:
h1 = np.random.rand(nc)*nc*0.5 + nc*0.5
h2 = np.random.rand(nc)*nc*0.5 + nc*0.5
h3 = np.random.rand(nc)*nc*0.5 + nc*0.5
@@ -145,29 +145,20 @@ class OrderTest(unittest.TestCase):
raise Exception('Unexpected meshType')
levels = int(np.log(nc)/np.log(2))
M = Tree(h[:meshDimension], levels=levels)
self.M = Tree(h[:self.meshDimension], levels=levels)
def function(cell):
if 'notatree' in meshType:
if 'notatree' in self._meshType:
return levels - 1
r = cell.center - np.array([0.5]*len(cell.center))
dist = np.sqrt(r.dot(r))
if dist < 0.2:
return levels
return levels - 1
M.refine(function,balance=False)
M.number(balance=False)
# M.plotGrid(showIt=True)
max_h = max([np.max(hi) for hi in M.h])
return M, max_h
def setupMesh(self, nc):
"""
For a given number of cells nc, generate a TensorMesh with uniform cells with edge length h=1/nc.
"""
M, h = self.makeMesh(nc, meshType=self._meshType, meshDimension=self.meshDimension)
self.M = M
return h
self.M.refine(function,balance=False)
self.M.number(balance=False)
# self.M.plotGrid(showIt=True)
max_h = max([np.max(hi) for hi in self.M.h])
return max_h
def getError(self):
"""For given h, generate A[h], f and A(f) and return norm of error."""
+14 -4
View File
@@ -88,12 +88,14 @@ def getIndicesBlock(p0,p1,ccMesh):
# Return a tuple
return ind
def defineBlock(ccMesh,p0,p1,vals=[0,1]):
def defineBlock(ccMesh,p0,p1,vals=None):
"""
Build a block with the conductivity specified by condVal. Returns an array.
vals[0] conductivity of the block
vals[1] conductivity of the ground
"""
if vals is None:
vals = [0,1]
sigma = np.zeros(ccMesh.shape[0]) + vals[1]
ind = getIndicesBlock(p0,p1,ccMesh)
@@ -101,7 +103,11 @@ def defineBlock(ccMesh,p0,p1,vals=[0,1]):
return mkvc(sigma)
def defineElipse(ccMesh, center=[0,0,0], anisotropy=[1,1,1], slope=10., theta=0.):
def defineElipse(ccMesh, center=None, anisotropy=None, slope=10., theta=0.):
if center is None:
center = [0,0,0]
if anisotropy is None:
anisotropy = [1,1,1]
G = ccMesh.copy()
dim = ccMesh.shape[1]
for i in range(dim):
@@ -156,7 +162,7 @@ def getIndicesSphere(center,radius,ccMesh):
# Return a tuple
return ind
def defineTwoLayers(ccMesh,depth,vals=[0,1]):
def defineTwoLayers(ccMesh,depth,vals=None):
"""
Define a two layered model. Depth of the first layer must be specified.
CondVals vector with the conductivity values of the layers. Eg:
@@ -167,6 +173,8 @@ def defineTwoLayers(ccMesh,depth,vals=[0,1]):
0 depth zf
1st layer 2nd layer
"""
if vals is None:
vals = [0,1]
sigma = np.zeros(ccMesh.shape[0]) + vals[1]
dim = np.size(ccMesh[0,:])
@@ -252,7 +260,7 @@ def layeredModel(ccMesh, layerTops, layerValues):
def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]):
def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=None):
"""
Create a random model by convolving a kernel with a
uniformly distributed model.
@@ -276,6 +284,8 @@ def randomModel(shape, seed=None, anisotropy=None, its=100, bounds=[0,1]):
"""
if bounds is None:
bounds = [0,1]
if seed is None:
seed = np.random.randint(1e3)
+1
View File
@@ -7,3 +7,4 @@ from CounterUtils import *
import ModelBuilder
import SolverUtils
from coordutils import *
from modelutils import *
+3 -1
View File
@@ -55,8 +55,10 @@ def hook(obj, method, name=None, overwrite=False, silent=False):
print 'Method '+name+' was not overwritten.'
def setKwargs(obj, ignore=[], **kwargs):
def setKwargs(obj, ignore=None, **kwargs):
"""Sets key word arguments (kwargs) that are present in the object, throw an error if they don't exist."""
if ignore is None:
ignore = []
for attr in kwargs:
if attr in ignore:
continue
+137
View File
@@ -0,0 +1,137 @@
from SimPEG import np, Mesh
import time as tm
import vtk, vtk.util.numpy_support as npsup
import re
def read_GOCAD_ts(tsfile):
"""
Read GOCAD triangulated surface (*.ts) file
INPUT:
tsfile: Triangulated surface
OUTPUT:
vrts : Array of vertices in XYZ coordinates [n x 3]
trgl : Array of index for triangles [m x 3]. The order of the vertices
is important and describes the normal
n = cross( (P2 - P1 ) , (P3 - P1) )
Author: @fourndo
.. note::
Remove all attributes from the GoCAD surface before exporting it!
"""
fid = open(tsfile,'r')
line = fid.readline()
# Skip all the lines until the vertices
while re.match('TFACE',line)==None:
line = fid.readline()
line = fid.readline()
vrtx = []
# Run down all the vertices and save in array
while re.match('VRTX',line):
l_input = re.split('[\s*]',line)
temp = np.array(l_input[2:5])
vrtx.append(temp.astype(np.float))
# Read next line
line = fid.readline()
vrtx = np.asarray(vrtx)
# Skip lines to the triangles
while re.match('TRGL',line)==None:
line = fid.readline()
# Run down the list of triangles
trgl = []
# Run down all the vertices and save in array
while re.match('TRGL',line):
l_input = re.split('[\s*]',line)
temp = np.array(l_input[1:4])
trgl.append(temp.astype(np.int))
# Read next line
line = fid.readline()
trgl = np.asarray(trgl)
return vrtx, trgl
def surface2inds(vrtx, trgl, mesh, boundaries=True, internal=True):
""""
Function to read gocad polystructure file and output indexes of mesh with in the structure.
"""
# Adjust the index
trgl = trgl - 1
# Make vtk pts
ptsvtk = vtk.vtkPoints()
ptsvtk.SetData(npsup.numpy_to_vtk(vrtx,deep=1))
# Make the polygon connection
polys = vtk.vtkCellArray()
for face in trgl:
poly = vtk.vtkPolygon()
poly.GetPointIds().SetNumberOfIds(len(face))
for nrv, vert in enumerate(face):
poly.GetPointIds().SetId(nrv,vert)
polys.InsertNextCell(poly)
# Make the polydata, structure of connections and vrtx
polyData = vtk.vtkPolyData()
polyData.SetPoints(ptsvtk)
polyData.SetPolys(polys)
# Make implicit func
ImpDistFunc = vtk.vtkImplicitPolyDataDistance()
ImpDistFunc.SetInput(polyData)
# Convert the mesh
vtkMesh = vtk.vtkRectilinearGrid()
vtkMesh.SetDimensions(mesh.nNx,mesh.nNy,mesh.nNz)
vtkMesh.SetXCoordinates(npsup.numpy_to_vtk(mesh.vectorNx, deep=1))
vtkMesh.SetYCoordinates(npsup.numpy_to_vtk(mesh.vectorNy, deep=1))
vtkMesh.SetZCoordinates(npsup.numpy_to_vtk(mesh.vectorNz, deep=1))
# Add indexes
vtkInd = npsup.numpy_to_vtk(np.arange(mesh.nC), deep=1)
vtkInd.SetName('Index')
vtkMesh.GetCellData().AddArray(vtkInd)
extractImpDistRectGridFilt = vtk.vtkExtractGeometry() # Object constructor
extractImpDistRectGridFilt.SetImplicitFunction(ImpDistFunc) #
extractImpDistRectGridFilt.SetInputData(vtkMesh)
if boundaries is True:
extractImpDistRectGridFilt.ExtractBoundaryCellsOn()
else:
extractImpDistRectGridFilt.ExtractBoundaryCellsOff()
if internal is True:
extractImpDistRectGridFilt.ExtractInsideOn()
else:
extractImpDistRectGridFilt.ExtractInsideOff()
print "Extracting indices from grid..."
# Executing the pipe
extractImpDistRectGridFilt.Update()
# Get index inside
insideGrid = extractImpDistRectGridFilt.GetOutput()
insideGrid = npsup.vtk_to_numpy(insideGrid.GetCellData().GetArray('Index'))
# Return the indexes inside
return insideGrid
+3 -3
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:
@@ -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()
+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 %s mesh'%mesh._meshType)
Nz = mesh.vectorNz[1:] # TODO: this will only work for tensor meshes
actind = np.array([False]*mesh.nC).reshape(mesh.vnC, order='F')
for ii in range(mesh.nCx):
for jj in range(mesh.nCy):
actind[ii,jj,:] = [np.all(gridTopo[ii:ii+2, jj:jj+2] >= Nz[kk]) for kk in range(len(Nz)) ]
elif mesh.dim == 2:
from scipy.interpolate import interp1d
Ftopo = interp1d(topo[:,0], topo[:,1])
if gridLoc == 'CC':
gridTopo = Ftopo(mesh.gridCC[:,0])
actind = mesh.gridCC[:,1] <= gridTopo
elif gridLoc == 'N':
gridTopo = Ftopo(mesh.vectorNx)
if mesh._meshType not in ['TENSOR', 'CYL', 'BASETENSOR']:
raise NotImplementedError('Nodal surface2ind_topo not implemented for %s mesh'%mesh._meshType)
Ny = mesh.vectorNy[1:] # TODO: this will only work for tensor meshes
actind = np.array([False]*mesh.nC).reshape(mesh.vnC, order='F')
for ii in range(mesh.nCx):
actind[ii,:] = [np.all(gridTopo[ii:ii+2] > Ny[kk]) for kk in range(len(Ny)) ]
else:
raise NotImplementedError('surface2ind_topo not implemented for 1D mesh')
return mkvc(actind)
+10 -2
View File
@@ -12,9 +12,17 @@
DC Forward Simulation
=====================
Forward model conductive spheres in a half-space and plot a pseudo-section
Forward model two conductive spheres in a half-space and plot a
pseudo-section. Assumes an infinite line source and measures along the
center of the spheres.
Created by @fourndo on Mon Feb 01 19:28:06 2016
INPUT:
loc = Location of spheres [[x1,y1,z1],[x2,y2,z2]]
radi = Radius of spheres [r1,r2]
param = Conductivity of background and two spheres [m0,m1,m2]
surveyType = survey type 'pole-dipole' or 'dipole-dipole'
unitType = Data type "appResistivity" | "appConductivity" | "volt"
Created by @fourndo
@@ -0,0 +1,58 @@
.. _examples_EM_Schenkel_Morrison_Casing:
.. --------------------------------- ..
.. ..
.. THIS FILE IS AUTO GENEREATED ..
.. ..
.. SimPEG/Examples/__init__.py ..
.. ..
.. --------------------------------- ..
EM: Schenkel and Morrison Casing Model
======================================
Here we create and run a FDEM forward simulation to calculate the vertical
current inside a steel-cased. The model is based on the Schenkel and
Morrison Casing Model, and the results are used in a 2016 SEG abstract by
Yang et al.
- Schenkel, C.J., and H.F. Morrison, 1990, Effects of well casing on potential field measurements using downhole current sources: Geophysical prospecting, 38, 663-686.
The model consists of:
- Air: Conductivity 1e-8 S/m, above z = 0
- Background: conductivity 1e-2 S/m, below z = 0
- Casing: conductivity 1e6 S/m
- 300m long
- radius of 0.1m
- thickness of 6e-3m
Inside the casing, we take the same conductivity as the background.
We are using an EM code to simulate DC, so we use frequency low enough
that the skin depth inside the casing is longer than the casing length (f
= 1e-6 Hz). The plot produced is of the current inside the casing.
These results are shown in the SEG abstract by Yang et al., 2016: 3D DC
resistivity modeling of steel casing for reservoir monitoring using
equivalent resistor network. The solver used to produce these results and
achieve the CPU time of ~30s is Mumps, which was installed using pymatsolver_
.. _pymatsolver: https://github.com/rowanc1/pymatsolver
This example is on figshare: https://dx.doi.org/10.6084/m9.figshare.3126961.v1
If you would use this example for a code comparison, or build upon it, a
citation would be much appreciated!
.. plot::
from SimPEG import Examples
Examples.EM_Schenkel_Morrison_Casing.run()
.. literalinclude:: ../../SimPEG/Examples/EM_Schenkel_Morrison_Casing.py
:language: python
:linenos:
+26
View File
@@ -0,0 +1,26 @@
.. _examples_Inversion_IRLS:
.. --------------------------------- ..
.. ..
.. THIS FILE IS AUTO GENEREATED ..
.. ..
.. SimPEG/Examples/__init__.py ..
.. ..
.. --------------------------------- ..
Inversion: Linear Problem
=========================
Here we go over the basics of creating a linear problem and inversion.
.. plot::
from SimPEG import Examples
Examples.Inversion_IRLS.run()
.. literalinclude:: ../../SimPEG/Examples/Inversion_IRLS.py
:language: python
:linenos:
@@ -1,4 +1,4 @@
.. _examples_Forward_BasicDirectCurrent:
.. _examples_MT_1D_analytic_nlayer_Earth:
.. --------------------------------- ..
.. ..
@@ -8,14 +8,14 @@
.. ..
.. --------------------------------- ..
Forward BasicDirectCurrent
==========================
MT 1D analytic nlayer Earth
===========================
.. plot::
from SimPEG import Examples
Examples.Forward_BasicDirectCurrent.run()
Examples.MT_1D_analytic_nlayer_Earth.run()
.. literalinclude:: ../../SimPEG/Examples/Forward_BasicDirectCurrent.py
.. literalinclude:: ../../SimPEG/Examples/MT_1D_analytic_nlayer_Earth.py
:language: python
:linenos:
+25
View File
@@ -0,0 +1,25 @@
.. _examples_Mesh_Basic_ForwardDC:
.. --------------------------------- ..
.. ..
.. THIS FILE IS AUTO GENEREATED ..
.. ..
.. SimPEG/Examples/__init__.py ..
.. ..
.. --------------------------------- ..
Mesh: Basic Forward 2D DC Resistivity
=====================================
2D DC forward modeling example with Tensor and Curvilinear Meshes
.. plot::
from SimPEG import Examples
Examples.Mesh_Basic_ForwardDC.run()
.. literalinclude:: ../../SimPEG/Examples/Mesh_Basic_ForwardDC.py
:language: python
:linenos:
+24
View File
@@ -0,0 +1,24 @@
.. _examples_Utils_surface2ind_topo:
.. --------------------------------- ..
.. ..
.. THIS FILE IS AUTO GENEREATED ..
.. ..
.. SimPEG/Examples/__init__.py ..
.. ..
.. --------------------------------- ..
Here we show how to use :code:`Utils.surface2ind_topo` to identify cells below
a topographic surface.
.. plot::
from SimPEG import Examples
Examples.Utils_surface2ind_topo.run()
.. literalinclude:: ../../SimPEG/Examples/Utils_surface2ind_topo.py
:language: python
:linenos:
+12 -6
View File
@@ -5,16 +5,17 @@ SimPEG is a python package for simulation and gradient based
parameter estimation in the context of geophysical applications.
"""
import numpy as np
import os
import sys
import subprocess
from distutils.core import setup
from distutils.command.build_ext import build_ext
from setuptools import find_packages
from distutils.extension import Extension
CLASSIFIERS = [
'Development Status :: 4 - Beta',
'Intended Audience :: Developers',
@@ -51,11 +52,16 @@ if args.count("build_ext") > 0 and args.count("--inplace") == 0:
try:
from Cython.Build import cythonize
from Cython.Distutils import build_ext
cythonKwargs = dict(cmdclass={'build_ext': build_ext})
USE_CYTHON = True
except Exception, e:
USE_CYTHON = False
cythonKwargs = dict()
class NumpyBuild(build_ext):
def finalize_options(self):
build_ext.finalize_options(self)
__builtins__.__NUMPY_SETUP__ = False
import numpy
self.include_dirs.append(numpy.get_include())
ext = '.pyx' if USE_CYTHON else '.c'
@@ -94,8 +100,8 @@ setup(
classifiers=CLASSIFIERS,
platforms = ["Windows", "Linux", "Solaris", "Mac OS-X", "Unix"],
use_2to3 = False,
include_dirs=[np.get_include()],
cmdclass={'build_ext':NumpyBuild},
setup_requires=['numpy'],
ext_modules = extensions,
scripts=scripts,
**cythonKwargs
)
+29
View File
@@ -1,6 +1,7 @@
import unittest
from SimPEG import *
from scipy.constants import mu_0
from SimPEG import Tests
class MyPropMap(Maps.PropMap):
@@ -187,6 +188,34 @@ class TestPropMaps(unittest.TestCase):
MyReciprocalPropMap([('sigma', iMap), ('mu', iMap)]) # This should be fine
def test_linked_derivs_sigma(self):
mesh = Mesh.TensorMesh([4,5], x0='CC')
mapping = Maps.ExpMap(mesh)
propmap = MyReciprocalPropMap([('rho', mapping)])
x0 = np.random.rand(mesh.nC)
m = propmap(x0)
# test Sigma
testme = lambda v: [1./(m.rhoMap*v), m.sigmaDeriv]
print 'Testing Rho from Sigma'
Tests.checkDerivative(testme, x0, dx=0.01*x0, num=5, plotIt=False)
def test_linked_derivs_rho(self):
mesh = Mesh.TensorMesh([4,5], x0='CC')
mapping = Maps.ExpMap(mesh)
propmap = MyReciprocalPropMap([('sigma', mapping)])
x0 = np.random.rand(mesh.nC)
m = propmap(x0)
# test Sigma
testme = lambda v: [1./(m.sigmaMap*v), m.rhoDeriv]
print 'Testing Rho from Sigma'
Tests.checkDerivative(testme, x0, dx=0.01*x0, num=5, plotIt=False)
if __name__ == '__main__':
unittest.main()
+73 -49
View File
@@ -5,6 +5,8 @@ from scipy.sparse.linalg import dsolve
import inspect
TOL = 1e-20
testReg = True
testRegMesh = True
class RegularizationTests(unittest.TestCase):
@@ -16,44 +18,80 @@ class RegularizationTests(unittest.TestCase):
mesh3 = Mesh.TensorMesh([hx, hy, hz])
self.meshlist = [mesh1,mesh2, mesh3]
def test_regularization(self):
for R in dir(Regularization):
r = getattr(Regularization, R)
if not inspect.isclass(r): continue
if not issubclass(r, Regularization.BaseRegularization):
continue
if testReg:
def test_regularization(self):
for R in dir(Regularization):
r = getattr(Regularization, R)
if not inspect.isclass(r): continue
if not issubclass(r, Regularization.BaseRegularization):
continue
for i, mesh in enumerate(self.meshlist):
print 'Testing %iD'%mesh.dim
mapping = r.mapPair(mesh)
reg = r(mesh, mapping=mapping)
m = np.random.rand(mapping.nP)
reg.mref = np.ones_like(m)*np.mean(m)
print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref)
passed = reg.eval(reg.mref) < TOL
self.assertTrue(passed)
print 'Check:', R
passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False)
self.assertTrue(passed)
print 'Check 2 Deriv:', R
passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False)
self.assertTrue(passed)
def test_regularization_ActiveCells(self):
for R in dir(Regularization):
r = getattr(Regularization, R)
if not inspect.isclass(r): continue
if not issubclass(r, Regularization.BaseRegularization):
continue
for i, mesh in enumerate(self.meshlist):
print 'Testing Active Cells %iD'%(mesh.dim)
if mesh.dim == 1:
indActive = Utils.mkvc(mesh.gridCC <= 0.8)
elif mesh.dim == 2:
indActive = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5)
elif mesh.dim == 3:
indActive = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5)
for indAct in [indActive, indActive.nonzero()[0]]: # test both bool and integers
reg = r(mesh, indActive=indAct)
m = np.random.rand(mesh.nC)[indAct]
reg.mref = np.ones_like(m)*np.mean(m)
print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref)
passed = reg.eval(reg.mref) < TOL
self.assertTrue(passed)
print 'Check:', R
passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False)
self.assertTrue(passed)
print 'Check 2 Deriv:', R
passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False)
self.assertTrue(passed)
if testRegMesh:
def test_regularizationMesh(self):
for i, mesh in enumerate(self.meshlist):
print 'Testing %iD'%mesh.dim
mapping = r.mapPair(mesh)
reg = r(mesh, mapping=mapping)
m = np.random.rand(mapping.nP)
reg.mref = np.ones_like(m)*np.mean(m)
print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref)
passed = reg.eval(reg.mref) < TOL
self.assertTrue(passed)
print 'Check:', R
passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False)
self.assertTrue(passed)
print 'Check 2 Deriv:', R
passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False)
self.assertTrue(passed)
def test_regularization_ActiveCells(self):
for R in dir(Regularization):
r = getattr(Regularization, R)
if not inspect.isclass(r): continue
if not issubclass(r, Regularization.BaseRegularization):
continue
for i, mesh in enumerate(self.meshlist):
print 'Testing Active Cells %iD'%(mesh.dim)
# mapping = r.mapPair(mesh)
# reg = r(mesh, mapping=mapping)
# m = np.random.rand(mapping.nP)
if mesh.dim == 1:
indAct = Utils.mkvc(mesh.gridCC <= 0.8)
@@ -62,23 +100,9 @@ class RegularizationTests(unittest.TestCase):
elif mesh.dim == 3:
indAct = Utils.mkvc(mesh.gridCC[:,-1] <= 2*np.sin(2*np.pi*mesh.gridCC[:,0])+0.5 * 2*np.sin(2*np.pi*mesh.gridCC[:,1])+0.5)
mapping = Maps.IdentityMap(nP=indAct.nonzero()[0].size)
regmesh = Regularization.RegularizationMesh(mesh, indActive=indAct)
reg = r(mesh, mapping=mapping, indActive=indAct)
m = np.random.rand(mesh.nC)[indAct]
reg.mref = np.ones_like(m)*np.mean(m)
print 'Check: phi_m (mref) = %f' %reg.eval(reg.mref)
passed = reg.eval(reg.mref) < TOL
self.assertTrue(passed)
print 'Check:', R
passed = Tests.checkDerivative(lambda m : [reg.eval(m), reg.evalDeriv(m)], m, plotIt=False)
self.assertTrue(passed)
print 'Check 2 Deriv:', R
passed = Tests.checkDerivative(lambda m : [reg.evalDeriv(m), reg.eval2Deriv(m)], m, plotIt=False)
self.assertTrue(passed)
assert (regmesh.vol == mesh.vol[indAct]).all()
if __name__ == '__main__':
+4 -4
View File
@@ -28,12 +28,12 @@ class FDEM_analyticTests(unittest.TestCase):
x = np.linspace(-10,10,5)
XYZ = Utils.ndgrid(x,np.r_[0],np.r_[0])
rxList = EM.FDEM.Rx(XYZ, 'exi')
rxList = EM.FDEM.Rx.Point_e(XYZ, orientation='x', component='imag')
Src0 = EM.FDEM.Src.MagDipole([rxList],loc=np.r_[0.,0.,0.], freq=freq)
survey = EM.FDEM.Survey([Src0])
prb = EM.FDEM.Problem_b(mesh, mapping=mapping)
prb = EM.FDEM.Problem3D_b(mesh, mapping=mapping)
prb.pair(survey)
try:
@@ -125,8 +125,8 @@ class FDEM_analyticTests(unittest.TestCase):
mapping = [('sigma', Maps.IdentityMap(mesh)),('mu', Maps.IdentityMap(mesh))]
prbe = EM.FDEM.Problem_h(mesh, mapping=mapping)
prbm = EM.FDEM.Problem_e(mesh, mapping=mapping)
prbe = EM.FDEM.Problem3D_h(mesh, mapping=mapping)
prbm = EM.FDEM.Problem3D_e(mesh, mapping=mapping)
prbe.pair(surveye) # pair problem and survey
prbm.pair(surveym)

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