├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── aznbsetup.sh ├── data ├── bookpurnong │ ├── 8044_Bookpurnong.HDR │ ├── Bookpurnong_Resolve_Exported.XYZ │ ├── Bookpurnong_SkyTEM.HDR │ ├── MurrayRiver.txt │ ├── README.txt │ └── SK655CS_Bookpurnong_ZX_HM_TxInc_newDTM.txt └── dc_data.csv ├── dev-requirements.txt ├── environment.yml ├── images ├── cylsetup.png └── finiteVolume-02.png ├── index.ipynb ├── notebooks ├── DC_Mise-a-la-masse.ipynb ├── DC_inversion_2D_example.ipynb ├── FDEM_inversion_bookpurnong.ipynb ├── FDEM_target_in_solenoid.ipynb ├── FDEM_vmd_sounding_over_sphere.ipynb ├── InversionModel-2018-07-22-15-43.txt ├── MT1D.py ├── MT_tutorial_1_MT1D_NumericalSetup.ipynb ├── MT_tutorial_2_MT1D_ForwardModellingAndNonuniqueness.ipynb ├── MT_tutorial_3_MT1D_5layer_inversion.ipynb ├── MT_tutorial_Appendix_A_MT1D_Sensitivity.ipynb ├── MT_tutorial_Appendix_B_MT1D_tests.ipynb ├── MTforward.py ├── TDEM_1D_inversion.ipynb ├── TDEM_inversion_bookpurnong.ipynb └── TDEM_vmd_sounding_over_sphere.ipynb ├── requirements.txt └── tests ├── __init__.py └── test_notebooks.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # IPython Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | venv/ 83 | ENV/ 84 | 85 | # Spyder project settings 86 | .spyderproject 87 | 88 | # Rope project settings 89 | .ropeproject 90 | 91 | # repo-specific 92 | notebooks/mt_inv.txt 93 | notebooks/InversionModel*.txt 94 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - 3.6 4 | - 3.7 5 | 6 | sudo: false 7 | 8 | env: 9 | - TEST_DIR="tests" 10 | 11 | # Setup anaconda 12 | before_install: 13 | - wget http://repo.continuum.io/miniconda/Miniconda3-3.8.3-Linux-x86_64.sh -O miniconda.sh; 14 | - chmod +x miniconda.sh 15 | - ./miniconda.sh -b -p $HOME/miniconda 16 | - export PATH=/home/travis/anaconda/bin:/home/travis/miniconda/bin:$PATH 17 | - conda update --yes conda 18 | 19 | install: 20 | - conda env create -f environment.yml 21 | - conda activate em-notebooks-environment 22 | - pip install -r dev-requirements.txt 23 | - export MPLBACKEND="agg" 24 | 25 | # Run test 26 | script: 27 | - travis_wait 40 pytest $TEST_DIR -v 28 | 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 SimPEG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **[overview](#overview) | [launching the notebooks](#launching-the-notebooks) | [running the notebooks](#running-the-notebooks) | [issues](#issues) | [contributing](#for-contributors)** 2 | 3 | # em-notebooks 4 | 5 | [![binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/simpeg/em-notebooks/master?filepath=index.ipynb) 6 | [![azure](https://notebooks.azure.com/launch.png)](https://notebooks.azure.com/import/gh/simpeg/em-notebooks) 7 | [![travis](https://travis-ci.org/simpeg/em-notebooks.svg?branch=master)](https://travis-ci.org/simpeg/em-notebooks) 8 | [![SimPEG](https://img.shields.io/badge/powered%20by-SimPEG-blue.svg)](http://simpeg.xyz) 9 | 10 | ## Overview 11 | 12 | This is a repo of notebooks and interactive examples for http://em.geosci.xyz. They are tutorials on the use 13 | of SimPEG for forward modelling and inversion of DC, frequency domain EM, and time domain EM. 14 | 15 | The notebooks are available on 16 | - [Binder](https://mybinder.org/v2/gh/simpeg/em-notebooks/master?filepath=index.ipynb) 17 | - [Azure Notebooks](https://notebooks.azure.com/import/gh/simpeg/em-notebooks) 18 | 19 | 20 | 21 | ## Launching the notebooks 22 | 23 | The notebooks can be run online through [Binder](#Binder) or [Azure notebooks](#Azure), or [downloaded and run locally](#Locally). 24 | 25 | ### Binder 26 | 27 | [![Binder](https://mybinder.org/badge.svg)](https://mybinder.org/v2/gh/simpeg/em-notebooks/master?filepath=index.ipynb) 28 | 29 | 1. Launch the binder by clicking on the badge above or going to: https://mybinder.org/v2/gh/simpeg/em-notebooks/master?filepath=index.ipynb. 30 | This can sometimes take a couple minutes, so be patient... 31 | 32 | 2. Select the notebook of interest from the contents 33 | 34 | 3. [Run the Jupyter notebook](#Running-the-notebooks) 35 | 36 | ![Binder-steps](https://em.geosci.xyz/_images/binder-steps.png) 37 | 38 | ### Azure 39 | 40 | [![Azure](https://notebooks.azure.com/launch.png)](https://notebooks.azure.com/import/gh/simpeg/em-notebooks) 41 | 42 | 1. Navigate to Azure notebooks by clicking on the badge above or going to: https://notebooks.azure.com/import/gh/simpeg/em-notebooks, 43 | and select `Import` to import the library 44 | 45 | 2. Sign in to your microsoft account (or `Create One` if you do not already have an account) 46 | 47 | 3. Create the new library: Select Import 48 | 49 | 4. Select `index.ipynb` to view the notebook contents 50 | 51 | 5. Select the notebook of interest from the contents 52 | 53 | 6. [Run the Jupyter notebook](#Running-the-notebooks) 54 | 55 | ![Azure-steps](https://em.geosci.xyz/_images/azure-steps.png) 56 | 57 | ### Locally 58 | 59 | To run them locally, you will need to have python installed, preferably through [anaconda](https://www.anaconda.com/download/). 60 | 61 | You can then clone this reposiroty. From a command line, run 62 | 63 | ``` 64 | git clone https://github.com/simpeg/em-notebooks.git 65 | ``` 66 | 67 | Then `cd` into `em-notebooks` 68 | 69 | ``` 70 | cd em-notebooks 71 | ``` 72 | 73 | To setup your software environment, we recommend you use the provided conda environment 74 | 75 | ``` 76 | conda env create -f environment.yml 77 | source activate em-notebooks-environment 78 | ``` 79 | 80 | alternatively, you can install dependencies through pypi 81 | ``` 82 | pip install -r requirements.txt 83 | ``` 84 | 85 | You can then launch Jupyter 86 | ``` 87 | jupyter notebook index.ipynb 88 | ``` 89 | 90 | Jupyter will then launch in your web-browser. 91 | 92 | **Note**: these notebooks make use of `ipywidgets`, if you do not already have `ipywidgets` installed, please follow the [ipywidgets installation instructions](https://ipywidgets.readthedocs.io/en/stable/user_install.html). 93 | 94 | ## Running the notebooks 95 | 96 | Each cell of code can be run with `shift + enter` or you can run the entire notebook by selecting `cell`, `Run All` in the toolbar. 97 | 98 | ![cell-run-all](https://em.geosci.xyz/_images/run_all_cells.png) 99 | 100 | For more information on running Jupyter notebooks, see the [Jupyter Documentation](https://jupyter.readthedocs.io/en/latest/) 101 | 102 | ## Issues 103 | 104 | If you run into problems or bugs, please let us know by [creating an issue](https://github.com/simpeg/em-notebooks/issues/new) in this repository. 105 | 106 | -------------------------------------------------------------------------------- /aznbsetup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Activate environment 4 | source /home/nbuser/anaconda3_501/bin/activate 5 | 6 | # Set up proxy 7 | http_proxy=http://webproxy:3128 8 | https_proxy=http://webproxy:3128 9 | export http_proxy 10 | export https_proxy 11 | 12 | # pip 13 | pip install -r /home/nbuser/library/requirements.txt 14 | -------------------------------------------------------------------------------- /data/bookpurnong/8044_Bookpurnong.HDR: -------------------------------------------------------------------------------- 1 | CALPERUM STATION AIRBORNE : FINAL DATA 2 | BOOKPURNONG SURVEY AREA 3 | 10 SEPT, 2008 4 | 5 | 6 | G.A. PROJECT NUMBER..unassigned as of Sept 19, 2008 7 | FUGRO JOB NUMBER.....08044 8 | SURVEY COMPANY.......Fugro Airborne Surveys Pty Ltd 9 | CLIENT...............Bureau of Rural Sciences 10 | SURVEY TYPE..........RESOLVE 11 | AREA NAME............Calperum Station Airborne 12 | DATE FLOWN...........July to August 2008 13 | 14 | 15 | AIRBORNE SURVEY PARAMETERS 16 | 17 | LINE SPACING.........100 m /200 m 18 | TIE LINE SPACING.....2000 m 19 | LINE DIRECTION.......134 / 314 degrees 20 | TIE LINE DIRECTION...44 / 224 degrees 21 | TERRAIN CLEARANCE....EM transmitter in towed bird at 30 m 22 | EM receiver in towed bird at 30 m 23 | AIRCRAFT.............AS-350FX2 Squirrel; VH-RTV 24 | AIRCRAFT SPEED.......30 m/s 25 | POSITIONAL CONTROL...Post-processed differential GPS used in processing, 26 | real-time satellite differential GPS used in-flight. 27 | DIGITAL RECORDING....RESOLVE acquisition system 28 | 29 | 30 | EQUIPMENT SPECIFICATIONS 31 | 32 | ELECTROMAGNETICS 33 | TYPE.................RESOLVE III; SYSTEM 2 BKS 58A 34 | INSTALLATION.........Six transmitter coils mounted and 35 | six receiver coils in a towed bird. 36 | COIL ORIENTATION.....Five co-planar (CP) and one co-axial (CX). 37 | 38 | SYSTEM 1 BKS 58A SPECIFICATIONS 39 | NOMINAL FREQUENCY 400 1800 8200 40000 140000 3300 40 | 41 | COIL ORIENTATION CP CP CP CP CP CX 42 | 43 | OPERATING FREQUENCY (Hz) 382 1822 7970 35920 130100 3258 44 | 45 | 46 | 47 | TX-RX COIL SEPARATION (m) 7.86 7.86 7.86 7.86 7.86 8.99 48 | 49 | 50 | SAMPLING.............10 Hz (approximately 3 m) 51 | CORRECTIONS..........The EM data have been base level corrected, calibrated by internal q-coils, 52 | lagged by -8 scans, filtered by an 11 point median filter and a 11 point 53 | Hanning filter. The final EM channels have also had levelling applied. 54 | The laser data has been corrected for dropouts and attitude variation. 55 | The Mag data have been lagged,diurnally corrected and IGRF removed. 56 | PARALLAX.............No parallax was applied. 57 | 58 | 59 | MAP COORDINATES 60 | MAP PROJECTION.....MGA54 61 | SPHEROID...........GDA94 62 | CENTRAL MERIDIAN...141 degrees East 63 | 64 | 65 | ________________________________________________________________________________________________ 66 | 67 | Output field format : DOS - Flat ascii 68 | Number of fields : 105 69 | 70 | 71 | Field Columns Channel Sample Units Description Width Decimals 72 | Rate 73 | 1 1- 5 GAProject 0.00 GA Project Number 5 0 74 | 2 6- 12 FLIGHT 0.00 7 0 75 | 3 13- 19 LINE 0.00 7 0 76 | 4 20- 30 FID 0.10 11 1 77 | 5 31- 40 DATE 0.00 ddmmyyyy UTC DAY LINE FLOWN 12 0 78 | 6 41- 50 UTC 0.10 seconds Seconds since UTC midnight 10 1 79 | 7 51- 55 BEARING 0.10 Degrees Line Bearing in degrees east of north 5 0 80 | 8 56- 68 LON_HELI 0.10 Degrees LONGITUDE-MGA54 Heli Ant 13 6 81 | 9 69- 81 LAT_HELI 0.10 Degrees LATITUDE -MGA54 Heli Ant 13 6 82 | 10 82- 91U TME_HELI 0.10 m UTME-MGA54 Heli 10 1 83 | 11 92- 102 UTMN_HELI 0.10 m UTMN-MGA54 Heli 11 1 84 | 12 103- 111 GPS_Z_HELI 0.10 m Heli Height above Spheroid 9 2 85 | 13 112- 120 RADAR_ALT 0.10 m Radar altimeter on helicopter 9 2 86 | 14 121- 130 UTME_CTR 0.10 m UTME-MGA54 Center Ant 10 1 87 | 15 131- 141 UTMN_CTR 0.10 m UTMN-MGA54 Center Ant 11 1 88 | 16 142- 149 GPS_Z_CTR 0.10 m Center Ant Height above Spheroid 8 2 89 | 17 150- 159 UTME_LFT 0.10 m UTME-MGA54 Rear Left Ant 10 1 90 | 18 160- 170 UTMN_LFT 0.10 m UTMN-MGA54 Rear Left Ant 11 1 91 | 19 171- 178 GPS_Z_LFT 0.10 m Left Ant Height above Spheroid 8 2 92 | 20 179- 188 UTME_RT 0.10 m UTME-MGA54 Rear Right Ant 10 1 93 | 21 189- 199 UTMN_RT 0.10 m UTMN-MGA54 Rear Right Ant 11 1 94 | 22 200- 207 GPS_Z_RT 0.10 m Right Ant Height above Spheroid 8 2 95 | 96 | 23 208- 217 UTME_BIRD 0.10 m UTME-MGA54 Bird 10 1 97 | 24 218- 228 UTMN_BIRD 0.10 m UTMN-MGA54 Bird 11 1 98 | 25 229- 236 GPS_Z_BIRD 0.10 m Bird Height above Spheroid 8 2 99 | 26 237- 244 BIRD_ROLL 0.10 deg Bird Roll 8 1 100 | 27 245- 252 BIRD_PITCH 0.10 deg Bird Pitch 8 1 101 | 28 253- 260 BIRD_YAW 0.10 deg Bird yaw 8 1 102 | 103 | 29 261- 268 LASER ALT RAW 0.10 m Raw laser altimeter on bird 8 2 104 | 30 269- 276 LASER ALT EDIT 0.10 m Edited and filtered laser altimeter 8 2 105 | 31 277- 284 BIRD HEIGHT 0.10 m Point and attitude corrected laser alt 8 2 106 | 32 285- 292 DTM_LAS 0.10 m Ground elevation from bird height 8 2 107 | 108 | 33 293- 300 CPPL 0.10 Power Line Monitor 8 3 109 | 34 301- 308 CPSP 0.10 Spherics Monitor 8 3 110 | 111 | 35 309- 316 ZCPI400 0.10 ppm Zero level INPHASE 382 HZ 8 1 112 | 36 317- 324 ZCPQ400 0.10 ppm Zero level QUAD 382 HZ 8 1 113 | 37 325- 332 ZCPI1800 0.10 ppm Zero level INPHASE 1822 HZ 8 1 114 | 38 333- 340 ZCPQ1800 0.10 ppm Zero level QUAD 1822 HZ 8 1 115 | 39 341- 348 ZCXI3300 0.10 ppm Zero level INPHASE 3258 HZ 8 1 116 | 40 349- 356 ZCXQ3300 0.10 ppm Zero level QUAD 3258 HZ 8 1 117 | 41 357- 364 ZCPI8200 0.10 ppm Zero level INPHASE 7970 HZ 8 1 118 | 42 365- 372 ZCPQ8200 0.10 ppm Zero level QUAD 7970 HZ 8 1 119 | 43 373- 380 ZCPI40k 0.10 ppm Zero level INPHASE 35920 HZ 8 1 120 | 44 381- 388 ZCPQ40k 0.10 ppm Zero level QUAD 35920 HZ 8 1 121 | 45 389- 396 ZCPI140k 0.10 ppm Zero level INPHASE 130.1 kHZ 8 1 122 | 46 397- 404 ZCPQ140k 0.10 ppm Zero level QUAD 130.1 kHZ 8 1 123 | 124 | 47 405- 412 RCPI400 0.10 ppm RAW INPHASE-COPLANAR 382 HZ 8 1 125 | 48 413- 420 RCPQ400 0.10 ppm RAW QUADRATURE- COPLANAR 382 HZ 8 1 126 | 49 421- 428 RCPI1800 0.10 ppm RAW INPHASE-COPLANAR 1822 HZ 8 1 127 | 50 429- 436 RCPQ1800 0.10 ppm RAW QUAD- COPLANAR 1822 HZ 8 1 128 | 51 437- 444 RCXI3300 0.10 ppm RAW INPHASE-COAXIAL 3258 HZ 8 1 129 | 52 445- 452 RCXQ3300 0.10 ppm RAW QUAD-COAXIAL 3258 HZ 8 1 130 | 53 453- 460 RCPI8200 0.10 ppm RAW INPHASE -COPLANAR 7970 HZ 8 1 131 | 54 461- 468 RCPQ8200 0.10 ppm RAW QUAD -COPLANAR 7970 HZ 8 1 132 | 55 469- 476 RCPI40k 0.10 ppm RAW INPHASE -COPLANAR 35920 HZ 8 1 133 | 56 477- 484 RCPQ40k 0.10 ppm RAW QUAD -COPLANAR 35920 HZ 8 1 134 | 57 485- 492 RCPI140k 0.10 ppm RAW INPHASE-COPLANAR 130.1 kHZ 8 1 135 | 58 493- 500 RCPQ140k 0.10 ppm RAW QUAD-COPLANAR 130.1 kHZ 8 1 136 | 137 | 59 501- 508 CPI400_ZLEV 0.10 ppm ZEROLEV INPHASE-COPLANAR 382 HZ 8 1 138 | 60 509- 516 CPQ400_ZLEV 0.10 ppm ZEROLEV QUADRATURE- COPLANAR 382 HZ 8 1 139 | 61 517- 524 CPI1800_ZLEV 0.10 ppm ZEROLEV INPHASE-COPLANAR 1822 HZ 8 1 140 | 62 525- 532 CPQ1800_ZLEV 0.10 ppm ZEROLEV QUAD- COPLANAR 1822 HZ 8 1 141 | 63 533- 540 CXI3300_ZLEV 0.10 ppm ZEROLEV INPHASE-COPLANAR 3258 HZ 8 1 142 | 64 541- 548 CXQ3300_ZLEV 0.10 ppm ZEROLEV QUAD-COPLANAR 3258 HZ 8 1 143 | 65 549- 556 CPI8200_ZLEV 0.10 ppm ZEROLEV INPHASE -COPLANAR 7970 HZ 8 1 144 | 66 557- 564 CPQ8200_ZLEV 0.10 ppm ZEROLEV QUAD -COPLANAR 7970 HZ 8 1 145 | 67 565- 572 CPI40k_ZLEV 0.10 ppm ZEROLEV INPHASE -COPLANAR 35920 HZ 8 1 146 | 68 573- 580 CPQ40k_ZLEV 0.10 ppm ZEROLEV QUAD -COPLANAR 35920 HZ 8 1 147 | 69 581- 588 CPI140k_ZLEV 0.10 ppm ZEROLEV INPHASE-COPLANAR 130.1 kHZ 8 1 148 | 70 589- 596 CPQ140k_ZLEV 0.10 ppm ZEROLEV QUAD-COPLANAR 130.1 kHZ 8 1 149 | 150 | 71 597- 604 CPI400_F 0.10 ppm FILTER INPHASE-COPLANAR 382 HZ 8 1 151 | 72 605- 612 CPQ400_F 0.10 ppm FILTER QUADRATURE- COPLANAR 382 HZ 8 1 152 | 73 613- 620 CPI1800_F 0.10 ppm FILTER INPHASE-COPLANAR 1822 HZ 8 1 153 | 74 621- 628 CPQ1800_F 0.10 ppm FILTER QUAD- COPLANAR 1822 HZ 8 1 154 | 75 629- 636 CXI3300_F 0.10 ppm FILTER INPHASE-COAXIAL 3258 HZ 8 1 155 | 76 637- 644 CXQ3300_F 0.10 ppm FILTER QUAD-COAXIAL 3258 HZ 8 1 156 | 77 645- 652 CPI8200_F 0.10 ppm FILTER INPHASE -COPLANAR 7970 HZ 8 1 157 | 78 653- 660 CPQ8200_F 0.10 ppm FILTER QUAD -COPLANAR 7970 HZ 8 1 158 | 79 661- 668 CPI40k_F 0.10 ppm FILTER INPHASE -COPLANAR 35920 HZ 8 1 159 | 80 669- 676 CPQ40k_F 0.10 ppm FILTER QUAD -COPLANAR 35920 HZ 8 1 160 | 81 677- 888 CPI140k_F 0.10 ppm FILTER INPHASE-COPLANAR 130.1 kHZ 8 1 161 | 82 685- 692 CPQ140k_F 0.10 ppm FILTER QUAD-COPLANAR 130.1 kHZ 8 1 162 | 163 | 83 693- 700 CPI400 0.10 ppm FINAL INPHASE-COPLANAR 382 HZ 8 1 164 | 84 701- 708 CPQ400 0.10 ppm FINAL QUADRATURE- COPLANAR 382 HZ 8 1 165 | 85 709- 716 CPI1800 0.10 ppm FINAL INPHASE-COPLANAR 1822 HZ 8 1 166 | 86 717- 724 CPQ1800 0.10 ppm FINAL QUAD- COPLANAR 1822 HZ 8 1 167 | 87 725- 732 CXI3300 0.10 ppm FINAL INPHASE-COAXIAL 3258 HZ 8 1 168 | 88 733- 740 CXQ3300 0.10 ppm FINAL QUAD-COAXIAL 3258 HZ 8 1 169 | 89 741- 748 CPI8200 0.10 ppm FINAL INPHASE -COPLANAR 7970 HZ 8 1 170 | 90 749- 756 CPQ8200 0.10 ppm FINAL QUAD -COPLANAR 7970 HZ 8 1 171 | 91 757- 764 CPI40k 0.10 ppm FINAL INPHASE -COPLANAR 35920 HZ 8 1 172 | 92 765- 772 CPQ40k 0.10 ppm FINAL QUAD -COPLANAR 35920 HZ 8 1 173 | 93 773- 780 CPI140k 0.10 ppm FINAL INPHASE-COPLANAR 130.1 kHZ 8 1 174 | 94 781- 788 CPQ140k 0.10 ppm FINAL QUAD-COPLANAR 130.1 kHZ 8 1 175 | 176 | 95 789- 797 APPCOND400 0.10 mS/m APP COND COPLANAR 382 HZ 9 1 177 | 96 798- 806 APPCOND1800 0.10 mS/m APP COND COPLANAR 1822 HZ 9 1 178 | 97 807- 815 APPCOND8200 0.10 mS/m APP COND COPLANAR 7970 HZ 9 1 179 | 98 816- 824 APPCOND40k 0.10 mS/m APP COND COPLANAR 35920 HZ 9 1 180 | 99 825- 833 APPCOND140k 0.10 mS/m APP COND COPLANAR 130.1 KHZ 9 1 181 | 100 834- 841 Dep400 0.10 m APP DEPTH COPLANAR 382 HZ 8 1 182 | 101 842- 849 Dep1800 0.10 m APP DEPTH COPLANAR 1822 HZ 8 1 183 | 102 850- 857 Dep8200 0.10 m APP DEPTH COPLANAR 7970 HZ 8 1 184 | 103 858- 865 Dep40k 0.10 m APP DEPTH COPLANAR 35920 HZ 8 1 185 | 104 866- 873 Dep140k 0.10 m APP DEPTH COPLANAR 130.1 KHZ 8 1 186 | 187 | 105 874- 884 MAG_FINAL 0.10 nT Total Field Magnetics 11 2 188 | 189 | 190 | 191 | 192 | Please Note: 193 | 194 | The flight number has a system number followed by the actual flight number. For this system, the system number is 12. 195 | For example, flight 12058 is actually flight 58. Each time the system is turned on and off, the data acquisition system 196 | assigns a new flight. 197 | 198 | Attitude measurements have the following sense: 199 | Port side high = positive roll; Starbord side high = negative roll 200 | Nose up = positive pitch; nose down = negative pitch 201 | 202 | There were no repeat lines flown for the Bookpurnong block. 203 | 204 | All dummy values have been replaced with -999.0 205 | 206 | 207 | -------------------------------------------------------------------------------- /data/bookpurnong/Bookpurnong_SkyTEM.HDR: -------------------------------------------------------------------------------- 1 | 2 | BOOKPURNONG SKYTEM SURVEY: RAW LOCATED EM DATA 3 | 4 | 5 | Survey Specifications: 6 | 7 | Date flown/compiled 02 - 05 November 2006 8 | Area name Bookpurnong, SA 9 | EM system SkyTEM 10 | Datum GDA94/MGA Zone 54 11 | Description Survey flown at production altitude in both high and low Tx moment modes 12 | 13 | 14 | System Geometry: 15 | 16 | The nominal transmitter-receiver geometry is: 17 | 18 | transmitter terrain clearance = 30 metres 19 | 20 | vertical (z) component receiver coil: 12.40 m behind and 2.09 m above Tx loop centre (in-loop) 21 | z-component receiver terrain clearance (nominal): 32.09 m 22 | z-component receiver effective area: 31.4 m^2 23 | 24 | horizontal in-line (x) component receiver coil: 13.69 m behind and 0.0 m above Tx loop centre (in-loop) 25 | x-component receiver terrain clearance (nominal): 30 m 26 | x-component receiver effective area: 31.4 m^2 27 | 28 | 29 | Electromagnetic System: 30 | 31 | SkyTEM is a time-domain electromagnetic system, capable of operating in a dual transmitter mode: 32 | 33 | - Low moment mode where low current, high base frequency and fast switch off provide early time data for shallow imaging; 34 | - High moment mode, where a higher current and lower base frequency provides high quality late time data for deep imaging. 35 | 36 | It is important to note that the two modes run sequentially, (although the low moment mode only uses one Tx turn). 37 | The exact sequencing can be digitally programmed to trade off vertical versus horizontal resolution for specific applications. 38 | The system can thus be used in either the low or high moment mode, or in this combined (dual) mode. 39 | 40 | Transmitter base frequency: 25 Hz in high moment mode (half period 20 ms; nominal Tx on-time 10 ms; off-time 10 ms); 41 | 222.22 Hz in low moment mode (half period 2.25 ms; nominal Tx on-time 0.8 ms; off-time 1.45 ms) 42 | 43 | Transmitter waveform: Bipolar 44 | 45 | A piecewise linear approximation to a half cycle of the 222.22 Hz high moment current waveform is given below: 46 | 47 | 48 | Time (ms) Current (% of peak) 49 | -0.80 0 50 | -0.77 20 51 | -0.75 40 52 | -0.71 60 53 | -0.64 80 54 | -0.58 90 55 | -0.51 95 56 | -0.40 99.04 57 | -0.30 100 58 | 0.00 100 59 | 0.00289 0.6 60 | 0.00348 0.2 61 | 0.00406 0.0 62 | 1.45000 0.0 63 | 64 | 65 | 66 | 67 | A piecewise linear approximation to a half cycle of the 25 Hz high moment current waveform is given below: 68 | 69 | 70 | Time (ms) Current (% of peak) 71 | -10 0 72 | -9.29 20 73 | -8.41 40 74 | -7.26 60 75 | -5.28 80 76 | -3.62 90 77 | -2.33 95 78 | -0.62 99 79 | 0.00 100 80 | 0.0266 1.53 81 | 0.0276 0.566 82 | 0.0286 0.000 83 | 10.000 0.000 84 | 85 | 86 | Tx area: 313.98 m^2 87 | Number of Tx turns: 4 in high moment mode; 1 in low moment mode 88 | Peak current: 90 A in high moment mode; 40 A in low moment mode (typical) 89 | Tx turn-off time: 29 microseconds in high moment mode; 4 microseconds in low moment mode 90 | 91 | 92 | 93 | Receiver window times are measured from the START of the Tx current turn-off: 94 | 95 | In low Tx moment mode, the 20 window times (in seconds) are: 96 | 97 | SkyTEM 98 | Window Window centre Window start Window width 99 | No sec sec sec 100 | 2 118e-7 1.01E-05 3.70E-06 101 | 3 181e-7 1.65E-05 3.70E-06 102 | 4 246e-7 2.29E-05 3.70E-06 103 | 5 310e-7 2.93E-05 3.70E-06 104 | 6 374e-7 3.57E-05 3.70E-06 105 | 7 470e-7 4.19E-05 1.01E-05 106 | 8 598e-7 5.47E-05 1.01E-05 107 | 9 726e-7 6.75E-05 1.01E-05 108 | 10 886e-7 8.03E-05 1.65E-05 109 | 11 1118e-7 1.01E-04 2.13E-05 110 | 12 1454e-7 1.30E-04 3.06E-05 111 | 13 1852e-7 1.66E-04 3.34E-05 112 | 14 2344e-7 2.10E-04 4.70E-05 113 | 15 2952e-7 2.64E-04 5.66E-05 114 | 16 3706e-7 3.31E-04 7.90E-05 115 | 17 4644e-7 4.15E-04 9.78E-05 116 | 18 5814e-7 5.19E-04 1.22E-04 117 | 19 7278e-7 6.49E-04 1.58E-04 118 | 20 9112e-7 8.12E-04 1.94E-04 119 | 21 11170e-7 1.02E-03 2.46E-04 120 | 121 | 122 | In high Tx moment mode, the times (in seconds) for the 24 windows are: 123 | 124 | SkyTEM 125 | Window Window centre Window start Window width 126 | No sec sec sec 127 | 7 470e-7 4.19E-05 1.01E-05 128 | 8 598e-7 5.47E-05 1.01E-05 129 | 9 726e-7 6.75E-05 1.01E-05 130 | 10 886e-7 8.03E-05 1.65E-05 131 | 11 1118e-7 1.01E-04 2.13E-05 132 | 12 1454e-7 1.30E-04 3.06E-05 133 | 13 1852e-7 1.66E-04 3.34E-05 134 | 14 2344e-7 2.10E-04 4.70E-05 135 | 15 2952e-7 2.64E-04 5.66E-05 136 | 16 3706e-7 3.31E-04 7.90E-05 137 | 17 4644e-7 4.15E-04 9.78E-05 138 | 18 5814e-7 5.19E-04 1.22E-04 139 | 19 7278e-7 6.49E-04 1.58E-04 140 | 20 9112e-7 8.12E-04 1.94E-04 141 | 21 11170e-7 1.02E-03 2.46E-04 142 | 22 14292E-7 1.27E-03 3.10E-04 143 | 23 17912E-7 1.59E-03 3.93E-04 144 | 24 22460E-7 2.00E-03 5.02E-04 145 | 25 28174E-7 2.50E-03 6.29E-04 146 | 26 35356E-7 3.14E-03 7.92E-04 147 | 27 44388E-7 3.94E-03 9.97E-04 148 | 28 55750E-7 4.94E-03 1.26E-03 149 | 29 7.00E-03 6.21E-03 1.59E-03 150 | 30 8.80E-03 7.80E-03 2.00E-03 151 | 152 | 153 | 154 | Measured data: 155 | 156 | Vertical and horizontal in-line components of dB/dt. 157 | 158 | The received voltage is averaged over the windows listed above, and then normalised by the 159 | Rx effective area, Tx current, Tx area and number of turns to yield units of V/(A.turns.m^4). 160 | 161 | Data have NOT been corrected for Tx inclination. 162 | 163 | Laser altimeter data HAVE been corrected for Tx inclination 164 | 165 | 166 | 167 | Lines: 168 | 169 | Data from Bookpurnong is contained in tab-delimited ASCII files 170 | 171 | Files: 172 | SK655CS_Bookpurnong_ZX_LM_final.txt contains production survey data in low Tx moment mode 173 | SK655CS_Bookpurnong_ZX_HM_final.txt contains production survey data in high Tx moment mode 174 | 175 | 176 | 177 | Located Data Format: 178 | 179 | Each file has a single text header line, followed by combined line data for the vertical and horizontal in-line components. 180 | 181 | Each file is written in a tab-delimited ascii format :- 182 | 183 | The file format for the high Tx moment data (SK655CS_Bookpurnong_ZX_HM_final.txt) is: 184 | 185 | Col Variable Units 186 | 187 | 1 Fiducial N/A 188 | 2 Line number N/A 189 | 3 Date of start of measurement N/A (GMT) 190 | 4 Time of start of measurement HH:MM:SS.S (GMT - 24 hr clock) 191 | 5 Date of end of measurement N/A (GMT) 192 | 6 Time of end of measurement HH:MM:SS.S (GMT) 193 | 7 System clock N/A 194 | 8 Number of stacks N/A 195 | 9 Tilt angle in in-line direction degrees - nose up +ve 196 | 10 Tilt angle perpendicular to in-line direction degrees - starboard side up +ve 197 | 11 Altitude (laser altimeter) metres 198 | 12 Peak Tx current Amperes 199 | 13 Northing (GDA94/MGA54) metres 200 | 14 Easting (GDA94/MGA54) metres 201 | 15 DGPS Altitude metres 202 | 16 Digital terrain model (= GPS Alt - Laser Alt) metres 203 | 17 Groundspeed km/h 204 | 18 z-component dB/dt data, Window 7 V/(A.turns.m^4) 205 | 19 z-component dB/dt data, Window 8 V/(A.turns.m^4) 206 | 20 z-component dB/dt data, Window 9 V/(A.turns.m^4) 207 | 21 z-component dB/dt data, Window 10 V/(A.turns.m^4) 208 | 22 z-component dB/dt data, Window 11 V/(A.turns.m^4) 209 | 23 z-component dB/dt data, Window 12 V/(A.turns.m^4) 210 | 24 z-component dB/dt data, Window 13 V/(A.turns.m^4) 211 | 25 z-component dB/dt data, Window 14 V/(A.turns.m^4) 212 | 26 z-component dB/dt data, Window 15 V/(A.turns.m^4) 213 | 27 z-component dB/dt data, Window 16 V/(A.turns.m^4) 214 | 28 z-component dB/dt data, Window 17 V/(A.turns.m^4) 215 | 29 z-component dB/dt data, Window 18 V/(A.turns.m^4) 216 | 30 z-component dB/dt data, Window 19 V/(A.turns.m^4) 217 | 31 z-component dB/dt data, Window 20 V/(A.turns.m^4) 218 | 32 z-component dB/dt data, Window 21 V/(A.turns.m^4) 219 | 33 z-component dB/dt data, Window 22 V/(A.turns.m^4) 220 | 34 z-component dB/dt data, Window 23 V/(A.turns.m^4) 221 | 35 z-component dB/dt data, Window 24 V/(A.turns.m^4) 222 | 36 z-component dB/dt data, Window 25 V/(A.turns.m^4) 223 | 37 z-component dB/dt data, Window 26 V/(A.turns.m^4) 224 | 38 z-component dB/dt data, Window 27 V/(A.turns.m^4) 225 | 39 z-component dB/dt data, Window 28 V/(A.turns.m^4) 226 | 40 z-component dB/dt data, Window 29 V/(A.turns.m^4) 227 | 41 z-component dB/dt data, Window 30 V/(A.turns.m^4) 228 | 42 x-component dB/dt data, Window 7 V/(A.turns.m^4) 229 | 43 x-component dB/dt data, Window 8 V/(A.turns.m^4) 230 | 44 x-component dB/dt data, Window 9 V/(A.turns.m^4) 231 | 45 x-component dB/dt data, Window 10 V/(A.turns.m^4) 232 | 46 x-component dB/dt data, Window 11 V/(A.turns.m^4) 233 | 47 x-component dB/dt data, Window 12 V/(A.turns.m^4) 234 | 48 x-component dB/dt data, Window 13 V/(A.turns.m^4) 235 | 49 x-component dB/dt data, Window 14 V/(A.turns.m^4) 236 | 50 x-component dB/dt data, Window 15 V/(A.turns.m^4) 237 | 51 x-component dB/dt data, Window 16 V/(A.turns.m^4) 238 | 52 x-component dB/dt data, Window 17 V/(A.turns.m^4) 239 | 53 x-component dB/dt data, Window 18 V/(A.turns.m^4) 240 | 54 x-component dB/dt data, Window 19 V/(A.turns.m^4) 241 | 55 x-component dB/dt data, Window 20 V/(A.turns.m^4) 242 | 56 x-component dB/dt data, Window 21 V/(A.turns.m^4) 243 | 57 x-component dB/dt data, Window 22 V/(A.turns.m^4) 244 | 58 x-component dB/dt data, Window 23 V/(A.turns.m^4) 245 | 59 x-component dB/dt data, Window 24 V/(A.turns.m^4) 246 | 60 x-component dB/dt data, Window 25 V/(A.turns.m^4) 247 | 61 x-component dB/dt data, Window 26 V/(A.turns.m^4) 248 | 62 x-component dB/dt data, Window 27 V/(A.turns.m^4) 249 | 63 x-component dB/dt data, Window 28 V/(A.turns.m^4) 250 | 64 x-component dB/dt data, Window 29 V/(A.turns.m^4) 251 | 65 x-component dB/dt data, Window 30 V/(A.turns.m^4) 252 | 253 | 254 | 255 | The file format for the low Tx moment data (SK655CS_Bookpurnong_ZX_LM_final.txt) is: 256 | 257 | Col Variable Units 258 | 259 | 1 Fiducial N/A 260 | 2 Line number N/A 261 | 3 Date of start of measurement N/A (GMT) 262 | 4 Time of start of measurement HH:MM:SS.S (GMT - 24 hr clock) 263 | 5 Date of end of measurement N/A (GMT) 264 | 6 Time of end of measurement HH:MM:SS.S (GMT) 265 | 7 System clock N/A 266 | 8 Number of stacks N/A 267 | 9 Tilt angle in in-line direction degrees - nose up +ve 268 | 10 Tilt angle perpendicular to in-line direction degrees - starboard side up +ve 269 | 11 Altitude (laser altimeter) metres 270 | 12 Peak Tx current Amperes 271 | 13 Northing (GDA94/MGA54) metres 272 | 14 Easting (GDA94/MGA54) metres 273 | 15 DGPS Altitude metres 274 | 16 Digital terrain model (= GPS Alt - Laser Alt) metres 275 | 17 Groundspeed km/h 276 | 18 z-component dB/dt data, Window 2 V/(A.turns.m^4) 277 | 19 z-component dB/dt data, Window 3 V/(A.turns.m^4) 278 | 20 z-component dB/dt data, Window 4 V/(A.turns.m^4) 279 | 21 z-component dB/dt data, Window 5 V/(A.turns.m^4) 280 | 22 z-component dB/dt data, Window 6 V/(A.turns.m^4) 281 | 23 z-component dB/dt data, Window 7 V/(A.turns.m^4) 282 | 24 z-component dB/dt data, Window 8 V/(A.turns.m^4) 283 | 25 z-component dB/dt data, Window 9 V/(A.turns.m^4) 284 | 26 z-component dB/dt data, Window 10 V/(A.turns.m^4) 285 | 27 z-component dB/dt data, Window 11 V/(A.turns.m^4) 286 | 28 z-component dB/dt data, Window 12 V/(A.turns.m^4) 287 | 29 z-component dB/dt data, Window 13 V/(A.turns.m^4) 288 | 30 z-component dB/dt data, Window 14 V/(A.turns.m^4) 289 | 31 z-component dB/dt data, Window 15 V/(A.turns.m^4) 290 | 32 z-component dB/dt data, Window 16 V/(A.turns.m^4) 291 | 33 z-component dB/dt data, Window 17 V/(A.turns.m^4) 292 | 34 z-component dB/dt data, Window 18 V/(A.turns.m^4) 293 | 35 z-component dB/dt data, Window 19 V/(A.turns.m^4) 294 | 36 z-component dB/dt data, Window 20 V/(A.turns.m^4) 295 | 37 z-component dB/dt data, Window 21 V/(A.turns.m^4) 296 | 38 x-component dB/dt data, Window 2 V/(A.turns.m^4) 297 | 39 x-component dB/dt data, Window 3 V/(A.turns.m^4) 298 | 40 x-component dB/dt data, Window 4 V/(A.turns.m^4) 299 | 41 x-component dB/dt data, Window 5 V/(A.turns.m^4) 300 | 42 x-component dB/dt data, Window 6 V/(A.turns.m^4) 301 | 43 x-component dB/dt data, Window 7 V/(A.turns.m^4) 302 | 44 x-component dB/dt data, Window 8 V/(A.turns.m^4) 303 | 45 x-component dB/dt data, Window 9 V/(A.turns.m^4) 304 | 46 x-component dB/dt data, Window 10 V/(A.turns.m^4) 305 | 47 x-component dB/dt data, Window 11 V/(A.turns.m^4) 306 | 48 x-component dB/dt data, Window 12 V/(A.turns.m^4) 307 | 49 x-component dB/dt data, Window 13 V/(A.turns.m^4) 308 | 50 x-component dB/dt data, Window 14 V/(A.turns.m^4) 309 | 51 x-component dB/dt data, Window 15 V/(A.turns.m^4) 310 | 52 x-component dB/dt data, Window 16 V/(A.turns.m^4) 311 | 53 x-component dB/dt data, Window 17 V/(A.turns.m^4) 312 | 54 x-component dB/dt data, Window 18 V/(A.turns.m^4) 313 | 55 x-component dB/dt data, Window 19 V/(A.turns.m^4) 314 | 56 x-component dB/dt data, Window 20 V/(A.turns.m^4) 315 | 57 x-component dB/dt data, Window 21 V/(A.turns.m^4) 316 | 317 | 318 | 319 | 320 | -------------------------------------------------------------------------------- /data/bookpurnong/MurrayRiver.txt: -------------------------------------------------------------------------------- 1 | 4.618792999999999884e+05 6.201592900000000373e+06 2 | 4.616067199999999721e+05 6.201521500000000000e+06 3 | 4.613673499999999767e+05 6.201508200000000186e+06 4 | 4.612352399999999907e+05 6.201506799999999814e+06 5 | 4.611035800000000163e+05 6.201493799999999814e+06 6 | 4.609314600000000210e+05 6.201468000000000000e+06 7 | 4.607531199999999953e+05 6.201409400000000373e+06 8 | 4.605941300000000047e+05 6.201316900000000373e+06 9 | 4.604805700000000070e+05 6.201170700000000186e+06 10 | 4.604293599999999860e+05 6.200961099999999627e+06 11 | 4.604467100000000210e+05 6.200714799999999814e+06 12 | 4.605224099999999744e+05 6.200532299999999814e+06 13 | 4.606181699999999837e+05 6.200386000000000000e+06 14 | 4.607300399999999790e+05 6.200210599999999627e+06 15 | 4.608715499999999884e+05 6.200028000000000000e+06 16 | 4.609737399999999907e+05 6.199818500000000000e+06 17 | 4.610117999999999884e+05 6.199650500000000000e+06 18 | 4.609649600000000210e+05 6.199514900000000373e+06 19 | 4.608865100000000093e+05 6.199427400000000373e+06 20 | 4.607988699999999953e+05 6.199380299999999814e+06 21 | 4.606660399999999790e+05 6.199349799999999814e+06 22 | 4.605372999999999884e+05 6.199376200000000186e+06 23 | 4.604305900000000256e+05 6.199403500000000000e+06 24 | 4.603164000000000233e+05 6.199423099999999627e+06 25 | 4.601877100000000210e+05 6.199433299999999814e+06 26 | 4.600251799999999930e+05 6.199482200000000186e+06 27 | 4.599251799999999930e+05 6.199501900000000373e+06 28 | 4.598459000000000233e+05 6.199540400000000373e+06 29 | 4.596491300000000047e+05 6.199615799999999814e+06 30 | 4.595068699999999953e+05 6.199713500000000000e+06 31 | 4.594184099999999744e+05 6.199784299999999814e+06 32 | 4.593450200000000186e+05 6.199831000000000000e+06 33 | 4.592825900000000256e+05 6.199861900000000373e+06 34 | 4.592200700000000070e+05 6.199888799999999814e+06 35 | 4.591232100000000210e+05 6.199908599999999627e+06 36 | 4.590414299999999930e+05 6.199904000000000000e+06 37 | 4.589724799999999814e+05 6.199876299999999814e+06 38 | 4.588953499999999767e+05 6.199833799999999814e+06 39 | 4.588459799999999814e+05 6.199785099999999627e+06 40 | 4.587885100000000093e+05 6.199699000000000000e+06 41 | 4.587739899999999907e+05 6.199615099999999627e+06 42 | 4.587593900000000140e+05 6.199555400000000373e+06 43 | 4.587444099999999744e+05 6.199495700000000186e+06 44 | 4.587459799999999814e+05 6.199441599999999627e+06 45 | 4.587259899999999907e+05 6.199384299999999814e+06 46 | 4.587153300000000163e+05 6.199320200000000186e+06 47 | 4.587155700000000070e+05 6.199249000000000000e+06 48 | 4.587408599999999860e+05 6.199171200000000186e+06 49 | 4.587889199999999837e+05 6.199132700000000186e+06 50 | 4.588376799999999930e+05 6.199114000000000000e+06 51 | 4.588764799999999814e+05 6.199089299999999814e+06 52 | 4.588761699999999837e+05 6.199050799999999814e+06 53 | 4.588393499999999767e+05 6.199020900000000373e+06 54 | 4.587983800000000047e+05 6.198988500000000000e+06 55 | 4.587169000000000233e+05 6.198945700000000186e+06 56 | 4.586871300000000047e+05 6.198940299999999814e+06 57 | 4.586507500000000000e+05 6.198932299999999814e+06 58 | 4.586296599999999744e+05 6.198916400000000373e+06 59 | 4.586145399999999790e+05 6.198877099999999627e+06 60 | 4.585954799999999814e+05 6.198837500000000000e+06 61 | 4.585718499999999767e+05 6.198813700000000186e+06 62 | 4.585414699999999721e+05 6.198790099999999627e+06 63 | 4.585183800000000047e+05 6.198753599999999627e+06 64 | 4.585130100000000093e+05 6.198709599999999627e+06 65 | 4.585425200000000186e+05 6.198661299999999814e+06 66 | 4.585664099999999744e+05 6.198628799999999814e+06 67 | 4.585703800000000047e+05 6.198581900000000373e+06 68 | 4.585667600000000093e+05 6.198540500000000000e+06 69 | 4.585494299999999930e+05 6.198476200000000186e+06 70 | 4.585298699999999953e+05 6.198415400000000373e+06 71 | 4.584853599999999860e+05 6.198351200000000186e+06 72 | 4.584317500000000000e+05 6.198285799999999814e+06 73 | 4.583767500000000000e+05 6.198241500000000000e+06 74 | 4.583206799999999930e+05 6.198197599999999627e+06 75 | 4.582748200000000070e+05 6.198158599999999627e+06 76 | 4.582057199999999721e+05 6.198167000000000000e+06 77 | 4.581411300000000047e+05 6.198190500000000000e+06 78 | 4.580345599999999977e+05 6.198205700000000186e+06 79 | 4.579297800000000279e+05 6.198211500000000000e+06 80 | 4.579455399999999790e+05 6.198166299999999814e+06 81 | 4.580395999999999767e+05 6.198152900000000373e+06 82 | 4.581354400000000023e+05 6.198142400000000373e+06 83 | 4.581946900000000023e+05 6.198120400000000373e+06 84 | 4.582534600000000210e+05 6.198101000000000000e+06 85 | 4.583006799999999930e+05 6.198100799999999814e+06 86 | 4.583317199999999721e+05 6.198149700000000186e+06 87 | 4.583699799999999814e+05 6.198174200000000186e+06 88 | 4.584223699999999953e+05 6.198210000000000000e+06 89 | 4.584569899999999907e+05 6.198243299999999814e+06 90 | 4.585036699999999837e+05 6.198288000000000000e+06 91 | 4.585413200000000070e+05 6.198344400000000373e+06 92 | 4.585821599999999744e+05 6.198401400000000373e+06 93 | 4.586045200000000186e+05 6.198497900000000373e+06 94 | 4.586195200000000186e+05 6.198574500000000000e+06 95 | 4.586114400000000023e+05 6.198634400000000373e+06 96 | 4.585862700000000186e+05 6.198681799999999814e+06 97 | 4.585680999999999767e+05 6.198717000000000000e+06 98 | 4.585701900000000023e+05 6.198745700000000186e+06 99 | 4.585885599999999977e+05 6.198766000000000000e+06 100 | 4.586150399999999790e+05 6.198783000000000000e+06 101 | 4.586502600000000093e+05 6.198803799999999814e+06 102 | 4.586975300000000279e+05 6.198828299999999814e+06 103 | 4.587136699999999837e+05 6.198863500000000000e+06 104 | 4.587326099999999860e+05 6.198891299999999814e+06 105 | 4.587585499999999884e+05 6.198912299999999814e+06 106 | 4.588001500000000233e+05 6.198933400000000373e+06 107 | 4.588342000000000116e+05 6.198955000000000000e+06 108 | 4.588971099999999860e+05 6.198993200000000186e+06 109 | 4.589208900000000140e+05 6.199015299999999814e+06 110 | 4.589282999999999884e+05 6.199052200000000186e+06 111 | 4.589314099999999744e+05 6.199082099999999627e+06 112 | 4.589218599999999860e+05 6.199112099999999627e+06 113 | 4.588930700000000070e+05 6.199140299999999814e+06 114 | 4.588503800000000047e+05 6.199152500000000000e+06 115 | 4.588181699999999837e+05 6.199171099999999627e+06 116 | 4.587780700000000070e+05 6.199205299999999814e+06 117 | 4.587654799999999814e+05 6.199239299999999814e+06 118 | 4.587639899999999907e+05 6.199272900000000373e+06 119 | 4.587687299999999814e+05 6.199311299999999814e+06 120 | 4.587771300000000047e+05 6.199349400000000373e+06 121 | 4.587938300000000163e+05 6.199369000000000000e+06 122 | 4.588228400000000256e+05 6.199339400000000373e+06 123 | 4.588558400000000256e+05 6.199317299999999814e+06 124 | 4.588873200000000070e+05 6.199293799999999814e+06 125 | 4.589168099999999977e+05 6.199272400000000373e+06 126 | 4.589537800000000279e+05 6.199258099999999627e+06 127 | 4.589985800000000163e+05 6.199244900000000373e+06 128 | 4.590928599999999860e+05 6.199210200000000186e+06 129 | 4.591486699999999837e+05 6.199191799999999814e+06 130 | 4.591976799999999930e+05 6.199167099999999627e+06 131 | 4.592510499999999884e+05 6.199142299999999814e+06 132 | 4.592991500000000233e+05 6.199117200000000186e+06 133 | 4.593674899999999907e+05 6.199089599999999627e+06 134 | 4.594333699999999953e+05 6.199061200000000186e+06 135 | 4.594797500000000000e+05 6.199035799999999814e+06 136 | 4.595338599999999860e+05 6.199009299999999814e+06 137 | 4.595851599999999744e+05 6.198980000000000000e+06 138 | 4.596309500000000116e+05 6.198944799999999814e+06 139 | 4.596854000000000233e+05 6.198917000000000000e+06 140 | 4.597277000000000116e+05 6.198879200000000186e+06 141 | 4.597752000000000116e+05 6.198838900000000373e+06 142 | 4.598024099999999744e+05 6.198810700000000186e+06 143 | 4.598311699999999837e+05 6.198776500000000000e+06 144 | 4.598593499999999767e+05 6.198726500000000000e+06 145 | 4.598730000000000000e+05 6.198694400000000373e+06 146 | 4.598957399999999907e+05 6.198654599999999627e+06 147 | 4.599305700000000070e+05 6.198553200000000186e+06 148 | 4.599469099999999744e+05 6.198486900000000373e+06 149 | 4.599772700000000186e+05 6.198430200000000186e+06 150 | 4.600223400000000256e+05 6.198389700000000186e+06 151 | 4.600691699999999837e+05 6.198348900000000373e+06 152 | 4.601200000000000000e+05 6.198315299999999814e+06 153 | 4.601662500000000000e+05 6.198291500000000000e+06 154 | 4.602106199999999953e+05 6.198269099999999627e+06 155 | 4.603392299999999814e+05 6.198213799999999814e+06 156 | 4.604452800000000279e+05 6.198209900000000373e+06 157 | 4.605370200000000186e+05 6.198211400000000373e+06 158 | 4.606310700000000070e+05 6.198220299999999814e+06 159 | 4.607097100000000210e+05 6.198242000000000000e+06 160 | 4.608040399999999790e+05 6.198272200000000186e+06 161 | 4.608789600000000210e+05 6.198282200000000186e+06 162 | 4.609477399999999907e+05 6.198289799999999814e+06 163 | 4.610097000000000116e+05 6.198282200000000186e+06 164 | 4.610676099999999860e+05 6.198259000000000000e+06 165 | 4.611012299999999814e+05 6.198223799999999814e+06 166 | 4.611276599999999744e+05 6.198183799999999814e+06 167 | 4.611387800000000279e+05 6.198137200000000186e+06 168 | 4.611367199999999721e+05 6.198082200000000186e+06 169 | 4.611142899999999790e+05 6.198039799999999814e+06 170 | 4.610919400000000023e+05 6.197999299999999814e+06 171 | 4.610619199999999837e+05 6.197961099999999627e+06 172 | 4.610349099999999744e+05 6.197947799999999814e+06 173 | 4.609804899999999907e+05 6.197932599999999627e+06 174 | 4.609272399999999907e+05 6.197933799999999814e+06 175 | 4.608394000000000233e+05 6.197941900000000373e+06 176 | 4.607239799999999814e+05 6.197946700000000186e+06 177 | 4.606615599999999977e+05 6.197955700000000186e+06 178 | 4.606119899999999907e+05 6.197944700000000186e+06 179 | 4.605625000000000000e+05 6.197931200000000186e+06 180 | 4.604643300000000163e+05 6.197915200000000186e+06 181 | 4.603862399999999907e+05 6.197904200000000186e+06 182 | 4.602986500000000233e+05 6.197895799999999814e+06 183 | 4.602016699999999837e+05 6.197879500000000000e+06 184 | 4.601307700000000186e+05 6.197848900000000373e+06 185 | 4.600373200000000070e+05 6.197788099999999627e+06 186 | 4.599892999999999884e+05 6.197730099999999627e+06 187 | 4.599535300000000279e+05 6.197666200000000186e+06 188 | 4.599384899999999907e+05 6.197585500000000000e+06 189 | 4.599460000000000000e+05 6.197508299999999814e+06 190 | 4.599549699999999721e+05 6.197433200000000186e+06 191 | 4.599694099999999744e+05 6.197356200000000186e+06 192 | 4.600186500000000233e+05 6.197279799999999814e+06 193 | 4.600906699999999837e+05 6.197218700000000186e+06 194 | 4.601725000000000000e+05 6.197184200000000186e+06 195 | 4.602458200000000070e+05 6.197167500000000000e+06 196 | 4.603171300000000047e+05 6.197158900000000373e+06 197 | 4.604038099999999977e+05 6.197164099999999627e+06 198 | 4.604665900000000256e+05 6.197181400000000373e+06 199 | 4.605228599999999860e+05 6.197208599999999627e+06 200 | 4.605510100000000093e+05 6.197217000000000000e+06 201 | 4.605527999999999884e+05 6.197218700000000186e+06 202 | 4.605816799999999930e+05 6.197243099999999627e+06 203 | 4.606132700000000186e+05 6.197287099999999627e+06 204 | 4.606701500000000233e+05 6.197336299999999814e+06 205 | 4.607656099999999860e+05 6.197391099999999627e+06 206 | 4.608346699999999837e+05 6.197405299999999814e+06 207 | 4.608773200000000070e+05 6.197396299999999814e+06 208 | 4.609147000000000116e+05 6.197389299999999814e+06 209 | 4.609520999999999767e+05 6.197365700000000186e+06 210 | 4.609876699999999837e+05 6.197327799999999814e+06 211 | 4.610291199999999953e+05 6.197267500000000000e+06 212 | 4.610941099999999860e+05 6.197131299999999814e+06 213 | 4.611371500000000233e+05 6.197017099999999627e+06 214 | 4.611674099999999744e+05 6.196897099999999627e+06 215 | 4.611830399999999790e+05 6.196779299999999814e+06 216 | 4.611822500000000000e+05 6.196666500000000000e+06 217 | 4.611905399999999790e+05 6.196575599999999627e+06 218 | 4.612071799999999930e+05 6.196522200000000186e+06 219 | 4.612348099999999977e+05 6.196473299999999814e+06 220 | 4.612614600000000210e+05 6.196429099999999627e+06 221 | 4.613082600000000093e+05 6.196392500000000000e+06 222 | 4.613459099999999744e+05 6.196362700000000186e+06 223 | 4.614088499999999767e+05 6.196336200000000186e+06 224 | 4.614710100000000093e+05 6.196331000000000000e+06 225 | 4.615355999999999767e+05 6.196329400000000373e+06 226 | 4.616314400000000023e+05 6.196362500000000000e+06 227 | 4.616753200000000070e+05 6.196390299999999814e+06 228 | 4.617072100000000210e+05 6.196438099999999627e+06 229 | 4.617288499999999767e+05 6.196484900000000373e+06 230 | 4.617732999999999884e+05 6.196597000000000000e+06 231 | 4.617793099999999977e+05 6.196636599999999627e+06 232 | 4.617854400000000023e+05 6.196680400000000373e+06 233 | 4.618255900000000256e+05 6.196831000000000000e+06 234 | 4.618504600000000210e+05 6.196917500000000000e+06 235 | 4.618834299999999930e+05 6.197060400000000373e+06 236 | 4.619223300000000163e+05 6.197164299999999814e+06 237 | 4.619831300000000047e+05 6.197295599999999627e+06 238 | 4.620525599999999977e+05 6.197382700000000186e+06 239 | 4.621131500000000233e+05 6.197435099999999627e+06 240 | 4.621748200000000070e+05 6.197487000000000000e+06 241 | 4.622509000000000233e+05 6.197522599999999627e+06 242 | 4.623325200000000186e+05 6.197540900000000373e+06 243 | 4.624037899999999790e+05 6.197538299999999814e+06 244 | 4.625340499999999884e+05 6.197503099999999627e+06 245 | 4.626210700000000070e+05 6.197460200000000186e+06 246 | 4.627405900000000256e+05 6.197384799999999814e+06 247 | 4.628184500000000116e+05 6.197300500000000000e+06 248 | 4.628760000000000000e+05 6.197195400000000373e+06 249 | 4.629045999999999767e+05 6.197101700000000186e+06 250 | 4.629289199999999837e+05 6.196961200000000186e+06 251 | 4.629387500000000000e+05 6.196839500000000000e+06 252 | 4.629432399999999907e+05 6.196716299999999814e+06 253 | 4.629227600000000093e+05 6.196586000000000000e+06 254 | 4.629052199999999721e+05 6.196517299999999814e+06 255 | 4.628416900000000023e+05 6.196426000000000000e+06 256 | 4.627495000000000000e+05 6.196358299999999814e+06 257 | 4.626834000000000233e+05 6.196299799999999814e+06 258 | 4.625780499999999884e+05 6.196229200000000186e+06 259 | 4.625109099999999744e+05 6.196163700000000186e+06 260 | 4.624602500000000000e+05 6.196082799999999814e+06 261 | 4.624285300000000279e+05 6.196011599999999627e+06 262 | 4.624090900000000256e+05 6.195921299999999814e+06 263 | 4.623976400000000140e+05 6.195810200000000186e+06 264 | 4.623864699999999721e+05 6.195679799999999814e+06 265 | 4.624011699999999837e+05 6.195586799999999814e+06 266 | 4.624447100000000210e+05 6.195450200000000186e+06 267 | 4.624952199999999721e+05 6.195355599999999627e+06 268 | 4.625569899999999907e+05 6.195256900000000373e+06 269 | 4.626585800000000163e+05 6.195175099999999627e+06 270 | 4.627250599999999977e+05 6.195130099999999627e+06 271 | 4.628047199999999721e+05 6.195076900000000373e+06 272 | 4.628604799999999814e+05 6.195041400000000373e+06 273 | 4.628738900000000140e+05 6.194971799999999814e+06 274 | 4.628558400000000256e+05 6.194924500000000000e+06 275 | 4.628300000000000000e+05 6.194874799999999814e+06 276 | 4.627925200000000186e+05 6.194829599999999627e+06 277 | 4.627500499999999884e+05 6.194765000000000000e+06 278 | 4.626975100000000093e+05 6.194668099999999627e+06 279 | 4.626201099999999860e+05 6.194559500000000000e+06 280 | 4.625329699999999721e+05 6.194473599999999627e+06 281 | 4.624705700000000070e+05 6.194443700000000186e+06 282 | 4.624063400000000256e+05 6.194418500000000000e+06 283 | 4.623337999999999884e+05 6.194412400000000373e+06 284 | 4.622441400000000140e+05 6.194406900000000373e+06 285 | 4.621489899999999907e+05 6.194404700000000186e+06 286 | 4.620441300000000047e+05 6.194389299999999814e+06 287 | 4.618746199999999953e+05 6.194362099999999627e+06 288 | 4.617235499999999884e+05 6.194356099999999627e+06 289 | 4.615885100000000093e+05 6.194344500000000000e+06 290 | 4.614720599999999977e+05 6.194333099999999627e+06 291 | 4.615075000000000000e+05 6.194142400000000373e+06 292 | 4.616157800000000279e+05 6.194148299999999814e+06 293 | 4.617079699999999721e+05 6.194164900000000373e+06 294 | 4.618254899999999907e+05 6.194206200000000186e+06 295 | 4.619769299999999930e+05 6.194255500000000000e+06 296 | 4.621230000000000000e+05 6.194304799999999814e+06 297 | 4.622158400000000256e+05 6.194320000000000000e+06 298 | 4.623302800000000279e+05 6.194327799999999814e+06 299 | 4.624079699999999721e+05 6.194339299999999814e+06 300 | 4.624767100000000210e+05 6.194350799999999814e+06 301 | 4.625452700000000186e+05 6.194375500000000000e+06 302 | 4.626250599999999977e+05 6.194417400000000373e+06 303 | 4.627300100000000093e+05 6.194503099999999627e+06 304 | 4.627874799999999814e+05 6.194568299999999814e+06 305 | 4.628455200000000186e+05 6.194673000000000000e+06 306 | 4.628804000000000233e+05 6.194727200000000186e+06 307 | 4.629351199999999953e+05 6.194873200000000186e+06 308 | 4.629495300000000279e+05 6.194980099999999627e+06 309 | 4.629498900000000140e+05 6.195022000000000000e+06 310 | 4.629711699999999837e+05 6.195040900000000373e+06 311 | 4.629812199999999721e+05 6.195088500000000000e+06 312 | 4.629600999999999767e+05 6.195111200000000186e+06 313 | 4.629505800000000163e+05 6.195141500000000000e+06 314 | 4.629430000000000000e+05 6.195168000000000000e+06 315 | 4.629096900000000023e+05 6.195166400000000373e+06 316 | 4.628861300000000047e+05 6.195162599999999627e+06 317 | 4.628330999999999767e+05 6.195200599999999627e+06 318 | 4.627384699999999721e+05 6.195262599999999627e+06 319 | 4.626391699999999837e+05 6.195351700000000186e+06 320 | 4.625932600000000093e+05 6.195422700000000186e+06 321 | 4.625642000000000116e+05 6.195495900000000373e+06 322 | 4.625267299999999814e+05 6.195620700000000186e+06 323 | 4.625087100000000210e+05 6.195702700000000186e+06 324 | 4.625019000000000233e+05 6.195810200000000186e+06 325 | 4.625280300000000279e+05 6.195918400000000373e+06 326 | 4.625505800000000163e+05 6.195992599999999627e+06 327 | 4.625868599999999860e+05 6.196073000000000000e+06 328 | 4.626332299999999814e+05 6.196137900000000373e+06 329 | 4.626896099999999860e+05 6.196185400000000373e+06 330 | 4.627755000000000000e+05 6.196256900000000373e+06 331 | 4.628712100000000210e+05 6.196337099999999627e+06 332 | 4.629267100000000210e+05 6.196393900000000373e+06 333 | 4.629595399999999790e+05 6.196424400000000373e+06 334 | 4.629942500000000000e+05 6.196447299999999814e+06 335 | 4.630256799999999930e+05 6.196512299999999814e+06 336 | 4.630418800000000047e+05 6.196610299999999814e+06 337 | 4.630492000000000116e+05 6.196784599999999627e+06 338 | 4.630407999999999884e+05 6.196896700000000186e+06 339 | 4.630115200000000186e+05 6.197042599999999627e+06 340 | 4.629984000000000233e+05 6.197121200000000186e+06 341 | 4.629525800000000163e+05 6.197255900000000373e+06 342 | 4.629145900000000256e+05 6.197359599999999627e+06 343 | 4.628332899999999790e+05 6.197440500000000000e+06 344 | 4.627553300000000163e+05 6.197496099999999627e+06 345 | 4.626906599999999744e+05 6.197548400000000373e+06 346 | 4.626298200000000070e+05 6.197572000000000000e+06 347 | 4.625846199999999953e+05 6.197595500000000000e+06 348 | 4.625452700000000186e+05 6.197613200000000186e+06 349 | 4.624902000000000116e+05 6.197625099999999627e+06 350 | 4.624292899999999790e+05 6.197629000000000000e+06 351 | 4.623466400000000140e+05 6.197640900000000373e+06 352 | 4.622526300000000047e+05 6.197620799999999814e+06 353 | 4.621937899999999790e+05 6.197616700000000186e+06 354 | 4.621021900000000023e+05 6.197588599999999627e+06 355 | 4.620463400000000256e+05 6.197558299999999814e+06 356 | 4.619818499999999767e+05 6.197500099999999627e+06 357 | 4.619023400000000256e+05 6.197407400000000373e+06 358 | 4.618502399999999907e+05 6.197323099999999627e+06 359 | 4.618089299999999930e+05 6.197219700000000186e+06 360 | 4.617931799999999930e+05 6.197122799999999814e+06 361 | 4.617647000000000116e+05 6.197037799999999814e+06 362 | 4.617486799999999930e+05 6.196948099999999627e+06 363 | 4.617233099999999977e+05 6.196860700000000186e+06 364 | 4.617117399999999907e+05 6.196751599999999627e+06 365 | 4.616951699999999837e+05 6.196656400000000373e+06 366 | 4.616796900000000023e+05 6.196570500000000000e+06 367 | 4.616511900000000023e+05 6.196499900000000373e+06 368 | 4.616115000000000000e+05 6.196450000000000000e+06 369 | 4.615615700000000070e+05 6.196420299999999814e+06 370 | 4.614980300000000279e+05 6.196412900000000373e+06 371 | 4.614397399999999907e+05 6.196416500000000000e+06 372 | 4.613829199999999837e+05 6.196442400000000373e+06 373 | 4.613385300000000279e+05 6.196490500000000000e+06 374 | 4.613124299999999930e+05 6.196549799999999814e+06 375 | 4.612818800000000047e+05 6.196620400000000373e+06 376 | 4.612764199999999837e+05 6.196722799999999814e+06 377 | 4.612798099999999977e+05 6.196857900000000373e+06 378 | 4.612704299999999930e+05 6.196956500000000000e+06 379 | 4.612261799999999930e+05 6.197080500000000000e+06 380 | 4.611868200000000070e+05 6.197159400000000373e+06 381 | 4.611394000000000233e+05 6.197240400000000373e+06 382 | 4.610974899999999907e+05 6.197293000000000000e+06 383 | 4.610688499999999767e+05 6.197351400000000373e+06 384 | 4.609957899999999790e+05 6.197436099999999627e+06 385 | 4.609355900000000256e+05 6.197471500000000000e+06 386 | 4.608576300000000047e+05 6.197485200000000186e+06 387 | 4.607699000000000233e+05 6.197482799999999814e+06 388 | 4.606843099999999977e+05 6.197460599999999627e+06 389 | 4.606031400000000140e+05 6.197393599999999627e+06 390 | 4.605337600000000093e+05 6.197329200000000186e+06 391 | 4.604491699999999837e+05 6.197280200000000186e+06 392 | 4.603701599999999744e+05 6.197256700000000186e+06 393 | 4.602715599999999977e+05 6.197248799999999814e+06 394 | 4.601584600000000210e+05 6.197283700000000186e+06 395 | 4.600945700000000070e+05 6.197334700000000186e+06 396 | 4.600612199999999721e+05 6.197384900000000373e+06 397 | 4.600286199999999953e+05 6.197476000000000000e+06 398 | 4.600281300000000047e+05 6.197563200000000186e+06 399 | 4.600855399999999790e+05 6.197669500000000000e+06 400 | 4.601563400000000256e+05 6.197732599999999627e+06 401 | 4.602197399999999907e+05 6.197767000000000000e+06 402 | 4.602967800000000279e+05 6.197782299999999814e+06 403 | 4.603868800000000047e+05 6.197796000000000000e+06 404 | 4.604885000000000000e+05 6.197806000000000000e+06 405 | 4.605573099999999977e+05 6.197814500000000000e+06 406 | 4.606265800000000163e+05 6.197830099999999627e+06 407 | 4.606708499999999767e+05 6.197849599999999627e+06 408 | 4.607441900000000023e+05 6.197863200000000186e+06 409 | 4.607480499999999884e+05 6.197863200000000186e+06 410 | 4.608021300000000047e+05 6.197863299999999814e+06 411 | 4.608910100000000093e+05 6.197857900000000373e+06 412 | 4.609471099999999860e+05 6.197858200000000186e+06 413 | 4.610496199999999953e+05 6.197875799999999814e+06 414 | 4.611039899999999907e+05 6.197903099999999627e+06 415 | 4.611802899999999790e+05 6.197992799999999814e+06 416 | 4.612068300000000163e+05 6.198083400000000373e+06 417 | 4.612065499999999884e+05 6.198183000000000000e+06 418 | 4.611685300000000279e+05 6.198251299999999814e+06 419 | 4.611337399999999907e+05 6.198295500000000000e+06 420 | 4.610535300000000279e+05 6.198357400000000373e+06 421 | 4.609609500000000116e+05 6.198406400000000373e+06 422 | 4.609057500000000000e+05 6.198412099999999627e+06 423 | 4.608683099999999977e+05 6.198417900000000373e+06 424 | 4.608210200000000186e+05 6.198411299999999814e+06 425 | 4.607797100000000210e+05 6.198397000000000000e+06 426 | 4.607030700000000070e+05 6.198365299999999814e+06 427 | 4.605913099999999977e+05 6.198328700000000186e+06 428 | 4.605169699999999721e+05 6.198308000000000000e+06 429 | 4.604015999999999767e+05 6.198311500000000000e+06 430 | 4.603390900000000256e+05 6.198311299999999814e+06 431 | 4.602842899999999790e+05 6.198335500000000000e+06 432 | 4.602142100000000210e+05 6.198369099999999627e+06 433 | 4.601445000000000000e+05 6.198417500000000000e+06 434 | 4.600968599999999860e+05 6.198475900000000373e+06 435 | 4.600474600000000210e+05 6.198536200000000186e+06 436 | 4.599996300000000047e+05 6.198653700000000186e+06 437 | 4.599167199999999721e+05 6.198830099999999627e+06 438 | 4.598407700000000186e+05 6.198948500000000000e+06 439 | 4.597509199999999837e+05 6.199024799999999814e+06 440 | 4.596727800000000279e+05 6.199081099999999627e+06 441 | 4.595905599999999977e+05 6.199131799999999814e+06 442 | 4.594818599999999860e+05 6.199183900000000373e+06 443 | 4.592899299999999930e+05 6.199253200000000186e+06 444 | 4.591834799999999814e+05 6.199287900000000373e+06 445 | 4.590753200000000070e+05 6.199308700000000186e+06 446 | 4.590028200000000070e+05 6.199332599999999627e+06 447 | 4.589538900000000140e+05 6.199361700000000186e+06 448 | 4.589220399999999790e+05 6.199395099999999627e+06 449 | 4.588914400000000023e+05 6.199452200000000186e+06 450 | 4.588787800000000279e+05 6.199493599999999627e+06 451 | 4.588713900000000140e+05 6.199570700000000186e+06 452 | 4.588773599999999860e+05 6.199654400000000373e+06 453 | 4.588963499999999767e+05 6.199692099999999627e+06 454 | 4.589234500000000116e+05 6.199716099999999627e+06 455 | 4.589622600000000093e+05 6.199744200000000186e+06 456 | 4.589978599999999860e+05 6.199747700000000186e+06 457 | 4.590648400000000256e+05 6.199749400000000373e+06 458 | 4.591477700000000186e+05 6.199734700000000186e+06 459 | 4.592226699999999837e+05 6.199702500000000000e+06 460 | 4.593149500000000116e+05 6.199643299999999814e+06 461 | 4.594049899999999907e+05 6.199579900000000373e+06 462 | 4.595005999999999767e+05 6.199510000000000000e+06 463 | 4.596205900000000256e+05 6.199438500000000000e+06 464 | 4.597018900000000140e+05 6.199405599999999627e+06 465 | 4.598048099999999977e+05 6.199375200000000186e+06 466 | 4.598953200000000070e+05 6.199349799999999814e+06 467 | 4.599975900000000256e+05 6.199322900000000373e+06 468 | 4.600972199999999721e+05 6.199314000000000000e+06 469 | 4.601723499999999767e+05 6.199306299999999814e+06 470 | 4.603250999999999767e+05 6.199306500000000000e+06 471 | 4.604068900000000140e+05 6.199300400000000373e+06 472 | 4.604630999999999767e+05 6.199298599999999627e+06 473 | 4.605265200000000186e+05 6.199278799999999814e+06 474 | 4.605952000000000116e+05 6.199257200000000186e+06 475 | 4.606012199999999721e+05 6.199259200000000186e+06 476 | 4.607057600000000093e+05 6.199249500000000000e+06 477 | 4.608497700000000186e+05 6.199265299999999814e+06 478 | 4.609729699999999721e+05 6.199322099999999627e+06 479 | 4.610734799999999814e+05 6.199401599999999627e+06 480 | 4.611185499999999884e+05 6.199496000000000000e+06 481 | 4.611561900000000023e+05 6.199606599999999627e+06 482 | 4.611664899999999907e+05 6.199670599999999627e+06 483 | 4.611674099999999744e+05 6.199757599999999627e+06 484 | 4.611501900000000023e+05 6.199865500000000000e+06 485 | 4.611232399999999907e+05 6.199971400000000373e+06 486 | 4.610587100000000210e+05 6.200045099999999627e+06 487 | 4.609708900000000140e+05 6.200160599999999627e+06 488 | 4.608727600000000093e+05 6.200282799999999814e+06 489 | 4.607384099999999744e+05 6.200472099999999627e+06 490 | 4.606517299999999814e+05 6.200610599999999627e+06 491 | 4.605915100000000093e+05 6.200756400000000373e+06 492 | 4.605824699999999721e+05 6.200847900000000373e+06 493 | 4.605948699999999953e+05 6.200950000000000000e+06 494 | 4.606290499999999884e+05 6.201043299999999814e+06 495 | 4.607223300000000163e+05 6.201180299999999814e+06 496 | 4.608030700000000070e+05 6.201251500000000000e+06 497 | 4.608762299999999814e+05 6.201298599999999627e+06 498 | 4.609575200000000186e+05 6.201328500000000000e+06 499 | 4.610351500000000233e+05 6.201338599999999627e+06 500 | 4.611088800000000047e+05 6.201329000000000000e+06 501 | 4.612366300000000047e+05 6.201311500000000000e+06 502 | 4.614075000000000000e+05 6.201323700000000186e+06 503 | 4.615589799999999814e+05 6.201343400000000373e+06 504 | 4.617209600000000210e+05 6.201375099999999627e+06 505 | 4.619274199999999837e+05 6.201467500000000000e+06 506 | -------------------------------------------------------------------------------- /data/bookpurnong/README.txt: -------------------------------------------------------------------------------- 1 | Bookpurnong Data Sets 2 | ===================== 3 | 4 | The RESOLVE and SkyTEM data collected over Bookpurnong have been made available with permission from CSIRO. Please acknowledge CSIRO if using these data in a presentation, publication, etc. 5 | 6 | Two data sets are included in this distribution, RESOLVE data collected in 2008, and SkyTEM (High Moment) data collected in 2006. 7 | 8 | For an example of how to load and plot the data, please see: http://docs.simpeg.xyz 9 | 10 | 11 | Contents 12 | -------- 13 | 14 | - 8044_Bookpurnong.HDR : RESOLVE header file for the 2008 Bookpurnong survey 15 | - Bookpurnong_Resolve_Exported.XYZ : RESOLVE data collected in 2008 16 | - Bookpurnong_SkyTEM.HDR : SkyTEM header file for the 2006 Bookpurnong survey 17 | - SK655CS_Bookpurnong_ZX_HM_TxInc_newDTM.txt : SkyTEM high moment data collected in 2006 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /dev-requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | matplotlib 4 | ipywidgets 5 | jupyter 6 | pandas 7 | pymatsolver 8 | SimPEG 9 | sphinx 10 | sphinx_rtd_theme 11 | nbsphinx 12 | testipynb 13 | pytest 14 | -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: em-notebooks-environment 2 | 3 | channels: 4 | - conda-forge 5 | - defaults 6 | dependencies: 7 | - numpy 8 | - scipy 9 | - matplotlib 10 | - ipywidgets>=0.6.0 11 | - mkl 12 | - pandas 13 | - pip: 14 | - pymatsolver 15 | - discretize 16 | - SimPEG 17 | -------------------------------------------------------------------------------- /images/cylsetup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simpeg/em-notebooks/c6861c964e994b9644a466d05ba40340ced0d256/images/cylsetup.png -------------------------------------------------------------------------------- /images/finiteVolume-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/simpeg/em-notebooks/c6861c964e994b9644a466d05ba40340ced0d256/images/finiteVolume-02.png -------------------------------------------------------------------------------- /index.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# EM Notebooks\n", 8 | "\n", 9 | "\n", 10 | "\n", 11 | "A collection of notebooks that use the electromagnetics (EM) module of [SimPEG](http://simpeg.xyz). Many of these notebooks reproduce examples from [EM GeoSci](http://em.geosci.xyz), an open source “textbook” on applied electromagnetics.\n", 12 | "\n", 13 | "\n", 14 | "If you build upon these notebooks in your work, please cite:\n", 15 | "\n", 16 | "- [(Cockett et al., 2015)](http://www.sciencedirect.com/science/article/pii/S009830041530056X): *SimPEG: An open source framework for simulation and gradient based parameter estimation in geophysical applications*\n", 17 | "- [(Heagy et al., 2016)](https://arxiv.org/abs/1610.00804): *A framework for simulation and inversion in electromagnetics*\n", 18 | "\n", 19 | "If you have feedback, we would like to hear from you! \n", 20 | "- Contact us\n", 21 | "- Report issues\n", 22 | "- Join the development\n" 23 | ] 24 | }, 25 | { 26 | "cell_type": "markdown", 27 | "metadata": {}, 28 | "source": [ 29 | "**[EM Fundamentals](#EM-Fundamentals) | [Inverting Field Data](Inverting-Field-Data) | [MT Tutorial](#MT-Tutorial) | [Additional Notebooks](#Additional-Notebooks)**\n", 30 | "\n", 31 | "## Contents\n", 32 | "\n", 33 | "### EM Fundamentals\n", 34 | "\n", 35 | "These notebooks walk through using SimPEG for conducting a TDEM and FDEM soundings over a sphere. They use the cylindrically symmetric mesh for the forward modelling\n", 36 | "- [TDEM_vmd_sounding_over_sphere.ipynb](notebooks/TDEM_vmd_sounding_over_sphere.ipynb)\n", 37 | "- [FDEM_vmd_sounding_over_sphere.ipynb](notebooks/FDEM_vmd_sounding_over_sphere.ipynb)\n", 38 | "\n", 39 | "\n", 40 | "### Inverting Field Data\n", 41 | "\n", 42 | "These notebooks walk through inverting a single sounding of airborne EM data collected in Australia. \n", 43 | "- [TDEM_inversion_bookpurnong](notebooks/TDEM_inversion_bookpurnong.ipynb)\n", 44 | "- [FDEM_inversion_bookpurnong](notebooks/FDEM_inversion_bookpurnong.ipynb)\n", 45 | "\n", 46 | "### MT Tutorial\n", 47 | "\n", 48 | "These notebooks were originall published in [The Leading Edge](https://doi.org/10.1190/tle36080696.1)\n", 49 | "\n", 50 | " Seogi Kang , Lindsey J. Heagy , Rowan Cockett , and Douglas W. Oldenburg (2017). ”Exploring nonlinear inversions: A 1D magnetotelluric example.” The Leading Edge, 36(8), 696–699.\n", 51 | "\n", 52 | "\n", 53 | "There are 5 notebooks in this tutorial - we wrote them starting from discretizing the governing equations for the Magnetotelluric Problem, running a forward simulation and exploring an example of non-uniqueness, and performing the inversion. Although this is a natural order in terms of building the pieces, you do not need to work through them in order, each notebook is self-contained and has links to others where appropriate. \n", 54 | "\n", 55 | "- [1_MT1D_NumericalSetup](notebooks/MT_tutorial_1_MT1D_NumericalSetup.ipynb): discretize and solve the 1D MT equations \n", 56 | "- [2_MT1D_ForwardModellingAndNonuniqueness](notebooks/MT_tutorial_2_MT1D_ForwardModellingAndNonuniqueness.ipynb): run the forward simulation and explore an example of non-uniqueness\n", 57 | "- [3_MT1D_5layer_inversion](notebooks/MT_tutorial_3_MT1D_5layer_inversion.ipynb): run inversions for a 5 layer model and explore the impacts of choosing a trade-off parameter $\\beta$, and changing the regularization parameters smoothness and smallness ($\\alpha_s$ and $\\alpha_z$). \n", 58 | "\n", 59 | "There are also 2 \"appendix\" notebooks\n", 60 | "- [Appendix_A_MT1D_Sensitivity](notebooks/MT_tutorial_Appendix_A_MT1D_Sensitivity.ipynb): derive and test the sensitivity \n", 61 | "- [Appendix_B_MT1D_tests](notebooks/MT_tutorial_Appendix_B_MT1D_tests.ipynb): demonstrates how we test the code\n", 62 | "\n", 63 | "\n", 64 | "### Additional Notebooks\n", 65 | "- [DC_Mise-a-la-masse.ipynb](notebooks/DC_Mise-a-la-masse.ipynb)\n", 66 | "- [DC_inversion_2D_example.ipynb](notebooks/DC_inversion_2D_example.ipynb)\n", 67 | "- [FDEM_target_in_solenoid.ipynb](notebooks/FDEM_target_in_solenoid.ipynb)\n", 68 | "- [TDEM_1D_inversion.ipynb](notebooks/TDEM_1D_inversion.ipynb)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "markdown", 73 | "metadata": {}, 74 | "source": [ 75 | "## Running the notebook\n", 76 | "\n", 77 | "From the menu, select `cell`, `run all`, or run each individual cell using `shift + enter`\n", 78 | "\n", 79 | "![cell-run-all](https://em.geosci.xyz/_images/run_all_cells.png)\n", 80 | "\n", 81 | "If you want to start with a clean slate, restart the Kernel either by going to the top, clicking on Kernel: Restart, or by \"esc + 00\" (if you do this, you will need to re-run the following block of code before running any other cells in the notebook) \n", 82 | "\n", 83 | "For more information on running Jupyter notebooks, see the [Jupyter Documentation](https://jupyter.readthedocs.io/en/latest/)" 84 | ] 85 | }, 86 | { 87 | "cell_type": "code", 88 | "execution_count": null, 89 | "metadata": {}, 90 | "outputs": [], 91 | "source": [] 92 | } 93 | ], 94 | "metadata": { 95 | "anaconda-cloud": {}, 96 | "kernelspec": { 97 | "display_name": "Python 3", 98 | "language": "python", 99 | "name": "python3" 100 | }, 101 | "language_info": { 102 | "codemirror_mode": { 103 | "name": "ipython", 104 | "version": 3 105 | }, 106 | "file_extension": ".py", 107 | "mimetype": "text/x-python", 108 | "name": "python", 109 | "nbconvert_exporter": "python", 110 | "pygments_lexer": "ipython3", 111 | "version": "3.6.6" 112 | } 113 | }, 114 | "nbformat": 4, 115 | "nbformat_minor": 1 116 | } 117 | -------------------------------------------------------------------------------- /notebooks/InversionModel-2018-07-22-15-43.txt: -------------------------------------------------------------------------------- 1 | # beta phi_d phi_m phi_m_small phi_m_smoomth_x phi_m_smoomth_y phi_m_smoomth_z phi 2 | 1 4.5905e+01 1.7237e+05 5.7446e+00 3.0677e+00 2.1667e+00 5.1020e-01 0.0000e+00 9.0073e+05 3 | 2 2.2953e+01 5.1968e+04 3.1711e+01 2.0220e+01 9.7547e+00 1.7368e+00 0.0000e+00 1.7264e+05 4 | 3 1.1476e+01 2.6783e+04 1.1745e+02 8.6091e+01 2.6497e+01 4.8632e+00 0.0000e+00 5.2696e+04 5 | 4 5.7382e+00 9.4050e+03 5.6589e+02 4.3343e+02 9.3772e+01 3.8685e+01 0.0000e+00 2.8131e+04 6 | 5 2.8691e+00 3.0645e+03 1.0631e+03 8.3858e+02 1.3914e+02 8.5425e+01 0.0000e+00 1.2652e+04 7 | 6 1.4345e+00 1.3364e+03 1.3256e+03 1.0710e+03 1.3424e+02 1.2037e+02 0.0000e+00 6.1148e+03 8 | 7 7.1727e-01 6.7890e+02 1.5614e+03 1.2558e+03 1.5599e+02 1.4955e+02 0.0000e+00 3.2380e+03 9 | 8 3.5864e-01 4.8067e+02 1.7238e+03 1.3810e+03 1.6344e+02 1.7929e+02 0.0000e+00 1.7988e+03 10 | -------------------------------------------------------------------------------- /notebooks/MT1D.py: -------------------------------------------------------------------------------- 1 | from SimPEG import ( 2 | Problem, Utils, Maps, Props, Mesh, Tests, Survey, Solver as SimpegSolver 3 | ) 4 | import numpy as np 5 | import scipy.sparse as sp 6 | import properties 7 | from scipy.constants import mu_0 8 | 9 | 10 | class MT1DSurvey(Survey.BaseSurvey): 11 | 12 | def __init__(self, srcList, **kwargs): 13 | self.srcList = srcList 14 | Survey.BaseSurvey.__init__(self, **kwargs) 15 | self.getUniqFrequency() 16 | 17 | @property 18 | def nFreq(self): 19 | if getattr(self, '_nFreq', None) is None: 20 | self._nFreq = len(self.frequency) 21 | return self._nFreq 22 | 23 | self.getUniqueTimes() 24 | 25 | def getUniqFrequency(self): 26 | frequency_rx = [] 27 | 28 | rxcount = 0 29 | for src in self.srcList: 30 | for rx in src.rxList: 31 | frequency_rx.append(rx.frequency) 32 | rxcount += 1 33 | freqs_temp = np.hstack(frequency_rx) 34 | self.frequency = np.unique(freqs_temp) 35 | 36 | # TODO: Generalize this so that user can omit specific datum at 37 | # certain frequencies 38 | if (len(freqs_temp) != rxcount * self.nFreq): 39 | raise Exception("# of Frequency of each Rx should be same!") 40 | 41 | @property 42 | def P0(self): 43 | """ 44 | Evaluation matrix at surface 45 | """ 46 | if getattr(self, '_P0', None) is None: 47 | P0 = sp.coo_matrix( 48 | ( 49 | np.r_[1.], (np.r_[0], np.r_[2*self.mesh.nC])), 50 | shape=(1, 2 * self.mesh.nC + 1) 51 | ) 52 | self._P0 = P0.tocsr() 53 | return self._P0 54 | 55 | def eval(self, f): 56 | """ 57 | Project fields to receiver locations 58 | 59 | :param Fields f: fields object 60 | :rtype: numpy.ndarray 61 | :return: data 62 | """ 63 | data = Survey.Data(self) 64 | for src in self.srcList: 65 | for rx in src.rxList: 66 | data[src, rx] = rx.eval(src, f, self.P0) 67 | return data 68 | 69 | def evalDeriv(self): 70 | raise Exception('Use Receivers to project fields deriv.') 71 | 72 | def setMesh(self, sigma=0.1, max_depth_core=3000., ncell_per_skind=10, n_skind=2, core_meshType="linear", max_hz_core=None): 73 | 74 | """ 75 | Set 1D Mesh based using skin depths 76 | 77 | """ 78 | rho = 1./sigma 79 | fmin, fmax = self.frequency.min(), self.frequency.max() 80 | print ( 81 | (">> Smallest cell size = %d m") % (500*np.sqrt(rho/fmax) / ncell_per_skind) 82 | ) 83 | print ( 84 | (">> Padding distance = %d m") % (500*np.sqrt(rho/fmin) * n_skind) 85 | ) 86 | cs = 500*np.sqrt(rho/fmax) / ncell_per_skind 87 | length_bc = 500*np.sqrt(100/fmin) * n_skind 88 | 89 | if core_meshType == "linear": 90 | 91 | max_hz_core = cs 92 | 93 | elif core_meshType == "log": 94 | 95 | if max_hz_core is None: 96 | max_hz_core = cs * 10 97 | 98 | ncz = 2 99 | hz_core = np.logspace(np.log10(cs), np.log10(max_hz_core), ncz) 100 | 101 | while hz_core.sum() < max_depth_core: 102 | ncz += 1 103 | hz_core = np.logspace(np.log10(cs), np.log10(max_hz_core), ncz) 104 | 105 | npad = 1 106 | blength = max_hz_core*1.3**(np.arange(npad)+1) 107 | 108 | while blength < length_bc: 109 | npad += 1 110 | blength = (max_hz_core*1.3**(np.arange(npad)+1)).sum() 111 | print ( 112 | (">> # of padding cells %d") % (npad) 113 | ) 114 | 115 | if core_meshType == "linear": 116 | ncz = int(max_depth_core / cs) 117 | hz = [(cs, npad, -1.3), (cs, ncz)] 118 | elif core_meshType == "log": 119 | hz_pad = max_hz_core * 1.3**(np.arange(npad)+1) 120 | hz = np.r_[hz_pad[::-1], hz_core[::-1]] 121 | 122 | print ( 123 | (">> # of core cells cells %d") % (ncz) 124 | ) 125 | mesh = Mesh.TensorMesh([hz], x0='N') 126 | 127 | return mesh 128 | 129 | 130 | class MT1DSrc(Survey.BaseSrc): 131 | """ 132 | Source class for MT1D 133 | We assume a boundary condition of Ex (z=0) = 1 134 | """ 135 | loc = np.r_[0.] 136 | 137 | 138 | class ZxyRx(Survey.BaseRx): 139 | 140 | def __init__(self, locs, component=None, frequency=None): 141 | self.component = component 142 | self.frequency = frequency 143 | Survey.BaseRx.__init__(self, locs, rxType=None) 144 | 145 | def eval(self, src, f, P0): 146 | Zxy = - 1./(P0*f) 147 | if self.component == "real": 148 | return Zxy.real 149 | elif self.component == "imag": 150 | return Zxy.imag 151 | elif self.component == "both": 152 | return np.r_[Zxy.real, Zxy.imag] 153 | else: 154 | raise NotImplementedError('must be real, imag or both') 155 | 156 | def evalDeriv(self, f, freq, P0, df_dm_v=None, v=None, adjoint=False): 157 | 158 | if adjoint: 159 | 160 | if self.component == "real": 161 | PTvr = (P0.T*v).astype(complex) 162 | dZr_dfT_v = Utils.sdiag((1./(f**2)))*PTvr 163 | return dZr_dfT_v 164 | elif self.component == "imag": 165 | PTvi = P0.T*v*-1j 166 | dZi_dfT_v = Utils.sdiag((1./(f**2)))*PTvi 167 | return dZi_dfT_v 168 | elif self.component == "both": 169 | PTvr = (P0.T*np.r_[v[0]]).astype(complex) 170 | PTvi = P0.T*np.r_[v[1]]*-1j 171 | dZr_dfT_v = Utils.sdiag((1./(f**2)))*PTvr 172 | dZi_dfT_v = Utils.sdiag((1./(f**2)))*PTvi 173 | return dZr_dfT_v + dZi_dfT_v 174 | else: 175 | raise NotImplementedError('must be real, imag or both') 176 | 177 | else: 178 | 179 | dZd_dm_v = P0 * (Utils.sdiag(1./(f**2)) * df_dm_v) 180 | 181 | if self.component == "real": 182 | return dZd_dm_v.real 183 | elif self.component == "imag": 184 | return dZd_dm_v.imag 185 | elif self.component == "both": 186 | return np.r_[dZd_dm_v.real, dZd_dm_v.imag] 187 | else: 188 | raise NotImplementedError('must be real, imag or both') 189 | 190 | @property 191 | def nD(self): 192 | if self.component == "both": 193 | return len(self.frequency) * 2 194 | else: 195 | return len(self.frequency) 196 | 197 | 198 | class AppResPhaRx(ZxyRx): 199 | 200 | def __init__(self, locs, component=None, frequency=None): 201 | super(AppResPhaRx, self).__init__(locs, component, frequency) 202 | 203 | def eval(self, src, f, P0): 204 | Zxy = - 1./(P0*f) 205 | omega = 2*np.pi*self.frequency 206 | if self.component == "appres": 207 | appres = abs(Zxy)**2 / (mu_0*omega) 208 | return appres 209 | elif self.component == "phase": 210 | phase = np.rad2deg(np.arctan(Zxy.imag / Zxy.real)) 211 | return phase 212 | elif self.component == "both": 213 | appres = abs(Zxy)**2 / (mu_0*omega) 214 | phase = np.rad2deg(np.arctan(Zxy.imag / Zxy.real)) 215 | return np.r_[appres, phase] 216 | else: 217 | raise NotImplementedError('must be appres, phase or both') 218 | 219 | def evalDeriv(self, f, freq, P0, df_dm_v=None, v=None, adjoint=False): 220 | 221 | Zxy = - 1./(P0*f) 222 | omega = 2*np.pi*freq 223 | 224 | if adjoint: 225 | 226 | dZa_dZ = Zxy / abs(Zxy) 227 | dappres_dZa = 2. * abs(Zxy) / (mu_0*omega) 228 | dappres_dZ = (dappres_dZa * dZa_dZ) 229 | 230 | if self.component == "appres": 231 | dappres_dZT_v = dappres_dZ.conj() * np.r_[v] 232 | dappres_dfT_v = Utils.sdiag((1./(f**2)))*(P0.T*dappres_dZT_v) 233 | return dappres_dfT_v 234 | elif self.component == "phase": 235 | return np.zeros_like(dappres_dfT_v) 236 | elif self.component == "both": 237 | dappres_dZT_v = dappres_dZ.conj() * np.r_[v[0]] 238 | dappres_dfT_v = Utils.sdiag((1./(f**2)))*(P0.T*dappres_dZT_v) 239 | return dappres_dfT_v 240 | else: 241 | raise NotImplementedError('must be real, imag or both') 242 | 243 | else: 244 | 245 | dZ_dm_v = P0 * (Utils.sdiag(1./(f**2)) * df_dm_v) 246 | 247 | dZa_dZ = Zxy.conjugate() / abs(Zxy) 248 | dappres_dZa = 2. * abs(Zxy) / (mu_0*omega) 249 | dappres_dZ = dappres_dZa * dZa_dZ 250 | dappres_dm_v = (dappres_dZ * dZ_dm_v).real 251 | 252 | if self.component == "appres": 253 | return dappres_dm_v 254 | elif self.component == "phase": 255 | return np.zeros_like(dappres_dm_v) 256 | elif self.component == "both": 257 | return np.r_[dappres_dm_v, np.zeros_like(dappres_dm_v)] 258 | else: 259 | raise NotImplementedError('must be appres, phase or both') 260 | 261 | 262 | class MT1DProblem(Problem.BaseProblem): 263 | """ 264 | 1D Magnetotelluric problem under quasi-static approximation 265 | 266 | """ 267 | 268 | sigma, sigmaMap, sigmaDeriv = Props.Invertible( 269 | "Electrical conductivity (S/m)" 270 | ) 271 | 272 | rho, rhoMap, rhoDeriv = Props.Invertible( 273 | "Electrical resistivity (Ohm-m)" 274 | ) 275 | 276 | Props.Reciprocal(sigma, rho) 277 | 278 | mu = Props.PhysicalProperty( 279 | "Magnetic Permeability (H/m)", 280 | default=mu_0 281 | ) 282 | 283 | surveyPair = Survey.BaseSurvey #: The survey to pair with. 284 | dataPair = Survey.Data #: The data to pair with. 285 | 286 | mapPair = Maps.IdentityMap #: Type of mapping to pair with 287 | 288 | Solver = SimpegSolver #: Type of solver to pair with 289 | solverOpts = {} #: Solver options 290 | 291 | verbose = False 292 | f = None 293 | 294 | def __init__(self, mesh, **kwargs): 295 | Problem.BaseProblem.__init__(self, mesh, **kwargs) 296 | # Setup boundary conditions 297 | mesh.setCellGradBC([['dirichlet', 'dirichlet']]) 298 | 299 | @property 300 | def deleteTheseOnModelUpdate(self): 301 | if self.verbose: 302 | print ("Delete Matrices") 303 | toDelete = [] 304 | if self.sigmaMap is not None or self.rhoMap is not None: 305 | toDelete += ['_MccSigma', '_Ainv', '_ATinv'] 306 | return toDelete 307 | 308 | @property 309 | def Exbc(self): 310 | """ 311 | Boundary value for Ex 312 | """ 313 | if getattr(self, '_Exbc', None) is None: 314 | self._Exbc = np.r_[0., 1.] 315 | return self._Exbc 316 | 317 | #################################################### 318 | # Mass Matrices 319 | #################################################### 320 | 321 | @property 322 | def MccSigma(self): 323 | """ 324 | Diagonal matrix for \\(\\sigma\\). 325 | """ 326 | if getattr(self, '_MccSigma', None) is None: 327 | self._MccSigma = Utils.sdiag(self.sigma) 328 | return self._MccSigma 329 | 330 | def MccSigmaDeriv(self, u): 331 | """ 332 | Derivative of MccSigma with respect to the model 333 | """ 334 | if self.sigmaMap is None: 335 | return Utils.Zero() 336 | 337 | return ( 338 | Utils.sdiag(u) * self.sigmaDeriv 339 | ) 340 | 341 | @property 342 | def MccEpsilon(self): 343 | """ 344 | Diagonal matrix for \\(\\epsilon\\). 345 | """ 346 | if getattr(self, '_MccEpsilon', None) is None: 347 | self._MccEpsilon = Utils.sdiag(self.epsilon) 348 | return self._MccEpsilon 349 | 350 | @property 351 | def MfMu(self): 352 | """ 353 | Edge inner product matrix for \\(\\mu\\). 354 | """ 355 | if getattr(self, '_MMfMu', None) is None: 356 | self._MMfMu = Utils.sdiag( 357 | self.mesh.aveCC2F * self.mu * np.ones(self.mesh.nC) 358 | ) 359 | return self._MMfMu 360 | 361 | #################################################### 362 | # Physics? 363 | #################################################### 364 | 365 | def getA(self, freq): 366 | """ 367 | .. math:: 368 | 369 | \mathbf{A} = 370 | \begin{bmatrix} 371 | \mathbf{Grad} & \imath \omega \mathbf{M}^{f2cc}_{\mu} \\[0.3em] 372 | \mathbf{M}^{cc}_{\hat{\sigma}} & \mathbf{Div} \\[0.3em] 373 | \end{bmatrix} 374 | 375 | """ 376 | 377 | Div = self.mesh.faceDiv 378 | Grad = self.mesh.cellGrad 379 | omega = 2*np.pi*freq 380 | A = sp.vstack( 381 | ( 382 | sp.hstack((Grad, 1j*omega*self.MfMu)), 383 | sp.hstack((self.MccSigma, Div)) 384 | ) 385 | ) 386 | return A 387 | 388 | @property 389 | def Ainv(self): 390 | if getattr(self, '_Ainv', None) is None: 391 | if self.verbose: 392 | print ("Factorize A matrix") 393 | self._Ainv = [] 394 | for freq in self.survey.frequency: 395 | self._Ainv.append(self.Solver(self.getA(freq))) 396 | return self._Ainv 397 | 398 | @property 399 | def ATinv(self): 400 | if getattr(self, '_ATinv', None) is None: 401 | if self.verbose: 402 | print ("Factorize AT matrix") 403 | self._ATinv = [] 404 | for freq in self.survey.frequency: 405 | self._ATinv.append(self.Solver(self.getA(freq).T)) 406 | return self._ATinv 407 | 408 | def getADeriv_sigma(self, freq, f, v, adjoint=False): 409 | Ex = f[:self.mesh.nC] 410 | dMcc_dsig = self.MccSigmaDeriv(Ex) 411 | if adjoint: 412 | return sp.hstack( 413 | (Utils.spzeros(self.mesh.nC, self.mesh.nN), dMcc_dsig.T) 414 | ) * v 415 | else: 416 | return np.r_[np.zeros(self.mesh.nC+1), dMcc_dsig*v] 417 | 418 | def getRHS(self, freq): 419 | """ 420 | .. math:: 421 | 422 | \mathbf{rhs} = 423 | \begin{bmatrix} 424 | - \mathbf{B}\mathbf{E}_x^{bc} \\ [0.3em] 425 | \boldsymbol{0} \\[0.3em] 426 | \end{bmatrix}$ 427 | 428 | """ 429 | B = self.mesh.cellGradBC 430 | RHS = np.r_[-B*self.Exbc, np.zeros(self.mesh.nC)] 431 | return RHS 432 | 433 | def fields(self, m=None): 434 | if self.verbose: 435 | print (">> Compute fields") 436 | 437 | if m is not None: 438 | self.model = m 439 | 440 | f = np.zeros( 441 | (int(self.mesh.nC*2+1), self.survey.nFreq), dtype="complex" 442 | ) 443 | 444 | for ifreq, freq in enumerate(self.survey.frequency): 445 | f[:, ifreq] = self.Ainv[ifreq] * self.getRHS(freq) 446 | return f 447 | 448 | def Jvec(self, m, v, f=None): 449 | 450 | if f is None: 451 | f = self.fields(m) 452 | 453 | Jv = [] 454 | 455 | for src in self.survey.srcList: 456 | for rx in src.rxList: 457 | for ifreq, freq in enumerate(self.survey.frequency): 458 | dA_dm_f_v = self.getADeriv_sigma(freq, f[:, ifreq], v) 459 | df_dm_v = - (self.Ainv[ifreq] * dA_dm_f_v) 460 | Jv.append( 461 | rx.evalDeriv( 462 | f[:, ifreq], freq, self.survey.P0, df_dm_v=df_dm_v 463 | ) 464 | ) 465 | return np.hstack(Jv) 466 | 467 | def Jtvec(self, m, v, f=None): 468 | 469 | if f is None: 470 | f = self.fields(m) 471 | # Ensure v is a data object. 472 | 473 | if not isinstance(v, self.dataPair): 474 | v = self.dataPair(self.survey, v) 475 | 476 | Jtv = np.zeros(m.size) 477 | 478 | for src in self.survey.srcList: 479 | for rx in src.rxList: 480 | for ifreq, freq in enumerate(self.survey.frequency): 481 | if rx.component == "both": 482 | v_temp = v[src, rx].reshape( 483 | (self.survey.nFreq, 2) 484 | )[ifreq, :] 485 | else: 486 | v_temp = v[src, rx][ifreq] 487 | 488 | dZ_dfT_v = rx.evalDeriv( 489 | f[:, ifreq], freq, self.survey.P0, 490 | v=v_temp, adjoint=True 491 | ) 492 | 493 | ATinvdZ_dfT = self.ATinv[ifreq]*dZ_dfT_v 494 | Jtv += - self.getADeriv_sigma( 495 | freq, f[:, ifreq], ATinvdZ_dfT, adjoint=True 496 | ).real 497 | 498 | return Jtv 499 | -------------------------------------------------------------------------------- /notebooks/MT_tutorial_Appendix_A_MT1D_Sensitivity.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "import numpy as np\n", 10 | "import scipy.sparse as sp\n", 11 | "import matplotlib.pyplot as plt\n", 12 | "from SimPEG import Mesh, Utils, Solver\n", 13 | "from scipy.constants import mu_0, epsilon_0\n", 14 | "%matplotlib inline" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "# Sensitivity computuation for 1D magnetotelluric (MT) problem" 22 | ] 23 | }, 24 | { 25 | "cell_type": "markdown", 26 | "metadata": {}, 27 | "source": [ 28 | "## Purpose\n", 29 | "\n", 30 | "With [SimPEG's](http://simpeg.xyz) mesh class, we discretize the sensitivity function for a 1D magnetotelluric problem. Rather than generating the full sensitivity matrix, we compute the forward (`Jvec`) and adjoint (`Jtvec`) functionals that can evalaute matrix-vector product. There are some milestones to be accomplished:\n", 31 | "\n", 32 | "- Break apart senstivity function, $J_{\\sigma}$ into to parts then derive each of them (using chain rules):\n", 33 | "\n", 34 | "$$ \n", 35 | "J_{\\sigma} = \\frac{d P(u)}{d \\sigma} = \\frac{d P(u)}{d u} \\frac{d u}{d \\sigma}\n", 36 | "$$\n", 37 | "\n", 38 | "- Compute forward and adjoint sensitivity function: `Jvec` and `Jtvec`\n", 39 | "\n", 40 | "- Test `Jvec` and `Jtvec`: Order test and Adjoint test" 41 | ] 42 | }, 43 | { 44 | "cell_type": "markdown", 45 | "metadata": {}, 46 | "source": [ 47 | "## Discretzation (forward simulation)\n", 48 | "\n", 49 | "We define physical properties at cell centers, and stagger the electric and magnetic fields\n", 50 | "\n", 51 | "- $\\sigma$, $\\mu$, $\\epsilon$ : cell centers\n", 52 | "- $E_x$: cell centers\n", 53 | "- $H_y$: faces\n", 54 | "\n", 55 | " \n", 56 | "\n", 57 | "and use a finite difference approach to define the operators, this gives us the discrete system of equations\n", 58 | "\n", 59 | "$$\n", 60 | "\\underbrace{\n", 61 | " \\begin{bmatrix}\n", 62 | " \\mathbf{Grad} & \\imath \\omega \\mathbf{M}^{f}_{\\mu} \\\\[0.3em]\n", 63 | " \\mathbf{M}^{cc}_{\\boldsymbol{\\sigma}} & \\mathbf{Div} \\\\[0.3em]\n", 64 | " \\end{bmatrix}\n", 65 | "}_{\\mathbf{A}}\n", 66 | "\\underbrace{\n", 67 | " \\begin{bmatrix}\n", 68 | " \\mathbf{e_x} \\\\[0.3em]\n", 69 | " \\mathbf{h_y} \\\\[0.3em]\n", 70 | " \\end{bmatrix}\n", 71 | "}_{\\mathbf{u}}\n", 72 | "=\n", 73 | "\\underbrace{\n", 74 | " \\begin{bmatrix}\n", 75 | " - \\mathbf{B}\\mathbf{e_x}^{BC} \\\\[0.3em]\n", 76 | " \\boldsymbol{0} \\\\[0.3em]\n", 77 | " \\end{bmatrix}\n", 78 | "}_{\\mathbf{rhs}}\n", 79 | "$$\n", 80 | "\n", 81 | "with \n", 82 | "\n", 83 | "- $\\mathbf{e_x}$: Discrete $E_x$, on cell centers $[\\text{nC} \\times 1]$\n", 84 | "\n", 85 | "- $\\mathbf{h_y}$: Dicrete $H_x$, on cell faces $[(\\text{nC}+1) \\times 1]$\n", 86 | "\n", 87 | "- $ \\mathbf{Grad}$: Discrete gradient operator $[\\text{nC} \\times (\\text{nC}+1)]$\n", 88 | "\n", 89 | "- $ \\mathbf{Div}$: Discrete divergence operator $[(\\text{nC}+1) \\times \\text{nC}]$\n", 90 | "\n", 91 | "- $\\mathbf{M}^{f}_{\\boldsymbol{\\mu}} = \\mathbf{diag}(\\mathbf{Av^{cc2f}} \\boldsymbol{\\mu})$ $[(\\text{nC}+1) \\times (\\text{nC}+1)]$\n", 92 | "\n", 93 | "- $\\mathbf{M}^{cc}_{\\boldsymbol{\\boldsymbol{\\sigma}}} = \\mathbf{diag}(\\boldsymbol{{\\sigma}})$ $[\\text{nC} \\times \\text{nC}]$. Here we are using the quasi-static assumption for brevity. \n", 94 | "\n", 95 | "- $\\mathbf{B} \\mathbf{e_x}^{BC}$ handles the boundary conditions" 96 | ] 97 | }, 98 | { 99 | "cell_type": "markdown", 100 | "metadata": {}, 101 | "source": [ 102 | "## What are the data?\n", 103 | "\n", 104 | "The measured data in general can be defined as:\n", 105 | "\n", 106 | "$$ \\mathbf{d} = P(\\mathbf{u}) $$\n", 107 | "\n", 108 | "where $P(\\cdot)$ is a evaluation functional which takes a solution vector $\\mathbf{u}$ and ouputs data at a receiver location.\n", 109 | "\n", 110 | "Here, we use impedace data (one could also consider using apparent resistivity and phase). The impedance is complex, so we treat the real and imaginary components of each as two separate data points\n", 111 | "\n", 112 | "$$\n", 113 | "Z_{xy} = -\\frac{E_x}{H_y} = \\text{Re}[Z_{xy}] + i ~\\text{Im}[Z_{xy}]\n", 114 | "$$\n" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "metadata": {}, 120 | "source": [ 121 | "The impedance $Z_{xy}$ can be evaluated from the solution vector $\\mathbf{u}$. We will evaluate data at $z=0m$. The solution vector we obtain from the forward simulation is: \n", 122 | "\n", 123 | "$$\n", 124 | "\\mathbf{u} = \n", 125 | " \\begin{bmatrix}\n", 126 | " \\mathbf{e_x} \\\\[0.3em]\n", 127 | " \\mathbf{h_y} \\\\[0.3em]\n", 128 | " \\end{bmatrix}\n", 129 | "$$\n", 130 | "\n", 131 | "At the surface, we specified the boundary condition that $E_x(z=0) = 1$. So what we need $P(\\dot)$ to accomplish is \n", 132 | "$$\n", 133 | "Z_{xy}\\big|_{z=0} = -\\frac{1}{h_y(z=0)}\n", 134 | "$$\n", 135 | "\n", 136 | "Thus, $P(\\dot)$ can be defined as an interpolation matrix that simply extracts the value of $h_y$ at the surface. We denote this matrix: $\\mathbf{P}_{0}$ (Thinking in terms of matrices is very helpful when we get to the step of taking derivatives!)\n", 137 | "\n", 138 | "$$\\mathbf{d} = Z_{xy} = - \\mathbf{P}_{0}\\left(\\frac{1}{\\mathbf{u}}\\right) $$\n", 139 | "\n", 140 | "From complex-values $Z_{xy}$, we can compute real and imagniary part of the $Z_{xy}$ then the data can be defined as:\n", 141 | "\n", 142 | "$$\n", 143 | "\\mathbf{d} = \\begin{bmatrix}\n", 144 | " \\text{Re}[Z_{xy}] \\\\[0.3em]\n", 145 | " \\text{Im}[Z_{xy}] \\\\[0.3em]\n", 146 | "\\end{bmatrix}\n", 147 | "$$\n", 148 | "\n", 149 | "We will set up an example and go through the steps to compute a datum. " 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": {}, 155 | "source": [ 156 | "### Set up Mesh and Model" 157 | ] 158 | }, 159 | { 160 | "cell_type": "code", 161 | "execution_count": 2, 162 | "metadata": {}, 163 | "outputs": [], 164 | "source": [ 165 | "def skin_depth(sigma, f):\n", 166 | " \"\"\"\n", 167 | " Depth at which the fields propagating through a homogeneous medium \n", 168 | " have decayed by a factor of 1/e for a given frequency, f and conductivity, sigma\n", 169 | " \"\"\"\n", 170 | " return 500./np.sqrt(sigma * f)" 171 | ] 172 | }, 173 | { 174 | "cell_type": "code", 175 | "execution_count": 3, 176 | "metadata": {}, 177 | "outputs": [ 178 | { 179 | "name": "stdout", 180 | "output_type": "stream", 181 | "text": [ 182 | "The minimum skin depth is 500.00m\n", 183 | "The maximum skin depth is 1.58e+05m\n" 184 | ] 185 | } 186 | ], 187 | "source": [ 188 | "rho_half = 100. # Resistivity of the halfspace in Ohm-m\n", 189 | "sigma_half = 1./rho_half # Conductivity is the inverse of conductivity\n", 190 | "frequency = np.logspace(-3, 2, 25) # frequencies at which to simulate the MT problem\n", 191 | "\n", 192 | "skin_depth_min = skin_depth(sigma_half, frequency.max())\n", 193 | "skin_depth_max = skin_depth(sigma_half, frequency.min())\n", 194 | "\n", 195 | "print(\"The minimum skin depth is {:1.2f}m\".format(skin_depth_min))\n", 196 | "print(\"The maximum skin depth is {:1.2e}m\".format(skin_depth_max))" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": 4, 202 | "metadata": {}, 203 | "outputs": [ 204 | { 205 | "name": "stdout", 206 | "output_type": "stream", 207 | "text": [ 208 | "The smallest cell size is 125.00m\n", 209 | "The core region of the mesh extends 5.00e+03m\n", 210 | "The mesh should extend at least 3.16e+05m\n" 211 | ] 212 | } 213 | ], 214 | "source": [ 215 | "cs = skin_depth_min / 4.\n", 216 | "core_extent = 5000. \n", 217 | "domain_extent = 2 * skin_depth_max\n", 218 | "\n", 219 | "print(\"The smallest cell size is {:1.2f}m\".format(cs))\n", 220 | "print(\"The core region of the mesh extends {:1.2e}m\".format(core_extent))\n", 221 | "print(\"The mesh should extend at least {:1.2e}m\".format(domain_extent))" 222 | ] 223 | }, 224 | { 225 | "cell_type": "markdown", 226 | "metadata": {}, 227 | "source": [ 228 | "Add padding to extend sufficiently far" 229 | ] 230 | }, 231 | { 232 | "cell_type": "code", 233 | "execution_count": 5, 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "name": "stdout", 238 | "output_type": "stream", 239 | "text": [ 240 | "25 padding cells extends 3.82e+05m > 3.16e+05m (2 skin depths)\n" 241 | ] 242 | } 243 | ], 244 | "source": [ 245 | "npad = 1 # start with 1 cell\n", 246 | "padding_fact = 1.3 # the amount by which we will expand each cell of the padding\n", 247 | "\n", 248 | "def padding_extent(npad):\n", 249 | " \"\"\"\n", 250 | " given a number of padding cells, this computes how far the padding extends\n", 251 | " \"\"\"\n", 252 | " padding_widths = cs*padding_fact**(np.arange(npad) + 1)\n", 253 | " return padding_widths.sum()\n", 254 | "\n", 255 | "# keep adding padding until we are beyond the desired extent\n", 256 | "padding_z = padding_extent(npad)\n", 257 | "while padding_z < domain_extent:\n", 258 | " npad+=1\n", 259 | " padding_z = padding_extent(npad)\n", 260 | " \n", 261 | "print(\"{:1.0f} padding cells extends {:1.2e}m > {:1.2e}m (2 skin depths)\".format(\n", 262 | " npad, padding_extent(npad), domain_extent\n", 263 | "))" 264 | ] 265 | }, 266 | { 267 | "cell_type": "code", 268 | "execution_count": 6, 269 | "metadata": {}, 270 | "outputs": [ 271 | { 272 | "name": "stdout", 273 | "output_type": "stream", 274 | "text": [ 275 | "There are 40 cells in the mesh. The mest extends 3.87e+05m\n" 276 | ] 277 | } 278 | ], 279 | "source": [ 280 | "ncz = np.ceil(core_extent / cs) # number of cells in the core domain\n", 281 | "hz = [(cs, npad, -1.3), (cs, ncz)] # define how to construct the cell widths\n", 282 | "mesh = Mesh.TensorMesh([hz], x0='N') # construct a 1D Tensor Mesh\n", 283 | "\n", 284 | "print(\"There are {:1.0f} cells in the mesh. The mest extends {:1.2e}m\".format(\n", 285 | " ncz, mesh.hx.sum()\n", 286 | ")) \n", 287 | "\n", 288 | "sigma = np.ones(mesh.nC) * sigma_half" 289 | ] 290 | }, 291 | { 292 | "cell_type": "markdown", 293 | "metadata": {}, 294 | "source": [ 295 | "### Forward simulation function\n", 296 | "\n", 297 | "Forward simulation function `dpred` takes conductivity model (`nCx1`), and frequency (`1x1`), and outputs real and imaginary part of the impedance, $Z_{xy}$ (`2x1`). By solving $\\mathbf{A} \\mathbf{u}=\\mathbf{rhs}$, we compute solution vector $\\mathbf{u}$, then evaluate real and imaginary part of impedance at $z=0$ ($\\mathbf{d} = P(\\mathbf{u})$). " 298 | ] 299 | }, 300 | { 301 | "cell_type": "code", 302 | "execution_count": 7, 303 | "metadata": {}, 304 | "outputs": [ 305 | { 306 | "name": "stdout", 307 | "output_type": "stream", 308 | "text": [ 309 | "The projection matrix has shape (1, 131) with 1 non-zero entry at (0,130)\n" 310 | ] 311 | } 312 | ], 313 | "source": [ 314 | "# Projection Matrix\n", 315 | "P0 = sp.csr_matrix(\n", 316 | " (np.r_[1.], (np.r_[0], np.r_[mesh.nF+mesh.nC-1])), shape=(1, mesh.nF+mesh.nC)\n", 317 | " )\n", 318 | "\n", 319 | "print(\n", 320 | " \"The projection matrix has shape {} with {} non-zero entry at ({},{})\".format(\n", 321 | " P0.shape, P0.nnz, P0.nonzero()[0][0], P0.nonzero()[1][0]\n", 322 | " )\n", 323 | ")\n" 324 | ] 325 | }, 326 | { 327 | "cell_type": "code", 328 | "execution_count": 8, 329 | "metadata": {}, 330 | "outputs": [], 331 | "source": [ 332 | "def dpred(sigma, f=100.):\n", 333 | " \n", 334 | " # angular frequency\n", 335 | " omega = f*2.*np.pi\n", 336 | " \n", 337 | " # physical properties\n", 338 | " mu = np.ones(mesh.nC)*mu_0 # magnetic permeability values for all cells\n", 339 | " sigmahat = sigma.copy() # here we are ignoring displacement current\n", 340 | " \n", 341 | " # Grad \n", 342 | " mesh.setCellGradBC([['dirichlet', 'dirichlet']]) # Setup boundary conditions\n", 343 | " Grad = mesh.cellGrad # Gradient matrix\n", 344 | "\n", 345 | " # MfMu\n", 346 | " Mmu = Utils.sdiag(mesh.aveCC2F * mu) \n", 347 | " \n", 348 | " # Mccsigma\n", 349 | " Msighat = Utils.sdiag(sigmahat) \n", 350 | " \n", 351 | " # Div\n", 352 | " Div = mesh.faceDiv # Divergence matrix\n", 353 | " \n", 354 | " # Right Hand Side\n", 355 | " B = mesh.cellGradBC # a matrix for boundary conditions\n", 356 | " Exbc = np.r_[0., 1.] # boundary values for Ex\n", 357 | "\n", 358 | " # A-matrix\n", 359 | " A = sp.vstack([\n", 360 | " sp.hstack([Grad, 1j*omega*Mmu]), # Top row of A matrix\n", 361 | " sp.hstack((Msighat, Div)) # Bottom row of A matrix\n", 362 | " ])\n", 363 | " \n", 364 | " # Right-hand side\n", 365 | " rhs = np.r_[\n", 366 | " -B*Exbc, \n", 367 | " np.zeros(mesh.nC)\n", 368 | " ] \n", 369 | "\n", 370 | " Ainv = Solver(A) # Factor A matrix\n", 371 | " u = Ainv*rhs # Solve A^-1 rhs = u\n", 372 | "\n", 373 | " # build the projection matrix, a sparse matrix that has 1 entry to grab the value of h_y at the surface\n", 374 | " P0 = sp.csr_matrix(\n", 375 | " (np.r_[1.], (np.r_[0], np.r_[len(u)-1])), shape=(1, len(u))\n", 376 | " )\n", 377 | " \n", 378 | " Zxy = - P0 * (1./(u))\n", 379 | " \n", 380 | " return np.r_[Zxy.real, Zxy.imag]" 381 | ] 382 | }, 383 | { 384 | "cell_type": "code", 385 | "execution_count": 9, 386 | "metadata": {}, 387 | "outputs": [ 388 | { 389 | "name": "stdout", 390 | "output_type": "stream", 391 | "text": [ 392 | "At f=100.0Hz, we have two data. \n", 393 | "Re[Z] = 0.196, Im[Z] = 0.202\n" 394 | ] 395 | } 396 | ], 397 | "source": [ 398 | "f = 100.\n", 399 | "data = dpred(sigma, f=f)\n", 400 | "\n", 401 | "print(\"At f={}Hz, we have two data. \\nRe[Z] = {:1.3f}, Im[Z] = {:1.3f}\".format(f, data[0], data[1]))" 402 | ] 403 | }, 404 | { 405 | "cell_type": "markdown", 406 | "metadata": {}, 407 | "source": [ 408 | "## Sensitivity of datum with regard to $\\sigma$:\n", 409 | "\n", 410 | "The sensitivity function shows how much the data are changed due to changes in model paramters. Understanding how \"sensitive\" our data are to the model is important for survey design. It is essential that we be able to compute the sensitivity when using gradient-based optimization techniques, as the sensitivity gives us the direction in which to take a step and update the model as we search for a solution. \n", 411 | "\n", 412 | "The sensitivity function can be defined as \n", 413 | "\n", 414 | "$$ J_{\\sigma} = \\frac{d P(u)}{d \\sigma}$$\n", 415 | "\n", 416 | "The size of the sensitivity is $[nD \\times n\\sigma]$" 417 | ] 418 | }, 419 | { 420 | "cell_type": "markdown", 421 | "metadata": {}, 422 | "source": [ 423 | "To obtain above sensitivity function in discrete space, we first differentiate \n", 424 | "\n", 425 | "$$\\mathbf{A}\\mathbf{u} = \\mathbf{rhs}$$\n", 426 | "\n", 427 | "w.r.t ${\\boldsymbol{\\sigma}}$, which yields \n", 428 | "\n", 429 | "$$ \\frac{d \\mathbf{A}}{d {\\boldsymbol{\\sigma}}}\\mathbf{u} + \\mathbf{A} \\frac{d \\mathbf{u} }{d {\\boldsymbol{\\sigma}}}= 0 $$\n", 430 | "\n", 431 | "Rearranging and multiplyting by $\\mathbf{A}^{-1}$ on both sides yields\n", 432 | "\n", 433 | "$$ \\frac{d \\mathbf{u} }{d {\\boldsymbol{\\sigma}}}= -\\mathbf{A}^{-1}\\frac{d \\mathbf{A}}{d {\\boldsymbol{\\sigma}}}\\mathbf{u} $$\n", 434 | "\n", 435 | "Next, we need to include the evaluation, $\\mathbf{d} = P(\\mathbf{u})$ which is the operation taken on $\\mathbf{u}$ to give us the data. From this, we obtain\n", 436 | "\n", 437 | "$$ \\mathbf{J}_{{\\boldsymbol{\\sigma}}} = \n", 438 | "\\frac{\\partial P(\\mathbf{u})}{\\partial {\\mathbf{u}}}\\Big(\\frac{d \\mathbf{u} }{d {\\boldsymbol{\\sigma}}}\\Big) = \n", 439 | "-\\frac{\\partial P(\\mathbf{u})}{\\partial {\\mathbf{u}}} \\Big(\\mathbf{A}^{-1}\\frac{d \\mathbf{A}}{d {\\boldsymbol{\\sigma}}}\\mathbf{u}\\Big) $$" 440 | ] 441 | }, 442 | { 443 | "cell_type": "markdown", 444 | "metadata": {}, 445 | "source": [ 446 | "From this, there are two derivatives need to be computed:\n", 447 | "\n", 448 | "1. $$\\frac{d \\mathbf{A}}{d \\boldsymbol{\\sigma}}\\mathbf{u}=?$$\n", 449 | "\n", 450 | "2. $$\\frac{\\partial P(\\mathbf{u})}{\\partial \\mathbf{u}}=?$$" 451 | ] 452 | }, 453 | { 454 | "cell_type": "markdown", 455 | "metadata": {}, 456 | "source": [ 457 | "### First part of the sensitivity, $\\frac{d \\mathbf{A}}{d \\boldsymbol{\\sigma}}\\mathbf{u}=?$\n", 458 | "For $\\frac{d \\mathbf{A}}{d \\boldsymbol{\\sigma}}\\mathbf{u}$, keep in mind that we are treating $\\mathbf{u}$ as fixed and that \n", 459 | "\n", 460 | "$$\n", 461 | "\\mathbf{A}\\mathbf{u} = \n", 462 | " \\begin{bmatrix}\n", 463 | " \\mathbf{Grad} & \\imath \\omega \\mathbf{M}^{f}_{\\mu} \\\\[0.3em]\n", 464 | " \\mathbf{M}^{cc}_{\\boldsymbol{\\sigma}} & \\mathbf{Div} \\\\[0.3em]\n", 465 | " \\end{bmatrix} \n", 466 | " \\begin{bmatrix}\n", 467 | " \\mathbf{e_x} \\\\[0.3em]\n", 468 | " \\mathbf{h_y} \\\\[0.3em]\n", 469 | " \\end{bmatrix}\n", 470 | "$$\n", 471 | "\n", 472 | "Here, we see that the only dependence on $\\boldsymbol{\\sigma}$ is in the matrix $\\mathbf{M}^{cc}_{\\hat{\\boldsymbol{\\sigma}}} = \\mathbf{diag}(\\boldsymbol{\\sigma})$. So lets focus our attention on that block. We are taking the derivative of a Matrix-vector product (which is just a vector) with respect to the vector $\\boldsymbol{\\sigma}$, so the result should be a matrix. We write out the problem: \n", 473 | "\n", 474 | "$$\n", 475 | "\\frac{\\partial}{\\partial \\boldsymbol{\\sigma}} \\mathbf{M}^{cc}_{\\hat{\\boldsymbol{\\sigma}}} \\mathbf{e_x}^{fix} = \\frac{\\partial}{\\partial \\boldsymbol{\\sigma}} \\mathbf{diag}(\\boldsymbol{\\sigma}) \\mathbf{e_x}^{fix}\n", 476 | "$$\n", 477 | "\n", 478 | "and since $\\text{diag}(\\mathbf{x})\\mathbf{y} = \\mathbf{diag}(\\mathbf{y})\\mathbf{x}$, we can interchange the roles of $\\boldsymbol{\\sigma}$ and $\\mathbf{e_x}^{fix}$\n", 479 | "\n", 480 | "$$\n", 481 | "\\frac{\\partial}{\\partial \\boldsymbol{\\sigma}} \\mathbf{M}^{cc}_{\\hat{\\boldsymbol{\\sigma}}} \\mathbf{e_x}^{fix} = \\frac{\\partial}{\\partial \\boldsymbol{\\sigma}} \\mathbf{diag}(\\mathbf{e_x}^{fix}) \\boldsymbol{\\sigma}\n", 482 | "$$\n", 483 | "\n", 484 | "So the derivative is simply: \n", 485 | "$$\n", 486 | "\\frac{\\partial}{\\partial \\boldsymbol{\\sigma}} \\mathbf{M}^{cc}_{\\hat{\\boldsymbol{\\sigma}}} \\mathbf{e_x}^{fix} =\\text{diag}(\\mathbf{e_x}^{fix})\n", 487 | "$$\n", 488 | "\n", 489 | "Thus the full derivative is \n", 490 | "$$ \n", 491 | "\\frac{d \\mathbf{A}}{d \\boldsymbol{\\sigma}}\\mathbf{u} =\n", 492 | "\\begin{bmatrix}\n", 493 | " \\mathbf{0} \\\\[0.3em]\n", 494 | " \\mathbf{diag}(\\mathbf{e}_x) \\\\[0.3em]\n", 495 | "\\end{bmatrix}\n", 496 | "$$" 497 | ] 498 | }, 499 | { 500 | "cell_type": "markdown", 501 | "metadata": {}, 502 | "source": [ 503 | "### Second part of the Sensitivity: $\\frac{\\partial P(\\mathbf{u})}{\\partial \\mathbf{u}}=?$\n", 504 | "For the other one we consider when the data is defined as real and imaginary parts of $Z_{xy} = -\\mathbf{P}_0\\frac{1}{\\mathbf{u}}$:\n", 505 | "\n", 506 | "Taking derivative of $Z_{xy}$ w.r.t. $\\mathbf{u}$ yields\n", 507 | "$$\n", 508 | "\\frac{\\partial Z_{\n", 509 | "xy}}{\\partial \\mathbf{u}}=\n", 510 | "\\mathbf{P}_0\\frac{1}{\\mathbf{u}^2}\n", 511 | "$$\n", 512 | "\n", 513 | "$$ \n", 514 | "\\frac{\\partial P(\\mathbf{u})}{\\partial \\mathbf{u}}=\n", 515 | "\\begin{bmatrix}\n", 516 | " \\frac{\\partial Re[Z_{xy}]}{\\partial \\mathbf{u}} \\\\[0.3em]\n", 517 | " \\frac{\\partial Im[Z_{xy}]}{\\partial \\mathbf{u}} \\\\[0.3em]\n", 518 | "\\end{bmatrix} \n", 519 | "=\n", 520 | "\\begin{bmatrix}\n", 521 | " Re[\\mathbf{P}_0\\frac{1}{\\mathbf{u}^2}] \\\\[0.3em]\n", 522 | " Im[\\mathbf{P}_0\\frac{1}{\\mathbf{u}^2}] \\\\[0.3em]\n", 523 | "\\end{bmatrix} \n", 524 | "$$\n" 525 | ] 526 | }, 527 | { 528 | "cell_type": "markdown", 529 | "metadata": {}, 530 | "source": [ 531 | "Now we can form sensitivity matrix $\\mathbf{J}_{\\sigma}$ by combining above equations:\n", 532 | "\n", 533 | "$$ \\mathbf{J}_{{\\boldsymbol{\\sigma}}} = \n", 534 | "-\\frac{\\partial P(\\mathbf{u})}{\\partial {\\mathbf{u}}} \\Big(\\mathbf{A}^{-1}\\frac{d \\mathbf{A}}{d {\\boldsymbol{\\sigma}}}\\mathbf{u}\\Big) $$" 535 | ] 536 | }, 537 | { 538 | "cell_type": "markdown", 539 | "metadata": {}, 540 | "source": [ 541 | "Deriving sensitivity for apparent resistivity and phase is possible, but this requires additional details hence, we focus on our attention to real and imaginary parts of impedance. " 542 | ] 543 | }, 544 | { 545 | "cell_type": "markdown", 546 | "metadata": {}, 547 | "source": [ 548 | "## Compute Sensitivity function\n", 549 | "\n", 550 | "We compute discretized sensitivity matrix, $\\mathbf{J}_{\\sigma}$ shown above. " 551 | ] 552 | }, 553 | { 554 | "cell_type": "code", 555 | "execution_count": 10, 556 | "metadata": {}, 557 | "outputs": [], 558 | "source": [ 559 | "# angular frequency\n", 560 | "omega = f*2*np.pi\n", 561 | "\n", 562 | "# physical properties\n", 563 | "sigma = np.ones(mesh.nC)*sigma_half # conductivity values for all cells\n", 564 | "mu = np.ones(mesh.nC)*mu_0 # magnetic permeability values for all cells\n", 565 | "sigmahat = sigma.copy()\n", 566 | "\n", 567 | "# Grad \n", 568 | "mesh.setCellGradBC([['dirichlet', 'dirichlet']]) # Setup boundary conditions\n", 569 | "Grad = mesh.cellGrad # Gradient matrix\n", 570 | "\n", 571 | "# MfMu\n", 572 | "Mmu = Utils.sdiag(mesh.aveCC2F * mu)\n", 573 | "\n", 574 | "# Mccsigma\n", 575 | "Msighat = Utils.sdiag(sigmahat) \n", 576 | "\n", 577 | "# Div\n", 578 | "Div = mesh.faceDiv # Divergence matrix\n", 579 | "\n", 580 | "# Right Hand Side\n", 581 | "B = mesh.cellGradBC # a matrix for boundary conditions\n", 582 | "Exbc = np.r_[0., 1.] # boundary values for Ex\n", 583 | "\n", 584 | "# A-matrix\n", 585 | "A = sp.vstack([\n", 586 | " sp.hstack([Grad, 1j*omega*Mmu]), # Top row of A matrix\n", 587 | " sp.hstack((Msighat, Div)) # Bottom row of A matrix\n", 588 | "])\n", 589 | "\n", 590 | "# Right-hand side\n", 591 | "rhs = np.r_[\n", 592 | " -B*Exbc, \n", 593 | " np.zeros(mesh.nC)\n", 594 | "] " 595 | ] 596 | }, 597 | { 598 | "cell_type": "code", 599 | "execution_count": 11, 600 | "metadata": {}, 601 | "outputs": [], 602 | "source": [ 603 | "Ainv = Solver(A) # Factorize A matrix\n", 604 | "u = Ainv*rhs # Solve A^-1 rhs = u\n", 605 | "\n", 606 | "Ex = u[:mesh.nC] # Extract Ex from uution vector u\n", 607 | "Hy = u[mesh.nC:mesh.nC+mesh.nN] # Extract Hy from solution vector u \n", 608 | "\n", 609 | "P0 = sp.csr_matrix(\n", 610 | " (np.r_[1.], (np.r_[0], np.r_[len(u)-1])), shape=(1, len(u))\n", 611 | " )\n", 612 | "P0 = P0.tocsr()\n", 613 | "\n", 614 | "dAdsig_u = sp.vstack((Utils.spzeros(int(mesh.nC+1), mesh.nC), Utils.sdiag(Ex)))\n", 615 | "dudsig = - (Ainv * (dAdsig_u.toarray()))\n", 616 | "dZdsig = P0 * (Utils.sdiag(1./(u**2)) * dudsig)\n", 617 | "\n", 618 | "J = np.vstack((dZdsig.real, dZdsig.imag))" 619 | ] 620 | }, 621 | { 622 | "cell_type": "markdown", 623 | "metadata": {}, 624 | "source": [ 625 | "#### Plot the sensitivity " 626 | ] 627 | }, 628 | { 629 | "cell_type": "code", 630 | "execution_count": 12, 631 | "metadata": {}, 632 | "outputs": [ 633 | { 634 | "data": { 635 | "text/plain": [ 636 | "Text(0,0.5,'Sensitivity')" 637 | ] 638 | }, 639 | "execution_count": 12, 640 | "metadata": {}, 641 | "output_type": "execute_result" 642 | }, 643 | { 644 | "data": { 645 | "image/png": "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\n", 646 | "text/plain": [ 647 | "" 648 | ] 649 | }, 650 | "metadata": {}, 651 | "output_type": "display_data" 652 | } 653 | ], 654 | "source": [ 655 | "fig, ax = plt.subplots(1, 1)\n", 656 | "\n", 657 | "core_inds = mesh.vectorCCx > -core_extent\n", 658 | "\n", 659 | "ax.loglog(-mesh.vectorCCx[core_inds], abs(J[0, core_inds]), label=\"real\")\n", 660 | "ax.loglog(-mesh.vectorCCx[core_inds], abs(J[1, core_inds]), label=\"imag\")\n", 661 | "\n", 662 | "ax.grid(True)\n", 663 | "ax.legend()\n", 664 | "ax.set_xlabel(\"Logarithmic Depth (m)\")\n", 665 | "ax.set_ylabel(\"Sensitivity\") " 666 | ] 667 | }, 668 | { 669 | "cell_type": "markdown", 670 | "metadata": {}, 671 | "source": [ 672 | "## Compute sensitivity-vector products:\n", 673 | "\n", 674 | "For the 1D MT problem, the sensitivity matrix ($N\\times M$) is small, hence generating sensitivity is not be a big deal. However, for any 3D EM problem, generating the sensitivity matrix will require a huge amount of memory. To minimize that we only compute sensitivity-vector product. In forward case we compute:\n", 675 | "\n", 676 | "$$ \\mathbf{Jv} = \\mathbf{J}_{\\boldsymbol{\\sigma}} \\mathbf{v} $$\n", 677 | "\n", 678 | "Similarly, in adjoint case, we compute\n", 679 | "\n", 680 | "$$ \\mathbf{Jtv} = \\mathbf{J}_{\\boldsymbol{\\sigma}}^{T} \\mathbf{v} $$\n", 681 | "\n", 682 | "Computing $\\mathbf{Jv}$ and $\\mathbf{Jtv}$ are straight forward from above derivation. \n", 683 | "\n", 684 | "$$ \\mathbf{J}_{{\\boldsymbol{\\sigma}}}^T \\mathbf{v} \n", 685 | "= - \\left(\\frac{d \\mathbf{A}}{d {\\boldsymbol{\\sigma}}}\\mathbf{u} \\right)^T\n", 686 | "\\left(\\mathbf{A}^{T}\\right)^{-1} \\frac{\\partial P(\\mathbf{u})}{\\partial {\\mathbf{u}}}^T \\mathbf{v} $$\n", 687 | "\n", 688 | "One function computes forward sensitivity-vector product as `Jvec` and the other function computes adjoint sensitivity-vector product are named as `Jtvec`. " 689 | ] 690 | }, 691 | { 692 | "cell_type": "markdown", 693 | "metadata": {}, 694 | "source": [ 695 | "### Jvec\n", 696 | "\n", 697 | "`Jvec` function takes conductivity ($\\sigma$) and vector ($\\mathbf{v}$), and computes sensitivity-vector product at a given frequency. " 698 | ] 699 | }, 700 | { 701 | "cell_type": "code", 702 | "execution_count": 13, 703 | "metadata": {}, 704 | "outputs": [], 705 | "source": [ 706 | "def Jvec(sigma, v, f=100.):\n", 707 | " mu = np.ones(mesh.nC)*mu_0 # magnetic permeability values for all cells\n", 708 | " epsilon = np.ones(mesh.nC)*epsilon_0 # dielectric constant values for all cells\n", 709 | " omega = 2*np.pi*f # Angular frequency (rad/s)\n", 710 | " sigmahat = sigma # Assume sigmahat = sigma\n", 711 | " \n", 712 | " Div = mesh.faceDiv # Divergence matrix\n", 713 | " mesh.setCellGradBC([['dirichlet', 'dirichlet']]) # Setup boundary conditions\n", 714 | " Grad = mesh.cellGrad # Gradient matrix\n", 715 | " B = mesh.cellGradBC # a matrix for boundary conditions\n", 716 | " Exbc = np.r_[0., 1.] # boundary values for Ex\n", 717 | " Msighat = Utils.sdiag(sigmahat) \n", 718 | " Mmu = Utils.sdiag(mesh.aveCC2F * mu) \n", 719 | "\n", 720 | " # A-matrix\n", 721 | " A = sp.vstack([\n", 722 | " sp.hstack([Grad, 1j*omega*Mmu]), # Top row of A matrix\n", 723 | " sp.hstack((Msighat, Div)) # Bottom row of A matrix\n", 724 | " ])\n", 725 | "\n", 726 | " # Right-hand side\n", 727 | " rhs = np.r_[\n", 728 | " -B*Exbc, \n", 729 | " np.zeros(mesh.nC)\n", 730 | " ] \n", 731 | "\n", 732 | " Ainv = Solver(A) # Factorize A matrix\n", 733 | " u = Ainv*rhs # Solve A^-1 rhs = u\n", 734 | " Ex = u[:mesh.nC] # Extract Ex from uution vector u\n", 735 | " Hy = u[mesh.nC:mesh.nC+mesh.nN] # Extract Hy from solution vector u \n", 736 | " \n", 737 | " P0 = sp.csr_matrix(\n", 738 | " (np.r_[1.], (np.r_[0], np.r_[len(u)-1])), shape=(1, len(u))\n", 739 | " )\n", 740 | " P0 = P0.tocsr()\n", 741 | " Zxy = - 1./(P0*u)\n", 742 | "\n", 743 | " dAdsig_u_v = np.r_[np.zeros_like(Hy), Utils.sdiag(Ex)*v]\n", 744 | " dudsig_v = - (Ainv * (dAdsig_u_v))\n", 745 | " dZdsig_v = P0 * (Utils.sdiag(1./(u**2)) * dudsig_v)\n", 746 | " dZrdsig_v = dZdsig_v.real\n", 747 | " dZidsig_v = dZdsig_v.imag\n", 748 | " return np.r_[dZrdsig_v, dZidsig_v]" 749 | ] 750 | }, 751 | { 752 | "cell_type": "markdown", 753 | "metadata": {}, 754 | "source": [ 755 | "### Order test: Jvec\n", 756 | "\n", 757 | "We have written the `Jvec` function, but how do we make sure this function is working properly? \n", 758 | "\n", 759 | "Let's consdier a predicted data $ d = \\mathcal{F}[\\sigma + \\triangle \\sigma] $.\n", 760 | "Applying Taylor's expansion yields\n", 761 | "\n", 762 | "$$ \n", 763 | "\\mathcal{F}[\\sigma + \\triangle \\sigma] = \\mathcal{F}[\\sigma]\n", 764 | "+\\frac{d \\mathcal{F}}{d \\sigma} \\triangle \\sigma \n", 765 | "+ \\mathcal{O}(\\triangle \\sigma )^2\n", 766 | "$$ \n", 767 | "\n", 768 | "By rearranging aboe equation, we can consider two misfit functions:\n", 769 | "\n", 770 | "$$\n", 771 | "f^1 = \\|\n", 772 | "\\mathcal{F}[\\sigma + \\triangle \\sigma] -\\mathcal{F}[\\sigma] \\|\n", 773 | "$$\n", 774 | "\n", 775 | "$$\n", 776 | "f^2 = \\|\n", 777 | "\\mathcal{F}[\\sigma + \\triangle \\sigma] -\\mathcal{F}[\\sigma]\n", 778 | "-\\frac{d \\mathcal{F}}{d \\sigma} \\triangle \\sigma \\|\n", 779 | "$$\n", 780 | "\n", 781 | "The first misfit function is supposed to have 1st order accuracy, but the other should be 2nd order accuracy. By using `SimPEG`'s `Tests` class we compute this two misfits, and check the accuracy. " 782 | ] 783 | }, 784 | { 785 | "cell_type": "code", 786 | "execution_count": 14, 787 | "metadata": {}, 788 | "outputs": [ 789 | { 790 | "name": "stdout", 791 | "output_type": "stream", 792 | "text": [ 793 | "==================== checkDerivative ====================\n", 794 | "iter h |ft-f0| |ft-f0-h*J0*dx| Order\n", 795 | "---------------------------------------------------------\n", 796 | " 0 1.00e-01 3.454e-02 7.604e-03 nan\n", 797 | " 1 1.00e-02 4.121e-03 9.254e-05 1.915\n", 798 | " 2 1.00e-03 4.204e-04 9.461e-07 1.990\n", 799 | "========================= PASS! =========================\n", 800 | "Testing is important.\n", 801 | "\n" 802 | ] 803 | }, 804 | { 805 | "data": { 806 | "text/plain": [ 807 | "True" 808 | ] 809 | }, 810 | "execution_count": 14, 811 | "metadata": {}, 812 | "output_type": "execute_result" 813 | } 814 | ], 815 | "source": [ 816 | "from SimPEG import Tests\n", 817 | "def derChk(m):\n", 818 | " return [dpred(m), lambda mx: Jvec(m, mx)]\n", 819 | "Tests.checkDerivative(derChk, sigma, plotIt=False, num=3, eps=1e-20, dx=sigma*3)" 820 | ] 821 | }, 822 | { 823 | "cell_type": "markdown", 824 | "metadata": {}, 825 | "source": [ 826 | "### Jtvec\n", 827 | "\n", 828 | "The below function takes conductivity ($\\sigma$) and vector ($\\mathbf{v}$), and computes adjoint sensitivity-vector product (`Jtvec`) at a given frequency. " 829 | ] 830 | }, 831 | { 832 | "cell_type": "code", 833 | "execution_count": 15, 834 | "metadata": {}, 835 | "outputs": [], 836 | "source": [ 837 | "def misfit(sigma, dobs=None):\n", 838 | " r = dpred(sigma) - dobs\n", 839 | " return 0.5 * np.linalg.norm(r)**2\n", 840 | "\n", 841 | "def Jtvec(sigma, v, dtype=\"ri\"):\n", 842 | " f = 100.\n", 843 | " mu = np.ones(mesh.nC)*mu_0 # magnetic permeability values for all cells\n", 844 | " epsilon = np.ones(mesh.nC)*epsilon_0 # dielectric constant values for all cells\n", 845 | " omega = 2*np.pi*f # Angular frequency (rad/s)\n", 846 | " sigmahat = sigma # Assume sigmahat = sigma\n", 847 | "\n", 848 | " Div = mesh.faceDiv # Divergence matrix\n", 849 | " mesh.setCellGradBC([['dirichlet', 'dirichlet']]) # Setup boundary conditions\n", 850 | " Grad = mesh.cellGrad # Gradient matrix\n", 851 | " B = mesh.cellGradBC # a matrix for boundary conditions\n", 852 | " Exbc = np.r_[0., 1.] # boundary values for Ex\n", 853 | " Msighat = Utils.sdiag(sigmahat) \n", 854 | " Mmu = Utils.sdiag(mesh.aveCC2F * mu) \n", 855 | "\n", 856 | " tempUp = sp.hstack((Grad, 1j*omega*Mmu)) # Top row of A matrix\n", 857 | " tempDw = sp.hstack((Msighat, Div)) # Bottom row of A matrix\n", 858 | " A = sp.vstack((tempUp, tempDw)) # Full A matrix\n", 859 | " rhs = np.r_[-B*Exbc, np.zeros(mesh.nC)] # Right-hand side \n", 860 | "\n", 861 | " Ainv = Solver(A) # Factorize A matrix\n", 862 | " u = Ainv*rhs # Solve A^-1 rhs = u\n", 863 | " Ex = u[:mesh.nC] # Extract Ex from uution vector u\n", 864 | " Hy = u[mesh.nC:mesh.nC+mesh.nN] # Extract Hy from solution vector u \n", 865 | " P0 = sp.coo_matrix(\n", 866 | " (np.r_[1.], (np.r_[0], np.r_[len(u)-1])), shape=(1, len(u))\n", 867 | " )\n", 868 | " P0 = P0.tocsr()\n", 869 | " Zxy = - 1./(P0*u) \n", 870 | " ATinv = Solver(A.T) # Factorize A matrix \n", 871 | " \n", 872 | " PTvr = (P0.T*np.r_[v[0]]).astype(complex)\n", 873 | " PTvi = P0.T*np.r_[v[1]]*-1j\n", 874 | " dZrduT_v = Utils.sdiag((1./(u**2)))*PTvr\n", 875 | " dZiduT_v = Utils.sdiag((1./(u**2)))*PTvi\n", 876 | "\n", 877 | " dAdsiguT = sp.hstack((Utils.spzeros(mesh.nC, mesh.nN), Utils.sdiag(Ex)))\n", 878 | "\n", 879 | " dZrdsigT_v = - (dAdsiguT*(ATinv*dZrduT_v)).real\n", 880 | " dZidsigT_v = - (dAdsiguT*(ATinv*dZiduT_v)).real \n", 881 | " return dZrdsigT_v + dZidsigT_v" 882 | ] 883 | }, 884 | { 885 | "cell_type": "markdown", 886 | "metadata": {}, 887 | "source": [ 888 | "### Order test: Jtvec\n", 889 | "\n", 890 | "Similarly, `Jtvec` function has to be tested. For this, in this turn we consider a data msifit function:\n", 891 | "\n", 892 | "$$\n", 893 | "\\phi_d = \\frac{1}{2}\\|\n", 894 | "\\mathcal{F}[\\sigma] - \\mathbf{d}^{obs}\n", 895 | "\\|^2_2\n", 896 | "=\\frac{1}{2} \\mathbf{r}^T\\mathbf{r},\n", 897 | "$$\n", 898 | "\n", 899 | "where residual is $\\mathbf{r} = \\mathcal{F}[\\sigma] - \\mathbf{d}^{obs}$. \n", 900 | "\n", 901 | "By taking derivative w.r.t $\\sigma$, we obtain\n", 902 | "\n", 903 | "$$\n", 904 | "\\frac{d \\phi_d}{d \\sigma} = \\mathbf{J}_{\\sigma}^T \\mathbf{r}\n", 905 | "$$\n", 906 | "\n", 907 | "- Note that this is basically a gradient direction, and for first order optimization method such as steepest descent, we only needs this function that is only `Jvec` is required. \n", 908 | "\n", 909 | "Then applying taylor expansion to $\\phi_d$ yields\n", 910 | "\n", 911 | "$$ \n", 912 | "\\phi_d[\\sigma + \\triangle \\sigma] = \\phi_d[\\sigma]\n", 913 | "+\\frac{d \\phi_d}{d \\sigma} \\triangle \\sigma \n", 914 | "+ \\mathcal{O}(\\triangle \\sigma )^2\n", 915 | "$$ \n", 916 | "\n", 917 | "And similarly, we can consider two misfit functions:\n", 918 | "\n", 919 | "$$\n", 920 | "\\phi_d^1 = \\|\n", 921 | "\\phi_d[\\sigma + \\triangle \\sigma] -\\phi_d[\\sigma] \\|\n", 922 | "$$\n", 923 | "\n", 924 | "$$\n", 925 | "\\phi_d^2 = \\|\n", 926 | "\\phi_d[\\sigma + \\triangle \\sigma] -\\phi_d[\\sigma]\n", 927 | "-\\frac{d \\phi_d}{d \\sigma} \\triangle \\sigma \\|\n", 928 | "$$\n", 929 | "\n", 930 | "The first data misfit function is supposed to have 1st order accuracy, but the other should be 2nd order accuracy. By using `SimPEG`'s `Tests` class we compute this two misfits, and check the accuracy. " 931 | ] 932 | }, 933 | { 934 | "cell_type": "code", 935 | "execution_count": 16, 936 | "metadata": {}, 937 | "outputs": [ 938 | { 939 | "name": "stdout", 940 | "output_type": "stream", 941 | "text": [ 942 | "==================== checkDerivative ====================\n", 943 | "iter h |ft-f0| |ft-f0-h*J0*dx| Order\n", 944 | "---------------------------------------------------------\n", 945 | " 0 1.00e-01 4.341e-02 6.094e-02 nan\n", 946 | " 1 1.00e-02 1.733e-03 1.981e-05 3.488\n", 947 | " 2 1.00e-03 1.754e-04 8.632e-08 2.361\n", 948 | " 3 1.00e-04 1.753e-05 1.094e-09 1.897\n", 949 | " 4 1.00e-05 1.753e-06 1.116e-11 1.991\n", 950 | "========================= PASS! =========================\n", 951 | "Testing is important.\n", 952 | "\n" 953 | ] 954 | }, 955 | { 956 | "data": { 957 | "text/plain": [ 958 | "True" 959 | ] 960 | }, 961 | "execution_count": 16, 962 | "metadata": {}, 963 | "output_type": "execute_result" 964 | } 965 | ], 966 | "source": [ 967 | "sigma0 = sigma*3\n", 968 | "dobs_ri = dpred(sigma)\n", 969 | "r = dpred(sigma0) - dobs_ri \n", 970 | "\n", 971 | "Tests.checkDerivative(\n", 972 | " lambda m: [misfit(m, dobs=dobs_ri), Jtvec(m, r)],\n", 973 | " sigma0,\n", 974 | " plotIt=False,\n", 975 | " num=5\n", 976 | ")" 977 | ] 978 | }, 979 | { 980 | "cell_type": "markdown", 981 | "metadata": {}, 982 | "source": [ 983 | "## Adjoint test\n", 984 | "\n", 985 | "Both `Jvec` and `Jtvec` functions have passed the order test. These tests are necessary, but not sufficient. \n", 986 | "To test that both `Jvec` and `Jtvec` are consistent, we perform adjoint test. Consdier two random vectors: $\\mathbf{w}$ and $\\mathbf{v}$, then we can evalaute\n", 987 | "\n", 988 | "$$\n", 989 | "\\mathbf{w}^T \\mathbf{J}_{\\sigma} \\mathbf{v}, \n", 990 | "$$\n", 991 | "\n", 992 | "which will be a scalar value. Adjoint of above proucts is \n", 993 | "\n", 994 | "$$\n", 995 | "\\mathbf{v}^T \\mathbf{J}_{\\sigma}^T \\mathbf{w}, \n", 996 | "$$\n", 997 | "\n", 998 | "They should have same value: $\\mathbf{w}^T \\mathbf{J}_{\\sigma} \\mathbf{v}=\\mathbf{v}^T \\mathbf{J}_{\\sigma}^T \\mathbf{w}$. We evaluate $\\mathbf{w}^T \\mathbf{J}_{\\sigma} \\mathbf{v}$ and $\\mathbf{v}^T \\mathbf{J}_{\\sigma}^T \\mathbf{w}$ using `Jvec` and `Jtvec`, respectively, and check if they are outputing same values. " 999 | ] 1000 | }, 1001 | { 1002 | "cell_type": "code", 1003 | "execution_count": 17, 1004 | "metadata": {}, 1005 | "outputs": [ 1006 | { 1007 | "name": "stdout", 1008 | "output_type": "stream", 1009 | "text": [ 1010 | "Adjoint Test 1.1102230246251565e-16 True\n" 1011 | ] 1012 | } 1013 | ], 1014 | "source": [ 1015 | "v = np.random.rand(mesh.nC)\n", 1016 | "w = np.random.rand(dobs_ri.shape[0])\n", 1017 | "wtJv = w.dot(Jvec(sigma0, v))\n", 1018 | "vtJtw = v.dot(Jtvec(sigma0, w))\n", 1019 | "passed = np.abs(wtJv - vtJtw) < 1e-10\n", 1020 | "print('Adjoint Test', np.abs(wtJv - vtJtw), passed)" 1021 | ] 1022 | }, 1023 | { 1024 | "cell_type": "code", 1025 | "execution_count": null, 1026 | "metadata": {}, 1027 | "outputs": [], 1028 | "source": [] 1029 | } 1030 | ], 1031 | "metadata": { 1032 | "anaconda-cloud": {}, 1033 | "kernelspec": { 1034 | "display_name": "Python 3", 1035 | "language": "python", 1036 | "name": "python3" 1037 | }, 1038 | "language_info": { 1039 | "codemirror_mode": { 1040 | "name": "ipython", 1041 | "version": 3 1042 | }, 1043 | "file_extension": ".py", 1044 | "mimetype": "text/x-python", 1045 | "name": "python", 1046 | "nbconvert_exporter": "python", 1047 | "pygments_lexer": "ipython3", 1048 | "version": "3.6.6" 1049 | } 1050 | }, 1051 | "nbformat": 4, 1052 | "nbformat_minor": 2 1053 | } 1054 | -------------------------------------------------------------------------------- /notebooks/MT_tutorial_Appendix_B_MT1D_tests.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "metadata": {}, 7 | "outputs": [], 8 | "source": [ 9 | "from MT1D import MT1DProblem, MT1DSurvey, MT1DSrc, ZxyRx, Survey, AppResPhaRx\n", 10 | "from SimPEG import Maps, DataMisfit\n", 11 | "from scipy.constants import mu_0\n", 12 | "import numpy as np" 13 | ] 14 | }, 15 | { 16 | "cell_type": "markdown", 17 | "metadata": {}, 18 | "source": [ 19 | "# Put all things together to SimPEG Problem\n", 20 | "\n", 21 | "In the [1_MT1D_NumericalSetup](./1_MT1D_NumericalSetup.ipynb) notebook, we coded up a 1D MT simulation function that computes complex impedances at multiple frequencies for a given conductivity model. To invert MT data in 1D using gradient-based optimization, sensitivity functions were derived, coded up, and tested in [Appendix_A_MT1D_Sensitivity](./Appendix_A_MT1D_Sensitivity.ipynb) notebook. Basically those are three funcionalities:\n", 22 | "\n", 23 | "- `dpred(m)`: takes model and predict MT data for a given model, `m`\n", 24 | "\n", 25 | "- `Jvec(m,v)`: takes model and a vector `v`, then computes sensitivity-vector product. \n", 26 | "\n", 27 | "- `Jtvec(m,v)`: takes model and a vector `v`, then computes adjoint sensitivity-vector product. \n", 28 | "\n", 29 | "Now we put all these things to `SimPEG`'s framework. " 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "metadata": {}, 35 | "source": [ 36 | "## `SimPEG` framework\n", 37 | "\n", 38 | "Our setup of the simluation follows the [SimPEG framework](http://simpeg.xyz). \n", 39 | "\n", 40 | "\"plane_wave\"\n", 41 | "\n", 42 | "\n", 43 | "For more details, see the [SimPEG docs](http://docs.simpeg.xyz)\n", 44 | "\n", 45 | "- `Mesh`: mesh geometry and differential operators\n", 46 | "- `Problem`: physics engine. contains the machinery to construct and solve the PDE\n", 47 | "- `Survey`: sources and receivers\n", 48 | "- `Src`: sources\n", 49 | "- `Rx`: receivers\n", 50 | "\n", 51 | "`Problem` class in `SimPEG` is a physics. It discretizes the earth and computes fields in a discretized domain, and here we use `Mesh` class. For an MT problem, Maxwell's equations are used, and electromagnetic fields are computed. To do this, we need to know details about MT survey (e.g. frequencies and location of source and receivers), and they are defined in `Survey` class. `Survey` class takes `Src` class, and `Src` class takes `Rx` class. Therefore, both information in sources and receivers can be aware in the `Survey`.\n", 52 | "\n", 53 | "### Mapping\n", 54 | "\n", 55 | "For simulation, we do need to input discretized physical property. For instance in 1D MT problem values of conductivity at each cell is required. However, when consdiering inversion, inversion model can be different from physical property (e.g. conductivity). For instance, often in electromagnetic (EM) inversions logarithmic conductivity was used as an inversion model: $\\mathbf{m} = log(\\boldsymbol{\\sigma})$. While inversion process, still simulation is required to predict data hence updated model, $\\mathbf{m}$ has to be converted to $\\boldsymbol{\\sigma}$, which is a discretized physical property. Here we define a mapping:\n", 56 | "\n", 57 | "$$ \\sigma = \\mathcal{M}(\\mathbf{m}) $$\n", 58 | "\n", 59 | "mapping is a function which takes an inversion model, and outputs physical property used in simulation. For more details see: http://docs.simpeg.xyz/content/api_core/api_Maps.html. " 60 | ] 61 | }, 62 | { 63 | "cell_type": "markdown", 64 | "metadata": {}, 65 | "source": [ 66 | "## Codes:\n", 67 | "\n", 68 | "Taking snippets of codes written in [1_MT1D_NumericalSetup](./1_MT1D_NumericalSetup.ipynb) and [Appendix_A_MT1D_Sensitivity](./Appendix_A_MT1D_Sensitivity.ipynb), we generated the `Problem`, `Survey`, `Src`, and `Rx` classes for 1D MT problem. And here are lists of classes:\n", 69 | "\n", 70 | "- `MT1DProblem`: This includes functions: `dpred(m)`, `Jvec(m,v)`, `Jtvec(m,v)`\n", 71 | "- `MT1DSurvey`: Need to input `MT1DSrc`\n", 72 | "- `MT1DSrc`: Need to input `ZxyRx`\n", 73 | "- `ZxyRx`: Receiver class / Real and Imaginary part of $Z_{xy}$" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 2, 79 | "metadata": {}, 80 | "outputs": [ 81 | { 82 | "name": "stdout", 83 | "output_type": "stream", 84 | "text": [ 85 | ">> Smallest cell size = 50 m\n", 86 | ">> Padding distance = 316227 m\n", 87 | ">> # of padding cells 17\n", 88 | ">> # of core cells cells 16\n" 89 | ] 90 | } 91 | ], 92 | "source": [ 93 | "rxloc = np.r_[0.]\n", 94 | "srcloc = np.r_[0.]\n", 95 | "frequency = np.logspace(-3, 2, 25)\n", 96 | "\n", 97 | "# Rx\n", 98 | "rx = ZxyRx(rxloc, component=\"both\", frequency=frequency)\n", 99 | "rxList = [rx]\n", 100 | "\n", 101 | "# Src\n", 102 | "src = MT1DSrc(rxList, loc=srcloc)\n", 103 | "\n", 104 | "# Survey\n", 105 | "survey = MT1DSurvey([src])\n", 106 | "mesh = survey.setMesh(\n", 107 | " sigma=0.01, max_depth_core=5000., \n", 108 | " ncell_per_skind=10, n_skind=2, \n", 109 | " core_meshType=\"log\", max_hz_core=1000.\n", 110 | ")\n", 111 | "\n", 112 | "# Physical property: Conductivity\n", 113 | "sigma = np.ones(mesh.nC) * 0.01\n", 114 | "\n", 115 | "# Problem\n", 116 | "prob = MT1DProblem(mesh, sigmaMap=Maps.ExpMap(mesh), verbose=False)\n", 117 | "prob.pair(survey)" 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": {}, 123 | "source": [ 124 | "## Order and Adjoint tests \n", 125 | "\n", 126 | "We perform both order and adjoint tests shown in [Appendix_A_MT1D_Sensitivity](./Appendix_A_MT1D_Sensitivity.ipynb) using 1D MT problem in `SimPEG`'s framework. " 127 | ] 128 | }, 129 | { 130 | "cell_type": "markdown", 131 | "metadata": {}, 132 | "source": [ 133 | "### Order test: `Jvec`" 134 | ] 135 | }, 136 | { 137 | "cell_type": "code", 138 | "execution_count": 3, 139 | "metadata": {}, 140 | "outputs": [ 141 | { 142 | "name": "stdout", 143 | "output_type": "stream", 144 | "text": [ 145 | "==================== checkDerivative ====================\n", 146 | "iter h |ft-f0| |ft-f0-h*J0*dx| Order\n", 147 | "---------------------------------------------------------\n", 148 | " 0 1.00e-01 2.669e-01 5.676e-02 nan\n", 149 | " 1 1.00e-02 2.151e-02 4.914e-04 2.063\n", 150 | " 2 1.00e-03 2.106e-03 4.846e-06 2.006\n", 151 | "========================= PASS! =========================\n", 152 | "You are awesome.\n", 153 | "\n" 154 | ] 155 | }, 156 | { 157 | "data": { 158 | "text/plain": [ 159 | "True" 160 | ] 161 | }, 162 | "execution_count": 3, 163 | "metadata": {}, 164 | "output_type": "execute_result" 165 | } 166 | ], 167 | "source": [ 168 | "from SimPEG import Tests\n", 169 | "def derChk(m):\n", 170 | " return [survey.dpred(m), lambda mx: prob.Jvec(m, mx)]\n", 171 | "Tests.checkDerivative(derChk, np.log(sigma), plotIt=False, num=3, eps=1e-20, dx=np.log(sigma)*2)" 172 | ] 173 | }, 174 | { 175 | "cell_type": "markdown", 176 | "metadata": {}, 177 | "source": [ 178 | "### Order test: `Jtvec`" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": 4, 184 | "metadata": {}, 185 | "outputs": [ 186 | { 187 | "name": "stdout", 188 | "output_type": "stream", 189 | "text": [ 190 | "SimPEG.DataMisfit.l2_DataMisfit assigning default eps of 1e-5 * ||dobs||\n" 191 | ] 192 | } 193 | ], 194 | "source": [ 195 | "# Evaluate predicted data\n", 196 | "pred = survey.dpred(np.log(sigma))\n", 197 | "survey.dobs = pred\n", 198 | "dmis = DataMisfit.l2_DataMisfit(survey)\n", 199 | "m0 = np.log(sigma)*2." 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 5, 205 | "metadata": {}, 206 | "outputs": [ 207 | { 208 | "name": "stdout", 209 | "output_type": "stream", 210 | "text": [ 211 | "==================== checkDerivative ====================\n", 212 | "iter h |ft-f0| |ft-f0-h*J0*dx| Order\n", 213 | "---------------------------------------------------------\n", 214 | " 0 1.00e-01 1.074e+06 4.010e+05 nan\n", 215 | " 1 1.00e-02 7.038e+04 3.059e+03 2.118\n", 216 | " 2 1.00e-03 6.762e+03 2.982e+01 2.011\n", 217 | " 3 1.00e-04 6.735e+02 2.975e-01 2.001\n", 218 | "========================= PASS! =========================\n", 219 | "You are awesome.\n", 220 | "\n" 221 | ] 222 | }, 223 | { 224 | "data": { 225 | "text/plain": [ 226 | "True" 227 | ] 228 | }, 229 | "execution_count": 5, 230 | "metadata": {}, 231 | "output_type": "execute_result" 232 | } 233 | ], 234 | "source": [ 235 | "Tests.checkDerivative(\n", 236 | " lambda m: [dmis(m), dmis.deriv(m)],\n", 237 | " m0,\n", 238 | " plotIt=False,\n", 239 | " num=4,\n", 240 | " dx = m0*1.\n", 241 | ")" 242 | ] 243 | }, 244 | { 245 | "cell_type": "markdown", 246 | "metadata": {}, 247 | "source": [ 248 | "### Adjoint test" 249 | ] 250 | }, 251 | { 252 | "cell_type": "code", 253 | "execution_count": 6, 254 | "metadata": {}, 255 | "outputs": [ 256 | { 257 | "name": "stdout", 258 | "output_type": "stream", 259 | "text": [ 260 | "Adjoint Test 8.881784197001252e-16 True\n" 261 | ] 262 | } 263 | ], 264 | "source": [ 265 | "v = np.random.rand(mesh.nC)\n", 266 | "w = np.random.rand(pred.shape[0])\n", 267 | "wtJv = w.dot(prob.Jvec(m0, v))\n", 268 | "vtJtw = v.dot(prob.Jtvec(m0, w))\n", 269 | "passed = np.abs(wtJv - vtJtw) < 1e-10\n", 270 | "print('Adjoint Test', np.abs(wtJv - vtJtw), passed)" 271 | ] 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "metadata": {}, 276 | "source": [ 277 | "## Ready to run an inversion\n", 278 | "\n", 279 | "Once you have created the `Survey` and `Problem` classes so that you can compute predicted data (`dpred`), forward and adjoint sensitivity-vector products (`Jvec` and `Jtvec`), you are all set to run inversion using `SimPEG`'s inverersion framework. Check out the examples in [3_MT1D_5layer_inversion](./3_MT1D_5layer_inversion.ipynb) and [1_MT1D_NumericalSetup](./1_MT1D_NumericalSetup.ipynb).\n" 280 | ] 281 | } 282 | ], 283 | "metadata": { 284 | "anaconda-cloud": {}, 285 | "kernelspec": { 286 | "display_name": "Python 3", 287 | "language": "python", 288 | "name": "python3" 289 | }, 290 | "language_info": { 291 | "codemirror_mode": { 292 | "name": "ipython", 293 | "version": 3 294 | }, 295 | "file_extension": ".py", 296 | "mimetype": "text/x-python", 297 | "name": "python", 298 | "nbconvert_exporter": "python", 299 | "pygments_lexer": "ipython3", 300 | "version": "3.6.6" 301 | } 302 | }, 303 | "nbformat": 4, 304 | "nbformat_minor": 2 305 | } 306 | -------------------------------------------------------------------------------- /notebooks/MTforward.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import scipy.sparse as sp 3 | from scipy.constants import mu_0 4 | from SimPEG import Utils, Solver 5 | 6 | 7 | def simulateMT(mesh, sigma, frequency, rtype="app_res"): 8 | """ 9 | Compute apparent resistivity and phase at each frequency. 10 | Return apparent resistivity and phase for rtype="app_res", 11 | or impedance for rtype="impedance" 12 | """ 13 | 14 | # Angular frequency (rad/s) 15 | def omega(freq): 16 | return 2*np.pi*freq 17 | 18 | # make sure we are working with numpy arrays 19 | if type(frequency) is float: 20 | frequency = np.r_[frequency] # make it a list to loop over later if it is just a scalar 21 | elif type(frequency) is list: 22 | frequency = np.array(frequency) 23 | 24 | # Grad 25 | mesh.setCellGradBC([['dirichlet', 'dirichlet']]) # Setup boundary conditions 26 | Grad = mesh.cellGrad # Gradient matrix 27 | 28 | # MfMu 29 | mu = np.ones(mesh.nC)*mu_0 # magnetic permeability values for all cells 30 | Mmu = Utils.sdiag(mesh.aveCC2F * mu) 31 | 32 | # Mccsigma 33 | sigmahat = sigma # quasi-static assumption 34 | Msighat = Utils.sdiag(sigmahat) 35 | 36 | # Div 37 | Div = mesh.faceDiv # Divergence matrix 38 | 39 | # Right Hand Side 40 | B = mesh.cellGradBC # a matrix for boundary conditions 41 | Exbc = np.r_[0., 1.] # boundary values for Ex 42 | 43 | # Right-hand side 44 | rhs = np.r_[ 45 | -B*Exbc, 46 | np.zeros(mesh.nC) 47 | ] 48 | 49 | # loop over frequencies 50 | Zxy = [] 51 | for freq in frequency: 52 | 53 | # A-matrix 54 | A = sp.vstack([ 55 | sp.hstack([Grad, 1j*omega(freq)*Mmu]), # Top row of A matrix 56 | sp.hstack((Msighat, Div)) # Bottom row of A matrix 57 | ]) 58 | 59 | Ainv = Solver(A) # Factorize A matrix 60 | sol = Ainv*rhs # Solve A^-1 rhs = sol 61 | Ex = sol[:mesh.nC] # Extract Ex from solution vector u 62 | Hy = sol[mesh.nC:mesh.nC+mesh.nN] # Extract Hy from solution vector u 63 | 64 | Zxy.append(- 1./Hy[-1]) # Impedance at the surface 65 | 66 | # turn it into an array 67 | Zxy = np.array(Zxy) 68 | 69 | if rtype.lower() == "impedance": 70 | return Zxy 71 | 72 | elif rtype.lower() == "app_res": 73 | app_res = abs(Zxy)**2 / (mu_0*omega(frequency)) 74 | app_phase = np.rad2deg(np.arctan(Zxy.imag / Zxy.real)) 75 | return app_res, app_phase 76 | 77 | else: 78 | raise Exception("rtype must be 'impedance' or 'app_res', not {}".format(rtype.lower())) 79 | -------------------------------------------------------------------------------- /notebooks/TDEM_vmd_sounding_over_sphere.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# TDEM Magnetic Dipole Sounding over a Sphere\n", 8 | "\n", 9 | "In this notebook, we will simulate an TDEM sounding over a conductive sphere. A cylindrical mesh and the [SimPEG](http://simpeg.xyz) Electromanetics module is used to perform the simulation. \n", 10 | "\n", 11 | "For more on SimPEG and SimPEG.EM see:\n", 12 | "\n", 13 | "- [(Cockett et al., 2015)](http://www.sciencedirect.com/science/article/pii/S009830041530056X): *SimPEG: An open source framework for simulation and gradient based parameter estimation in geophysical applications*\n", 14 | "- [(Heagy et al., 2016)](https://arxiv.org/abs/1610.00804): *A framework for simulation and inversion in electromagnetics*" 15 | ] 16 | }, 17 | { 18 | "cell_type": "markdown", 19 | "metadata": {}, 20 | "source": [ 21 | "\n", 22 | "## Setup\n", 23 | "\n", 24 | "An inductive loop transmitter is centered over an electrically conductive sphere (radius 30m). The transmitter is 20m above the surface, and the center of the sphere is 50m below the surface. A coil receiver is offset by 8m horizontally from the transmitter. \n", 25 | "\n", 26 | "" 27 | ] 28 | }, 29 | { 30 | "cell_type": "markdown", 31 | "metadata": {}, 32 | "source": [ 33 | "## Getting Started: Package Imports\n", 34 | "\n", 35 | "- [NumPy](http://www.numpy.org/), [SciPy](https://www.scipy.org/) and [Matplotlib](http://matplotlib.org/) are core Python packages that can be installed when you install python with a distribution such as [Anaconda](https://www.continuum.io/downloads). \n", 36 | "\n", 37 | "- [SimPEG](http://simpeg.xyz) is a Simulation and Inversion package for geophysics\n", 38 | "\n", 39 | "If you would like to set up and run SimPEG on your machine, see http://simpeg.xyz and http://tutorials.simpeg.xyz" 40 | ] 41 | }, 42 | { 43 | "cell_type": "code", 44 | "execution_count": 2, 45 | "metadata": {}, 46 | "outputs": [], 47 | "source": [ 48 | "# Basic python packages\n", 49 | "import numpy as np \n", 50 | "import matplotlib.pyplot as plt\n", 51 | "from scipy.constants import mu_0\n", 52 | "\n", 53 | "# Modules of SimPEG we will use for forward modelling\n", 54 | "from SimPEG import Mesh, Utils, Maps\n", 55 | "from SimPEG.EM import TDEM\n", 56 | "from SimPEG import SolverLU as Solver\n", 57 | "\n", 58 | "# Set a nice colormap! \n", 59 | "plt.set_cmap(plt.get_cmap('viridis'))\n", 60 | "\n", 61 | "%matplotlib inline" 62 | ] 63 | }, 64 | { 65 | "cell_type": "markdown", 66 | "metadata": {}, 67 | "source": [ 68 | "## Model Parameters\n", 69 | "\n", 70 | "We define a \n", 71 | "- resistive halfspace and \n", 72 | "- conductive sphere \n", 73 | " - radius of 30m \n", 74 | " - center is 50m below the surface" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 3, 80 | "metadata": {}, 81 | "outputs": [], 82 | "source": [ 83 | "# electrical conductivities in S/m\n", 84 | "sig_halfspace = 1e-6\n", 85 | "sig_sphere = 1e-2\n", 86 | "sig_air = 1e-8" 87 | ] 88 | }, 89 | { 90 | "cell_type": "code", 91 | "execution_count": 4, 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "# depth to center, radius in m\n", 96 | "sphere_z = -50.\n", 97 | "sphere_radius = 30. " 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": {}, 103 | "source": [ 104 | "## Survey Parameters\n", 105 | "\n", 106 | "- Transmitter and receiver 20m above the surface \n", 107 | "- Receiver offset from transmitter by 8m horizontally\n", 108 | "- We will sample 30 times from $10^{-7}$s to $10^{-4}$s" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 5, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "boom_height = 20. \n", 118 | "rx_offset = 8. \n", 119 | "\n", 120 | "times = np.logspace(-7, -4, 30)\n", 121 | "\n", 122 | "# source and receiver location in 3D space\n", 123 | "src_loc = np.r_[0., 0., boom_height]\n", 124 | "rx_loc = np.atleast_2d(np.r_[rx_offset, 0., boom_height])" 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 6, 130 | "metadata": {}, 131 | "outputs": [ 132 | { 133 | "name": "stdout", 134 | "output_type": "stream", 135 | "text": [ 136 | "min diffusion distance: 3.61e+00 m\n", 137 | "max diffusion distance: 1.14e+04 m\n" 138 | ] 139 | } 140 | ], 141 | "source": [ 142 | "# print the min and max diffusion distances to make sure mesh is \n", 143 | "# fine enough and extends far enough \n", 144 | "\n", 145 | "def diffusion_distance(sigma, time):\n", 146 | " return 1.28*np.sqrt(time/(sigma * mu_0))\n", 147 | "\n", 148 | "print(\n", 149 | " 'min diffusion distance: {:.2e} m'.format(diffusion_distance(sig_sphere, times.min()))\n", 150 | ")\n", 151 | "print(\n", 152 | " 'max diffusion distance: {:.2e} m'.format(diffusion_distance(sig_halfspace, times.max()))\n", 153 | ")" 154 | ] 155 | }, 156 | { 157 | "cell_type": "markdown", 158 | "metadata": {}, 159 | "source": [ 160 | "## Mesh\n", 161 | "\n", 162 | "Here, we define a cylindrically symmetric tensor mesh. \n", 163 | "\n", 164 | "The figure below shows a cell in a cartesian mesh (a) and a cylindrically symmetric mesh (b). Note that edges are rotational and faces are radial and vertical in the cylindrically symmetric mesh. \n", 165 | "\n", 166 | "" 167 | ] 168 | }, 169 | { 170 | "cell_type": "markdown", 171 | "metadata": {}, 172 | "source": [ 173 | "### Mesh Parameters\n", 174 | "\n", 175 | "For the mesh, we will use a cylindrically symmetric tensor mesh. To construct a tensor mesh, all that is needed is a vector of cell widths in the x and z-directions. We will define a core mesh region of uniform cell widths and a padding region where the cell widths expand \"to infinity\". " 176 | ] 177 | }, 178 | { 179 | "cell_type": "code", 180 | "execution_count": 7, 181 | "metadata": {}, 182 | "outputs": [], 183 | "source": [ 184 | "# x-direction\n", 185 | "csx = 2 # core mesh cell width in the x-direction\n", 186 | "ncx = np.ceil(1.2*sphere_radius/csx) # number of core x-cells (uniform mesh slightly beyond sphere radius)\n", 187 | "npadx = 30 # number of x padding cells\n", 188 | "\n", 189 | "# z-direction\n", 190 | "csz = 1 # core mesh cell width in the z-direction\n", 191 | "ncz = np.ceil(1.2*(boom_height - (sphere_z-sphere_radius))/csz) # number of core z-cells (uniform cells slightly below bottom of sphere)\n", 192 | "npadz = 32 # number of z padding cells\n", 193 | "\n", 194 | "# padding factor (expand cells to infinity)\n", 195 | "pf = 1.3" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 8, 201 | "metadata": {}, 202 | "outputs": [], 203 | "source": [ 204 | "# cell spacings in the x and z directions\n", 205 | "hx = Utils.meshTensor([(csx, ncx), (csx, npadx, pf)])\n", 206 | "hz = Utils.meshTensor([(csz, npadz, -pf), (csz, ncz), (csz, npadz, pf)])\n", 207 | "\n", 208 | "# define a SimPEG mesh\n", 209 | "mesh = Mesh.CylMesh([hx, 1, hz], x0 = np.r_[0.,0., -hz.sum()/2.-boom_height])" 210 | ] 211 | }, 212 | { 213 | "cell_type": "markdown", 214 | "metadata": {}, 215 | "source": [ 216 | "### Plot the mesh\n", 217 | "\n", 218 | "Below, we plot the mesh. The cyl mesh is rotated around x=0. Ensure that each dimension extends beyond the maximum skin depth. \n", 219 | "\n", 220 | "Zoom in by changing the xlim and zlim. " 221 | ] 222 | }, 223 | { 224 | "cell_type": "code", 225 | "execution_count": 9, 226 | "metadata": {}, 227 | "outputs": [ 228 | { 229 | "name": "stdout", 230 | "output_type": "stream", 231 | "text": [ 232 | "The maximum diffusion distance (in background) is: 1.14e+04 m. Does the mesh go sufficiently past that?\n" 233 | ] 234 | }, 235 | { 236 | "data": { 237 | "image/png": "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\n", 238 | "text/plain": [ 239 | "" 240 | ] 241 | }, 242 | "metadata": {}, 243 | "output_type": "display_data" 244 | } 245 | ], 246 | "source": [ 247 | "# X and Z limits we want to plot to. Try \n", 248 | "xlim = np.r_[0., 2.5e4]\n", 249 | "zlim = np.r_[-2.5e4, 2.5e4]\n", 250 | "\n", 251 | "fig, ax = plt.subplots(1,1)\n", 252 | "mesh.plotGrid(ax=ax)\n", 253 | "\n", 254 | "ax.set_title('Simulation Mesh')\n", 255 | "ax.set_xlim(xlim)\n", 256 | "ax.set_ylim(zlim)\n", 257 | "\n", 258 | "print(\n", 259 | " 'The maximum diffusion distance (in background) is: {:.2e} m. '\n", 260 | " 'Does the mesh go sufficiently past that?'.format(\n", 261 | " diffusion_distance(sig_halfspace, times.max())\n", 262 | " )\n", 263 | ")" 264 | ] 265 | }, 266 | { 267 | "cell_type": "markdown", 268 | "metadata": {}, 269 | "source": [ 270 | "## Put Model on Mesh\n", 271 | "\n", 272 | "Now that the model parameters and mesh are defined, we can define electrical conductivity on the mesh. \n", 273 | "\n", 274 | "The electrical conductivity is defined at cell centers when using the finite volume method. So here, we define a vector that contains an electrical conductivity value for every cell center. " 275 | ] 276 | }, 277 | { 278 | "cell_type": "code", 279 | "execution_count": 10, 280 | "metadata": {}, 281 | "outputs": [], 282 | "source": [ 283 | "# create a vector that has one entry for every cell center\n", 284 | "sigma = sig_air*np.ones(mesh.nC) # start by defining the conductivity of the air everwhere\n", 285 | "sigma[mesh.gridCC[:,2] < 0.] = sig_halfspace # assign halfspace cells below the earth\n", 286 | "\n", 287 | "sigma_background = sigma.copy()\n", 288 | "\n", 289 | "# indices of the sphere (where (x-x0)**2 + (z-z0)**2 <= R**2)\n", 290 | "sphere_ind = (mesh.gridCC[:,0]**2 + (mesh.gridCC[:,2] - sphere_z)**2) <= sphere_radius**2 \n", 291 | "sigma[sphere_ind] = sig_sphere # assign the conductivity of the sphere" 292 | ] 293 | }, 294 | { 295 | "cell_type": "code", 296 | "execution_count": 11, 297 | "metadata": {}, 298 | "outputs": [ 299 | { 300 | "data": { 301 | "text/plain": [ 302 | "Text(0.5,1,'Conductivity Model')" 303 | ] 304 | }, 305 | "execution_count": 11, 306 | "metadata": {}, 307 | "output_type": "execute_result" 308 | }, 309 | { 310 | "data": { 311 | "image/png": "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\n", 312 | "text/plain": [ 313 | "" 314 | ] 315 | }, 316 | "metadata": {}, 317 | "output_type": "display_data" 318 | } 319 | ], 320 | "source": [ 321 | "# Plot a cross section of the conductivity model\n", 322 | "fig, ax = plt.subplots(1,1)\n", 323 | "cb = plt.colorbar(mesh.plotImage(np.log10(sigma), ax=ax, mirror=True)[0])\n", 324 | "\n", 325 | "# plot formatting and titles\n", 326 | "cb.set_label('$\\log_{10}\\sigma$', fontsize=13)\n", 327 | "ax.axis('equal')\n", 328 | "ax.set_xlim([-120., 120.])\n", 329 | "ax.set_ylim([-100., 30.])\n", 330 | "ax.set_title('Conductivity Model')" 331 | ] 332 | }, 333 | { 334 | "cell_type": "markdown", 335 | "metadata": {}, 336 | "source": [ 337 | "## Set up the Survey\n", 338 | "\n", 339 | "Here, we define sources and receivers. For this example, the receivers sample $db/dt$, the time-derivative of the magnetic flux. The source is a vertical magnetic dipole with unit moment. " 340 | ] 341 | }, 342 | { 343 | "cell_type": "code", 344 | "execution_count": 12, 345 | "metadata": {}, 346 | "outputs": [], 347 | "source": [ 348 | "# Define the receivers, we will sample the real secondary magnetic flux density as well as the \n", 349 | "# imaginary magnetic flux density \n", 350 | "\n", 351 | "dbdt_z = TDEM.Rx.Point_dbdt(locs=rx_loc, times=times, orientation='z') # vertical db_dt\n", 352 | "rxList = [dbdt_z] # list of receivers" 353 | ] 354 | }, 355 | { 356 | "cell_type": "code", 357 | "execution_count": 13, 358 | "metadata": {}, 359 | "outputs": [ 360 | { 361 | "name": "stdout", 362 | "output_type": "stream", 363 | "text": [ 364 | "There is 1 source. Each source has 1 receivers sampling the resulting db/dt-field at 30 times\n" 365 | ] 366 | } 367 | ], 368 | "source": [ 369 | "# Define the list of sources - one source for each frequency. The source is a point dipole oriented\n", 370 | "# in the z-direction\n", 371 | "\n", 372 | "srcList = [\n", 373 | " TDEM.Src.MagDipole(\n", 374 | " rxList, loc=src_loc, orientation='z', waveform=TDEM.Src.StepOffWaveform()\n", 375 | " )\n", 376 | "]\n", 377 | "\n", 378 | "print(\n", 379 | " 'There is {nsrc} source. Each source has {nrx} receivers '\n", 380 | " 'sampling the resulting db/dt-field at {ntimes} times'.format(\n", 381 | " nsrc = len(srcList), \n", 382 | " nrx = len(rxList),\n", 383 | " ntimes = len(times)\n", 384 | " )\n", 385 | ")" 386 | ] 387 | }, 388 | { 389 | "cell_type": "markdown", 390 | "metadata": {}, 391 | "source": [ 392 | "## Set up Forward Simulation \n", 393 | "\n", 394 | "A forward simulation consists of a paired SimPEG problem and Survey. For this example, we use the E-formulation of Maxwell's equations, solving the second-order system for the electric field, which is defined on the cell edges of the mesh. This is the `prob` variable below. The `survey` takes the source list which is used to construct the RHS for the problem. The source list also contains the receiver information, so the `survey` knows how to sample fields and fluxes that are produced by solving the `prob`.\n", 395 | "\n", 396 | "\n", 397 | "\n", 398 | "**An Aside: Mappings** \n", 399 | "\n", 400 | "The `sigmaMap` defines a [mapping](http://dev-docs.simpeg.xyz/content/api_core/api_Maps.html) which translates an input vector to a physical property - specifically, $\\sigma$. This comes in handy when you want to invert for $\\log(\\sigma)$, in that case, the model is defined in terms of log-conductivity, and you would need an `ExpMap` to translate $\\log(\\sigma) \\to \\sigma$" 401 | ] 402 | }, 403 | { 404 | "cell_type": "code", 405 | "execution_count": 14, 406 | "metadata": {}, 407 | "outputs": [ 408 | { 409 | "name": "stdout", 410 | "output_type": "stream", 411 | "text": [ 412 | "The maximum time is 1.3e-04. \n", 413 | " There are 80 timesteps, 6 of them distinct (which is the same as the number of matrices that need to be factored)\n" 414 | ] 415 | } 416 | ], 417 | "source": [ 418 | "# solve the problem at these times\n", 419 | "timeSteps = [(1e-8, 20), (1e-7, 20), (2e-7, 10), (1e-6, 10), (2e-6, 10), (1e-5, 10)] \n", 420 | "\n", 421 | "# define a problem - the statement of which discrete pde system we want to solve\n", 422 | "prob = TDEM.Problem3D_e(mesh, timeSteps = timeSteps, sigmaMap=Maps.IdentityMap(mesh)) \n", 423 | "prob.solver = Solver\n", 424 | "\n", 425 | "survey = TDEM.Survey(srcList)\n", 426 | "\n", 427 | "# tell the problem and survey about each other - so the RHS can be constructed for \n", 428 | "# the problem and the resulting fields and fluxes can be sampled by the receiver. \n", 429 | "prob.pair(survey) \n", 430 | "\n", 431 | "print(\n", 432 | " 'The maximum time is {:1.1e}. \\n There are {} timesteps, '\n", 433 | " '{} of them distinct (which is the same as the number of matrices that need to be factored)'.format(\n", 434 | " prob.times[-1], prob.nT, (len(timeSteps))\n", 435 | " )\n", 436 | ")" 437 | ] 438 | }, 439 | { 440 | "cell_type": "markdown", 441 | "metadata": {}, 442 | "source": [ 443 | "### Solve the forward simulation \n", 444 | "\n", 445 | "Here, we solve the problem for the fields everywhere on the mesh, for with and without the sphere. " 446 | ] 447 | }, 448 | { 449 | "cell_type": "code", 450 | "execution_count": 15, 451 | "metadata": {}, 452 | "outputs": [ 453 | { 454 | "name": "stdout", 455 | "output_type": "stream", 456 | "text": [ 457 | "solving with sphere ... \n", 458 | "... done \n", 459 | "CPU times: user 6.31 s, sys: 415 ms, total: 6.72 s\n", 460 | "Wall time: 4.93 s\n" 461 | ] 462 | } 463 | ], 464 | "source": [ 465 | "%%time\n", 466 | "print('solving with sphere ... ')\n", 467 | "fields = prob.fields(sigma)\n", 468 | "print('... done ')" 469 | ] 470 | }, 471 | { 472 | "cell_type": "code", 473 | "execution_count": 16, 474 | "metadata": {}, 475 | "outputs": [ 476 | { 477 | "name": "stdout", 478 | "output_type": "stream", 479 | "text": [ 480 | "solving without sphere ... \n", 481 | "... done \n", 482 | "CPU times: user 6.51 s, sys: 487 ms, total: 7 s\n", 483 | "Wall time: 6.62 s\n" 484 | ] 485 | } 486 | ], 487 | "source": [ 488 | "%%time\n", 489 | "print('solving without sphere ... ')\n", 490 | "fields_background = prob.fields(sigma_background)\n", 491 | "print('... done ')" 492 | ] 493 | }, 494 | { 495 | "cell_type": "markdown", 496 | "metadata": {}, 497 | "source": [ 498 | "### Plot the fields\n", 499 | "\n", 500 | "Lets look at the physics!" 501 | ] 502 | }, 503 | { 504 | "cell_type": "code", 505 | "execution_count": 17, 506 | "metadata": {}, 507 | "outputs": [], 508 | "source": [ 509 | "# log-scale the colorbar\n", 510 | "from matplotlib.colors import LogNorm \n", 511 | "import ipywidgets" 512 | ] 513 | }, 514 | { 515 | "cell_type": "code", 516 | "execution_count": 18, 517 | "metadata": {}, 518 | "outputs": [ 519 | { 520 | "data": { 521 | "application/vnd.jupyter.widget-view+json": { 522 | "model_id": "bb711db917ac4490b952a8724589df31", 523 | "version_major": 2, 524 | "version_minor": 0 525 | }, 526 | "text/html": [ 527 | "

Failed to display Jupyter Widget of type interactive.

\n", 528 | "

\n", 529 | " If you're reading this message in the Jupyter Notebook or JupyterLab Notebook, it may mean\n", 530 | " that the widgets JavaScript is still loading. If this message persists, it\n", 531 | " likely means that the widgets JavaScript library is either not installed or\n", 532 | " not enabled. See the Jupyter\n", 533 | " Widgets Documentation for setup instructions.\n", 534 | "

\n", 535 | "

\n", 536 | " If you're reading this message in another frontend (for example, a static\n", 537 | " rendering on GitHub or NBViewer),\n", 538 | " it may mean that your frontend doesn't currently support widgets.\n", 539 | "

\n" 540 | ], 541 | "text/plain": [ 542 | "interactive(children=(IntSlider(value=1, description='time_ind', max=79, min=1), Output()), _dom_classes=('widget-interact',))" 543 | ] 544 | }, 545 | "metadata": {}, 546 | "output_type": "display_data" 547 | }, 548 | { 549 | "data": { 550 | "text/plain": [ 551 | "" 552 | ] 553 | }, 554 | "execution_count": 18, 555 | "metadata": {}, 556 | "output_type": "execute_result" 557 | } 558 | ], 559 | "source": [ 560 | "def plot_dbdtSphere(\n", 561 | " time_ind=0 # which frequency would you like to look at?\n", 562 | "# ax=ax\n", 563 | "):\n", 564 | " fig, ax = plt.subplots(1,1, figsize=(6,5))\n", 565 | " \n", 566 | " # Plot the magnetic flux\n", 567 | " field_to_plot = fields[srcList, 'dbdt', time_ind]\n", 568 | " max_field = np.abs(field_to_plot).max() #use to set colorbar limits\n", 569 | " cb_range = 5e2 # dynamic range of colorbar\n", 570 | " \n", 571 | " cb = plt.colorbar(mesh.plotImage(\n", 572 | " field_to_plot, \n", 573 | " vType='F', view='vec', \n", 574 | " range_x=[-120., 120.], range_y=[-180., 80.],\n", 575 | " pcolorOpts={\n", 576 | " 'norm': LogNorm(), \n", 577 | " 'cmap': plt.get_cmap('viridis')\n", 578 | " },\n", 579 | " streamOpts={'color': 'w'}, mirror=True, ax=ax, \n", 580 | " clim=[max_field/cb_range, max_field]\n", 581 | " )[0], ax=ax)\n", 582 | "\n", 583 | " ax.set_xlim([-120., 120.])\n", 584 | " ax.set_ylim([-180., 70.])\n", 585 | " cb.set_label('|db/dt|')\n", 586 | "\n", 587 | " # plot the outline of the sphere\n", 588 | " x = np.linspace(-sphere_radius, sphere_radius, 100)\n", 589 | " ax.plot(x, np.sqrt(sphere_radius**2 - x**2) + sphere_z, color='k')\n", 590 | " ax.plot(x, -np.sqrt(sphere_radius**2 - x**2) + sphere_z, color='k')\n", 591 | "\n", 592 | " # plot the source and receiver locations\n", 593 | " ax.plot(src_loc[0],src_loc[2],'co', markersize=6)\n", 594 | " # ax.plot(rx_loc[0,0],rx_loc[0,2],'co', markersize=6)\n", 595 | "\n", 596 | " # plot the surface of the earth\n", 597 | " ax.plot(np.r_[-200, 200], np.r_[0., 0.], 'w:')\n", 598 | "\n", 599 | " # give it a title\n", 600 | " ax.set_title(\n", 601 | " 'db/dt, {time:10.2e} s'.format( \n", 602 | " time=prob.times[time_ind]\n", 603 | " )\n", 604 | " )\n", 605 | " plt.show()\n", 606 | " return ax\n", 607 | "\n", 608 | "ipywidgets.interact(\n", 609 | " plot_dbdtSphere, \n", 610 | " time_ind=ipywidgets.IntSlider(min=1, max=len(prob.timeSteps)-1, value=1) \n", 611 | ")" 612 | ] 613 | }, 614 | { 615 | "cell_type": "markdown", 616 | "metadata": {}, 617 | "source": [ 618 | "### Plot data with and without sphere\n", 619 | "\n", 620 | "In what follows, we plot db/dt data with and without the sphere" 621 | ] 622 | }, 623 | { 624 | "cell_type": "code", 625 | "execution_count": 19, 626 | "metadata": {}, 627 | "outputs": [], 628 | "source": [ 629 | "dpred = survey.dpred(sigma, f=fields)\n", 630 | "dpred_background = survey.dpred(sigma_background, f=fields_background)" 631 | ] 632 | }, 633 | { 634 | "cell_type": "code", 635 | "execution_count": 20, 636 | "metadata": {}, 637 | "outputs": [ 638 | { 639 | "data": { 640 | "text/plain": [ 641 | "Text(0.5,0,'time (ms)')" 642 | ] 643 | }, 644 | "execution_count": 20, 645 | "metadata": {}, 646 | "output_type": "execute_result" 647 | }, 648 | { 649 | "data": { 650 | "image/png": "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\n", 651 | "text/plain": [ 652 | "" 653 | ] 654 | }, 655 | "metadata": {}, 656 | "output_type": "display_data" 657 | } 658 | ], 659 | "source": [ 660 | "# Plot\n", 661 | "fig, ax = plt.subplots(1,1)\n", 662 | "\n", 663 | "ax.loglog(1e3*times, -dpred)\n", 664 | "ax.loglog(1e3*times, -dpred_background, '--k')\n", 665 | "ax.grid(True, color='k',linestyle=\"-\", linewidth=0.1)\n", 666 | "ax.legend(['with sphere', 'background'])\n", 667 | "\n", 668 | "ax.set_title('Sounding over Sphere')\n", 669 | "ax.set_ylabel('-$db_z/dt$')\n", 670 | "ax.set_xlabel('time (ms)')" 671 | ] 672 | }, 673 | { 674 | "cell_type": "code", 675 | "execution_count": null, 676 | "metadata": {}, 677 | "outputs": [], 678 | "source": [] 679 | } 680 | ], 681 | "metadata": { 682 | "anaconda-cloud": {}, 683 | "kernelspec": { 684 | "display_name": "Python 3", 685 | "language": "python", 686 | "name": "python3" 687 | }, 688 | "language_info": { 689 | "codemirror_mode": { 690 | "name": "ipython", 691 | "version": 3 692 | }, 693 | "file_extension": ".py", 694 | "mimetype": "text/x-python", 695 | "name": "python", 696 | "nbconvert_exporter": "python", 697 | "pygments_lexer": "ipython3", 698 | "version": "3.6.4" 699 | } 700 | }, 701 | "nbformat": 4, 702 | "nbformat_minor": 1 703 | } 704 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | scipy 3 | matplotlib 4 | ipywidgets 5 | jupyter 6 | discretize 7 | SimPEG 8 | pymatsolver 9 | pandas 10 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | if __name__ == '__main__': 2 | import os 3 | import glob 4 | import unittest 5 | test_file_strings = glob.glob('test_*.py') 6 | module_strings = [str[0:len(str)-3] for str in test_file_strings] 7 | suites = [unittest.defaultTestLoader.loadTestsFromName(str) for str 8 | in module_strings] 9 | testSuite = unittest.TestSuite(suites) 10 | 11 | unittest.TextTestRunner(verbosity=2).run(testSuite) 12 | -------------------------------------------------------------------------------- /tests/test_notebooks.py: -------------------------------------------------------------------------------- 1 | import os 2 | import testipynb 3 | import unittest 4 | 5 | NBDIR = os.path.sep.join( 6 | os.path.abspath(__file__).split(os.path.sep)[:-2] + ['notebooks'] 7 | ) 8 | IGNORE = ["DC_Mise-a-la-masse", "DC_inversion_2D_example"] 9 | 10 | class TestNotebooks(unittest.TestCase): 11 | 12 | def test_notebooks(self): 13 | Test = testipynb.TestNotebooks(directory=NBDIR, timeout=1800) 14 | self.assertTrue(Test.run_tests()) 15 | 16 | if __name__ == "__main__": 17 | unittest.main() 18 | --------------------------------------------------------------------------------