From a500f4b28b52f628054d00983fd56e0e1428ca3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dieter=20Werthm=C3=BCller?= Date: Thu, 4 Jul 2024 11:59:01 +0200 Subject: [PATCH] Update Gallery (#217) - Replace LaTeX in figures by unicode symbols - Replace implicit by explicit pyplot (OO) - Use by default coordinate system with positive z upwards - Update for Jupyterlab - Replace %matplotlib notebook by %matplotlib widget - Document ipympl along with matplotlib for frequency domain, reproducing, and published. Missing are time domain and educational. --- .gitignore | 1 + CHANGELOG.rst | 10 + docs/conf.py | 7 +- docs/manual/installation.rst | 3 +- examples/educational/coordinate_system.py | 16 +- examples/educational/dipoles_and_loops.py | 5 +- examples/educational/dlf_design.py | 2 - .../dlf_standard_lagged_splined.py | 20 +- examples/educational/halfspace_vs_dipole.py | 8 - .../educational/ht_ft_with_other_modellers.py | 4 - examples/educational/random_noise_f_domain.py | 2 - examples/educational/tmte_split.py | 4 - examples/frequency_domain/dipole_vs_bipole.py | 151 ++--- .../frequency_domain/full_vs_diffusive.py | 103 ++-- examples/frequency_domain/magnetotelluric.py | 52 +- .../frequency_domain/single_and_crossplot.py | 191 +++---- .../frequency_domain/src_rec_comparison.py | 106 ++-- .../published/article_werthmuller-2017-GEO.py | 2 +- .../published/article_werthmuller-2019-GEO.py | 3 +- .../book_ziolkowski-slob-2019-CPU.py | 2 +- .../tutorial_werthmuller-2017-TLE.py | 2 +- examples/reproducing/constable2006.py | 116 ++-- examples/reproducing/hunziker2015.py | 71 +-- examples/reproducing/ward1988.py | 540 ++++++++---------- examples/reproducing/ziolkowski2007.py | 72 ++- examples/time_domain/cole_cole_ip.py | 4 +- examples/time_domain/dc_rho-a_dip-dip.py | 2 - examples/time_domain/note_for_land_csem.py | 2 - examples/time_domain/step_and_impulse.py | 8 - examples/time_domain/tem_walktem.py | 7 +- requirements-dev.txt | 5 +- tests/test_fdesign.py | 1 + 32 files changed, 679 insertions(+), 843 deletions(-) diff --git a/.gitignore b/.gitignore index 2bc36fa4..7091d0ac 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ docs/savefig/ docs/gallery/*/ docs/my*.json docs/my*.txt +docs/sg_execution_times.rst # Pytest and coverage related htmlcov diff --git a/CHANGELOG.rst b/CHANGELOG.rst index d34a7ca9..17da1a8d 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -10,6 +10,16 @@ v2.3.x """""" +latest +------ + +- Gallery Update Part I: + - Update for Jupyterlab (ipympl/widget) + - Replaced implicit by explicit pyplots + - Use by default a positiv z-upwards coordinate system + - Part I: frequency domain; reproducing; published + + v2.3.1: Julia wrapper --------------------- diff --git a/docs/conf.py b/docs/conf.py index e6e7705b..fd3a1a44 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -1,7 +1,6 @@ import time import warnings from empymod import __version__ -from sphinx_gallery.sorting import FileNameSortKey # ==== 1. Extensions ==== @@ -51,17 +50,17 @@ 'gallery/reproducing', 'gallery/published', ], - 'capture_repr': ('_repr_html_', '__repr__'), + 'capture_repr': ('_repr_html_', ), # Patter to search for example files "filename_pattern": r"\.py", # Sort gallery example by file name instead of number of lines (default) - "within_subsection_order": FileNameSortKey, + "within_subsection_order": "FileNameSortKey", # Remove the settings (e.g., sphinx_gallery_thumbnail_number) 'remove_config_comments': True, # Show memory 'show_memory': True, # Custom first notebook cell - 'first_notebook_cell': '%matplotlib notebook', + 'first_notebook_cell': '%matplotlib widget', } # https://github.com/sphinx-gallery/sphinx-gallery/pull/521/files diff --git a/docs/manual/installation.rst b/docs/manual/installation.rst index 00b8a7db..03ea1a48 100644 --- a/docs/manual/installation.rst +++ b/docs/manual/installation.rst @@ -18,7 +18,8 @@ Requirements are the modules ``scipy``, ``numba``, and ``libdlf``. The modeller empymod comes with add-ons (``empymod.scripts``). These add-ons provide some very specific, additional functionalities. Some of these add-ons have additional, optional dependencies such as matplotlib. See the -*Add-ons*-section for their documentation. +*Add-ons*-section for their documentation. For interactive plots you will need +ipympl in addition to matplotlib. If you are new to Python we recommend using a Python distribution, which will ensure that all dependencies are met, specifically properly compiled versions diff --git a/examples/educational/coordinate_system.py b/examples/educational/coordinate_system.py index 85744fc9..b609c42d 100644 --- a/examples/educational/coordinate_system.py +++ b/examples/educational/coordinate_system.py @@ -193,7 +193,7 @@ def repeated(ax, pm): ############################################################################### # Create figure -fig = plt.figure(figsize=(8, 3.5)) +fig = plt.figure(figsize=(8, 3.5), constrained_layout=True) # Left-handed system ax1 = fig.add_subplot(121, projection=Axes3D.name, facecolor='w') @@ -211,9 +211,6 @@ def repeated(ax, pm): repeated(ax2, 1) -plt.tight_layout() -plt.show() - ############################################################################### # Dipole @@ -274,7 +271,7 @@ def repeated(ax, pm): # Plotting the two confirms that the results agree, no matter if we use the LHS # or the RHS definition. -plt.figure(figsize=(9, 4)) +plt.figure(figsize=(9, 4), constrained_layout=True) ax1 = plt.subplot(121) plt.title('Real') @@ -300,9 +297,6 @@ def repeated(ax, pm): ax2.yaxis.set_label_position("right") ax2.yaxis.tick_right() -plt.tight_layout() -plt.show() - ############################################################################### # Bipole [x1, x2, y1, y2, z1, z2] @@ -338,9 +332,6 @@ def repeated(ax, pm): plt.ylabel('$E_x$ (V/m)') plt.legend() -plt.show() - - ############################################################################### # Bipole [x, y, z, azimuth, dip] # ------------------------------ @@ -373,9 +364,6 @@ def repeated(ax, pm): plt.ylabel('$E_x$ (V/m)') plt.legend() -plt.show() - - ############################################################################### empymod.Report() diff --git a/examples/educational/dipoles_and_loops.py b/examples/educational/dipoles_and_loops.py index 8fd38bb0..496a952c 100644 --- a/examples/educational/dipoles_and_loops.py +++ b/examples/educational/dipoles_and_loops.py @@ -122,7 +122,7 @@ fs = 16 # Fontsize # Figure -fig = plt.figure(figsize=(12, 8)) +fig = plt.figure(figsize=(12, 8), constrained_layout=True) # Frequency Domain plt.subplot(231) @@ -200,8 +200,6 @@ fig.text(-0.01, 0.5, 'Amplitude; e-rec (V/m); m-rec (A/m)', va='center', rotation='vertical', fontsize=fs, color='.4') -plt.tight_layout() -plt.show() ############################################################################### # The figure shows the main points of Equations (2) and (3): @@ -300,7 +298,6 @@ def setplot(name): # Title fig.suptitle(title, y=.95, fontsize=20) - plt.show() ############################################################################### diff --git a/examples/educational/dlf_design.py b/examples/educational/dlf_design.py index b3d193f5..b6db890f 100644 --- a/examples/educational/dlf_design.py +++ b/examples/educational/dlf_design.py @@ -114,8 +114,6 @@ def plotresult(depth, res, zsrc, zrec): plt.xlim([0, 20e3]) plt.ylim([1e-14, 1]) - plt.show() - ############################################################################### # Plot the individual models diff --git a/examples/educational/dlf_standard_lagged_splined.py b/examples/educational/dlf_standard_lagged_splined.py index b3e39a1d..6ae31719 100644 --- a/examples/educational/dlf_standard_lagged_splined.py +++ b/examples/educational/dlf_standard_lagged_splined.py @@ -66,7 +66,6 @@ import empymod import numpy as np import matplotlib.pyplot as plt -from copy import deepcopy as dc plt.style.use('ggplot') # sphinx_gallery_thumbnail_number = 3 @@ -143,7 +142,7 @@ [f'{i:G}' for i in np.round(relerror*100, 1)]), '%') # Figure -plt.figure(figsize=(10, 4)) +plt.figure(figsize=(10, 4), constrained_layout=True) plt.suptitle(r'DLF example for $J_0$ Hankel transform using 5 pt filter', y=1.05) @@ -171,9 +170,6 @@ plt.xlabel(r'$x$') plt.xlim([x_x.min(), x_x.max()]) -plt.tight_layout() -plt.show() - ############################################################################### # 3. Difference between standard, lagged convolution, and splined DLF # ------------------------------------------------------------------- @@ -252,8 +248,6 @@ plt.ylabel('Fourier transform') plt.ylim([-0.1, 1.1]) -plt.show() - ############################################################################### # 3.2 Lagged Convolution DLF # -------------------------- @@ -330,8 +324,6 @@ plt.ylabel('Fourier transform') plt.ylim([-0.1, 1.1]) -plt.show() - ############################################################################### # 3.3 Splined DLF # --------------- @@ -408,8 +400,6 @@ plt.ylabel('Fourier transform') plt.ylim([-0.1, 1.1]) -plt.show() - ############################################################################### # 4. Example for the Hankel transform # ----------------------------------- @@ -499,9 +489,6 @@ plt.semilogy(x/1000, np.abs((splin100-resp)/resp), label='Splined 100/dec') plt.xlabel('Offset (km)') -plt.tight_layout() -plt.show() - ############################################################################### # Runtimes and number of required wavenumbers for each method: # @@ -554,7 +541,7 @@ t = np.logspace(0, 2, 100) xt = 2000 -tparam = dc(params) +tparam = params.copy() tparam['rec'] = [xt, 0, 200] tparam['freqtime'] = t tparam['signal'] = 0 # Impulse response @@ -610,9 +597,6 @@ plt.semilogy(t, np.abs((tspline10-tresp)/tresp), label='Splined 10/dec') plt.xlabel('Time (s)') -plt.tight_layout() -plt.show() - ############################################################################### # Runtimes and number of required frequencies for each method: # diff --git a/examples/educational/halfspace_vs_dipole.py b/examples/educational/halfspace_vs_dipole.py index 9741c4bc..8747ba11 100644 --- a/examples/educational/halfspace_vs_dipole.py +++ b/examples/educational/halfspace_vs_dipole.py @@ -56,7 +56,6 @@ def plot_t(EM, HS, title, i): HS = empymod.analytical(**inpEM, **modFS, solution='dhs', ab=ab, signal=0) plot_t(EM, HS, 'Impulse HS', i) plt.suptitle('Impulse HS') -plt.show() ############################################################################### # Switch-on HS @@ -69,7 +68,6 @@ def plot_t(EM, HS, title, i): HS = empymod.analytical(**inpEM, **modFS, solution='dhs', ab=ab, signal=1) plot_t(EM, HS, 'Switch-on HS', i) plt.suptitle('Switch-on HS') -plt.show() ############################################################################### # Switch-off HS @@ -82,7 +80,6 @@ def plot_t(EM, HS, title, i): HS = empymod.analytical(**inpEM, **modFS, solution='dhs', ab=ab, signal=-1) plot_t(EM, HS, 'Switch-off HS', i) plt.suptitle('Switch-off HS') -plt.show() ############################################################################### # Impulse FS @@ -95,7 +92,6 @@ def plot_t(EM, HS, title, i): HS = empymod.analytical(**inpEM, **modFS, solution='dfs', ab=ab, signal=0) plot_t(EM, HS, 'Impulse FS', i) plt.suptitle('Impulse FS') -plt.show() ############################################################################### # Switch-on FS @@ -108,7 +104,6 @@ def plot_t(EM, HS, title, i): HS = empymod.analytical(**inpEM, **modFS, solution='dfs', ab=ab, signal=1) plot_t(EM, HS, 'Switch-on FS', i) plt.suptitle('Switch-on FS') -plt.show() ############################################################################### # Switch-off FS @@ -123,7 +118,6 @@ def plot_t(EM, HS, title, i): HS = empymod.analytical(**inpEM, **modFS, solution='dfs', ab=ab, signal=-1) plot_t(EM, HS, 'Switch-off FS', i) plt.suptitle('Switch-off FS') -plt.show() ############################################################################### # Frequency domain @@ -153,7 +147,6 @@ def plot_f(EM, HS, title, i): plot_f(EM, HS, 'Frequency HS', i) plt.figure('Frequency HS') plt.suptitle('Frequency HS') -plt.show() ############################################################################### # Fullspace @@ -166,7 +159,6 @@ def plot_f(EM, HS, title, i): HS = empymod.analytical(**inpEM, **modFS, solution='dfs', ab=ab) plot_f(EM, HS, 'Frequency FS', i) plt.suptitle('Frequency FS') -plt.show() ############################################################################### diff --git a/examples/educational/ht_ft_with_other_modellers.py b/examples/educational/ht_ft_with_other_modellers.py index f855d9c4..715ca07f 100644 --- a/examples/educational/ht_ft_with_other_modellers.py +++ b/examples/educational/ht_ft_with_other_modellers.py @@ -73,8 +73,6 @@ plt.xlabel('Frequency (Hz)') plt.ylabel('$E_x$ (nV/m)') -plt.show() - ############################################################################### # Fourier transform # ----------------- @@ -106,8 +104,6 @@ plt.xlabel('Time (s)') plt.ylabel('$E_x$ (uV/m)') -plt.show() - ############################################################################### empymod.Report() diff --git a/examples/educational/random_noise_f_domain.py b/examples/educational/random_noise_f_domain.py index 03b37b6c..ce80f2f2 100644 --- a/examples/educational/random_noise_f_domain.py +++ b/examples/educational/random_noise_f_domain.py @@ -211,8 +211,6 @@ def stack(n, data, ntype, **kwargs): ax.set_xlim([-4, 10]) ax2.set_xlabel('Real part') -# fig.tight_layout() -fig.show() ############################################################################### # diff --git a/examples/educational/tmte_split.py b/examples/educational/tmte_split.py index 4ddf42d7..0de7b5d6 100644 --- a/examples/educational/tmte_split.py +++ b/examples/educational/tmte_split.py @@ -93,8 +93,6 @@ plt.ylim([1e-17, 1e-9]) plt.xlim([0, 15]) -plt.show() - ############################################################################### # The result shows that mainly the TM-mode contributions are sensitive to the # reservoir. For TM, all modes contribute significantly except $T^{+-}$, which @@ -124,8 +122,6 @@ plt.ylim([1e-17, 1e-9]) plt.xlim([0, 15]) -plt.show() - ############################################################################### empymod.Report() diff --git a/examples/frequency_domain/dipole_vs_bipole.py b/examples/frequency_domain/dipole_vs_bipole.py index 5d454d58..9c8da9be 100644 --- a/examples/frequency_domain/dipole_vs_bipole.py +++ b/examples/frequency_domain/dipole_vs_bipole.py @@ -2,7 +2,27 @@ Point dipole vs finite length dipole ==================================== -Comparison of a 800 m long bipole with a dipole at its centre. +Comparison of the Eₓₓ-fields (in-line electric x-directed field generated by an +electric x-directed source) between a + +- 800 m long bipole source, and a +- infinitesimal small (point) dipole source, + +where the latter is located at the center of the former. + +A common rule of thumb `¹`_ is that a finite length bipole can be approximated +by an infinitesimal small dipole, if the receivers are further away than five +times the bipole length. In this case, this would be from 4 km onwards (five +times 800 m). + +-------- + +_`¹` See, e.g., page 288 of **Spies, B. R., and F. C. Frischknecht**, 1991, +*Electromagnetic sounding*: SEG, Investigations in Geophysics, No. 3, 5, +285-425; `DOI 10.1190/1.9781560802686 +`_. There it was used to approximate a +loop as a magnetic point dipole, but similar approximations are used for finite +vs point electric dipoles. """ import empymod @@ -15,57 +35,35 @@ # Define models # ------------- -name = 'Example Model' # Model name -depth = [0, 300, 1000, 1200] # Layer boundaries -res = [2e14, 0.3, 1, 50, 1] # Anomaly resistivities -resBG = [2e14, 0.3, 1, 1, 1] # Background resistivities -aniso = [1, 1, 1.5, 1.5, 1.5] # Layer anis. (same for anomaly and background) - -# Modelling parameters -verb = 2 - -# Spatial parameters -zsrc = 250 # Src-depth -zrec = 300 # Rec-depth -fx = np.arange(5, 101)*100 # Offsets -fy = np.zeros(fx.size) # 0s +depth = [0, -300, -1000, -1200] # Layer boundaries +res_tg = [2e14, 0.3, 1, 50, 1] # Anomaly resistivities +res_bg = [2e14, 0.3, 1, 1, 1] # Background resistivities +aniso = [1, 1, 1.5, 1.5, 1.5] # Layer anisotropies (same for entire model) ############################################################################### # Plot models # ~~~~~~~~~~~ -pdepth = np.repeat(np.r_[-100, depth], 2) -pdepth[:-1] = pdepth[1:] -pdepth[-1] = 2*depth[-1] -pres = np.repeat(res, 2) -presBG = np.repeat(resBG, 2) -pani = np.repeat(aniso, 2) +p_depth = np.repeat(np.r_[100, depth, 2*depth[-1]], 2)[1:-1] # Create figure -fig = plt.figure(figsize=(7, 5), facecolor='w') -fig.subplots_adjust(wspace=.25, hspace=.4) -plt.suptitle(name, fontsize=20) +fig, (ax1, ax2) = plt.subplots(1, 2, constrained_layout=True, sharey=True) +fig.suptitle("Model", fontsize=16) # Plot Resistivities -ax1 = plt.subplot(1, 2, 1) -plt.plot(pres, pdepth, 'r') -plt.plot(presBG, pdepth, 'k') -plt.xscale('log') -plt.xlim([.2*np.array(res).min(), 2*np.array(res)[1:].max()]) -plt.ylim([1.5*depth[-1], -100]) -plt.ylabel('Depth (m)') -plt.xlabel(r'Resistivity $\rho_h\ (\Omega\,\rm{m})$') +ax1.semilogx(np.repeat(res_tg, 2), p_depth, 'C0') +ax1.semilogx(np.repeat(res_bg, 2), p_depth, 'k') +ax1.set_xlim([0.08, 500]) +ax1.set_ylim([-1800, 100]) +ax1.set_ylabel('Depth (m)') +ax1.set_xlabel('Resistivity ρₕ (Ωm)') # Plot anisotropies -ax2 = plt.subplot(1, 2, 2) -plt.plot(pani, pdepth, 'k') -plt.xlim([0, 2]) -plt.ylim([1.5*depth[-1], -100]) -plt.xlabel(r'Anisotropy $\lambda (-)$') +ax2.plot(np.repeat(aniso, 2), p_depth, 'k') +ax2.set_xlim([0, 2]) +ax2.set_xlabel('Anisotropy λ (-)') ax2.yaxis.tick_right() -plt.show() - ############################################################################### # Frequency response for f = 1 Hz # ------------------------------- @@ -73,49 +71,56 @@ # Compute # ~~~~~~~ -# Dipole -inpdat = {'src': [0, 0, zsrc, 0, 0], 'rec': [fx, fy, zrec, 0, 0], - 'depth': depth, 'freqtime': 1, 'aniso': aniso, - 'htarg': {'pts_per_dec': -1}, 'verb': verb} -fEM = empymod.bipole(**inpdat, res=res) -fEMBG = empymod.bipole(**inpdat, res=resBG) - -# Bipole -inpdat['src'] = [-400, 400, 0, 0, zsrc, zsrc] -inpdat['srcpts'] = 10 -fEMbp = empymod.bipole(**inpdat, res=res) -fEMBGbp = empymod.bipole(**inpdat, res=resBG) - +# Spatial parameters +srcz = -250 # Source depth +recz = -300 # Receiver depth +recx = np.arange(5, 101)*100 # Receiver offsets in x-direction +recy = np.zeros(96) # Receiver offsets in y-direction + +# General input +inpdat = { + 'rec': [recx, recy, recz, 0, 0], + 'depth': depth, + 'freqtime': 1, # 1 Hz + 'aniso': aniso, + 'htarg': {'pts_per_dec': -1}, # Faster computation + 'verb': 2, # Verbosity +} + +# Dipole Source [x, y, z, azm, dip] +inpdat['src'] = [0, 0, srcz, 0, 0] +dip_tg = empymod.bipole(res=res_tg, **inpdat) +dip_bg = empymod.bipole(res=res_bg, **inpdat) + +# Bipole Source [ x0, x1, y0, y1, z0, z1] +inpdat['src'] = [-400, 400, 0, 0, srcz, srcz] +inpdat['srcpts'] = 10 # Bipole computed with 10 dipoles +bip_tg = empymod.bipole(res=res_tg, **inpdat) +bip_bg = empymod.bipole(res=res_bg, **inpdat) ############################################################################### # Plot # ~~~~ -fig = plt.figure(figsize=(8, 6), facecolor='w') -fig.subplots_adjust(wspace=.25, hspace=.4) -fig.suptitle(name+': src-x, rec-x; f = 1 Hz', fontsize=16, y=1) +fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, constrained_layout=True) + +ax1.set_title("Eₓₓ; f = 1 Hz") # Plot Amplitude -ax1 = plt.subplot(2, 2, 1) -plt.semilogy(fx/1000, fEMBG.amp(), label='BG') -plt.semilogy(fx/1000, fEM.amp(), label='Anomaly') -plt.semilogy(fx/1000, fEMBGbp.amp(), '--', label='BG bipole') -plt.semilogy(fx/1000, fEMbp.amp(), '--', label='Anomaly bipole') -plt.legend(loc='best') -plt.title(r'Amplitude ($V/(A\ $m$^2$))') -plt.xlabel('Offset (km)') +ax1.semilogy(recx/1000, dip_bg.amp()) +ax1.semilogy(recx/1000, dip_tg.amp()) +ax1.semilogy(recx/1000, bip_bg.amp(), '--') +ax1.semilogy(recx/1000, bip_tg.amp(), '--') +ax1.set_ylabel('Amplitude (V/(Am²))') # Plot Phase -ax2 = plt.subplot(2, 2, 2) -plt.title(r'Phase ($^\circ$)') -plt.plot(fx/1000, fEMBG.pha(deg=True), label='BG') -plt.plot(fx/1000, fEM.pha(deg=True), label='Anomaly') -plt.plot(fx/1000, fEMBGbp.pha(deg=True), '--', label='BG bipole') -plt.plot(fx/1000, fEMbp.pha(deg=True), '--', label='Anomaly bipole') -plt.xlabel('Offset (km)') - -plt.show() +ax2.plot(recx/1000, dip_bg.pha(deg=True), label='Dipole: background') +ax2.plot(recx/1000, dip_tg.pha(deg=True), label='Dipole: anomaly') +ax2.plot(recx/1000, bip_bg.pha(deg=True), '--', label='Bipole: background') +ax2.plot(recx/1000, bip_tg.pha(deg=True), '--', label='Bipole: target') +ax2.set_xlabel('Offset (km)') +ax2.set_ylabel('Phase (°)') +ax2.legend(ncols=2, loc='upper center') ############################################################################### - empymod.Report() diff --git a/examples/frequency_domain/full_vs_diffusive.py b/examples/frequency_domain/full_vs_diffusive.py index 2dfabd34..930ebff6 100644 --- a/examples/frequency_domain/full_vs_diffusive.py +++ b/examples/frequency_domain/full_vs_diffusive.py @@ -1,11 +1,16 @@ """ -Full wavefield vs diffusive approx. for a fullspace -=================================================== +Full wavefield vs diffusive approximation for a fullspace +========================================================= -Play around to see that the difference is getting bigger for +Example comparison of the electric field using the complete Maxwell's +equations, and the electric field using the diffusive or quasi-static +approximation. -- higher frequencies, -- higher eperm/mperm. +You can play around with the parameters to see that the difference is getting +bigger for + +- higher frequencies, and +- higher electric permittivity / magnetic permeability. """ import empymod @@ -17,26 +22,20 @@ # Define model # ------------ -x = (np.arange(526))*20-500 -rx = np.repeat([x, ], np.size(x), axis=0) +x = np.arange(526)*20. - 500 +x[x == 0] += 1e-3 # Avoid warning message regarding 0 offset. +rx = np.tile(x[:, None], x.size) ry = rx.transpose() -zsrc = 150 -zrec = 200 -res = 1/3 -freq = 0.5 -ab = 11 -aniso = np.sqrt(3/.3) -perm = 1 inp = { - 'src': [0, 0, zsrc], - 'rec': [rx.ravel(), ry.ravel(), zrec], - 'res': res, - 'freqtime': freq, - 'aniso': aniso, - 'ab': ab, - 'epermH': perm, - 'mpermH': perm, - 'verb': 0 + 'src': [0, 0, 0], # Source [x, y, z] + 'rec': [rx.ravel(), ry.ravel(), 50], # Receiver [x, y, z] + 'res': 1/3, # Resistivity + 'freqtime': 0.5, # Frequency + 'aniso': np.sqrt(10), # Anisotropy + 'ab': 11, # Configuration; 11=Exx + 'epermH': 1.0, # Electric permittivity + 'mpermH': 1.0, # Magnetic permeability + 'verb': 1, # Verbosity } ############################################################################### @@ -44,12 +43,10 @@ # ----------- # Halfspace -hs = empymod.analytical(**inp, solution='dfs') -hs = hs.reshape(np.shape(rx)) +hs = empymod.analytical(solution='dfs', **inp).reshape(rx.shape) # Fullspace -fs = empymod.analytical(**inp) -fs = fs.reshape(np.shape(rx)) +fs = empymod.analytical(**inp).reshape(rx.shape) # Relative error (%) amperr = np.abs((fs.amp() - hs.amp())/fs.amp())*100 @@ -60,46 +57,38 @@ # Plot # ---- -fig, axs = plt.subplots(figsize=(10, 4.2), nrows=1, ncols=2) +fig, (ax1, ax2) = plt.subplots( + 1, 2, figsize=(9, 5), sharey=True, constrained_layout=True) +fig.suptitle('Analytical fullspace solution\nDifference between full ' + + 'wavefield and diffusive approximation.') # Min and max, properties vmin = 1e-10 vmax = 1e0 -props = {'levels': np.logspace(np.log10(vmin), np.log10(vmax), 50), - 'locator': plt.matplotlib.ticker.LogLocator(), 'cmap': 'Greys'} +props = { + 'levels': np.logspace(np.log10(vmin), np.log10(vmax), 50), + 'locator': plt.matplotlib.ticker.LogLocator(), + 'cmap': 'Greys', +} # Plot amplitude error -plt.sca(axs[0]) -plt.title(r'(a) Amplitude') -cf1 = plt.contourf(rx/1000, ry/1000, amperr.clip(vmin, vmax), **props) -plt.ylabel('Crossline offset (km)') -plt.xlabel('Inline offset (km)') -plt.xlim(min(x)/1000, max(x)/1000) -plt.ylim(min(x)/1000, max(x)/1000) -plt.axis('equal') +ax1.set_title('Amplitude') +cf1 = ax1.contourf(rx/1000, ry/1000, amperr.clip(vmin, vmax), **props) +ax1.set_ylabel('Crossline offset (km)') # Plot phase error -plt.sca(axs[1]) -plt.title(r'(b) Phase') -cf2 = plt.contourf(rx/1000, ry/1000, phaerr.clip(vmin, vmax), **props) -plt.xlabel('Inline offset (km)') -plt.xlim(min(x)/1000, max(x)/1000) -plt.ylim(min(x)/1000, max(x)/1000) -plt.axis('equal') - -# Title -plt.suptitle('Analytical fullspace solution\nDifference between full ' + - 'wavefield and diffusive approximation.', y=1.1) +ax2.set_title('Phase') +cf2 = ax2.contourf(rx/1000, ry/1000, phaerr.clip(vmin, vmax), **props) -# Plot colorbar -cax, kw = plt.matplotlib.colorbar.make_axes( - [axs[0], axs[1]], location='right', fraction=.05, pad=0.05, aspect=20) -cb = plt.colorbar(cf2, cax=cax, ticks=10**(-(np.arange(13.)[::-1])+2), **kw) -cb.set_label(r'Relative Error $(\%)$') +for ax in [ax1, ax2]: + ax.set_xlabel('Inline offset (km)') + ax.set_xlim(min(x)/1000, max(x)/1000) + ax.set_ylim(min(x)/1000, max(x)/1000) + ax.axis('equal') -# Show -plt.show() +# Plot colorbar +cb = plt.colorbar(cf2, ax=[ax1, ax2], ticks=10**np.arange(-10, 1.)) +cb.set_label('Relative Error (%)') ############################################################################### - empymod.Report() diff --git a/examples/frequency_domain/magnetotelluric.py b/examples/frequency_domain/magnetotelluric.py index 94bd2981..7f35c96a 100644 --- a/examples/frequency_domain/magnetotelluric.py +++ b/examples/frequency_domain/magnetotelluric.py @@ -10,7 +10,7 @@ Ubiquitous in MT is the plane-wave approximation, hence, that the source signal is a plane wave hitting the Earth's surface. Having a 1D source (vertical plane wave) for a layered, 1D model reduces the computation of the impedances and -from there the apparent resistivity and apparent phase a simple recursion +from there to the apparent resistivity and apparent phase to a simple recursion algorithm. As such it does not make sense to use a full EM wavefield algorithm with three-dimensional sources such as empymod to compute MT responses. However, it is still interesting to see if we can compute MT impedances with a @@ -85,19 +85,20 @@ -------- +Note that in this example we assume that positive z points upwards. + **Reference**: -- Chave, A., and Jones, A. (Eds.). (2012). The Magnetotelluric Method: Theory +- Chave, A., and Jones, A. (Eds.), 2012. The Magnetotelluric Method: Theory and Practice. Cambridge: Cambridge University Press; - https://doi.org/10.1017/CBO9781139020138. -- Pedersen, J., Hermance, J.F. Least squares inversion of one-dimensional - magnetotelluric data: An assessment of procedures employed by Brown - University. Surv Geophys 8, 187–231 (1986); - https://doi.org/10.1007/BF01902413. + `DOI: 10.1017/CBO9781139020138 `_. +- Pedersen, J., and Hermance, J.F., 1986. Least squares inversion of + one-dimensional magnetotelluric data: An assessment of procedures employed by + Brown University. Surveys in Geophysics 8, 187–231 (1986); + `DOI: 10.1007/BF01902413 `_. - This example was strongly motivated by Andrew Pethicks blog post - https://www.digitalearthlab.com/tutorial/tutorial-1d-mt-forward. - - + `tutorial-1d-mt-forward + `_. """ import empymod @@ -111,7 +112,7 @@ # -------------------------------------- resistivities = np.array([2e14, 300, 2500, 0.8, 3000, 2500]) -depths = np.array([0, 200, 600, 640, 1140]) +depths = np.array([0, -200, -600, -640, -1140]) frequencies = np.logspace(-4, 5, 101) omega = 2 * np.pi * frequencies @@ -128,7 +129,7 @@ for j in range(depths.size-1, 0, -1): # Thickness - t_j = depths[j] - depths[j-1] + t_j = depths[j-1] - depths[j] # Intrinsic impedance z_oj = np.sqrt(1j * omega * mu_0 * resistivities[j]) @@ -161,8 +162,8 @@ dist = 1_000_000_000 # 1 million kilometer (!) inp = { - 'src': (-dist, -dist, -dist), - 'rec': (0, 0, 0.1), + 'src': (dist, dist, dist), + 'rec': (0, 0, -0.1), 'res': resistivities, 'depth': depths, 'freqtime': frequencies, @@ -171,7 +172,7 @@ # Get Ex, Hy. ex = empymod.dipole(ab=11, **inp) -hy = empymod.dipole(ab=51, **inp) +hy = -empymod.dipole(ab=51, **inp) # Impedance. Z = ex/hy @@ -184,29 +185,22 @@ # Plot results # ------------ # -fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4)) +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9, 4), constrained_layout=True) ax1.set_title('Apparent resistivity') -ax1.plot(frequencies, apres_mt1d, label='MT-1D') -ax1.plot(frequencies, apres_empy, '--', label='empymod') -ax1.set_xscale('log') -ax1.set_yscale('log') +ax1.loglog(frequencies, apres_mt1d, label='MT-1D') +ax1.loglog(frequencies, apres_empy, '--', label='empymod') ax1.set_xlabel('Frequency (Hz)') -ax1.set_ylabel(r'Apparent resistivity ($\Omega\,$m)') +ax1.set_ylabel('Apparent resistivity (Ω m)') ax1.legend() ax2.set_title('Phase') -ax2.plot(frequencies, phase_mt1d*180/np.pi) -ax2.plot(frequencies, phase_empy*180/np.pi, '--') -ax2.set_xscale('log') +ax2.semilogx(frequencies, phase_mt1d*180/np.pi) +ax2.semilogx(frequencies, phase_empy*180/np.pi, '--') ax2.yaxis.tick_right() ax2.set_xlabel('Frequency (Hz)') -ax2.set_ylabel('Phase (degree)') +ax2.set_ylabel('Phase (°)') ax2.yaxis.set_label_position("right") -fig.tight_layout() -fig.show() - - ############################################################################### empymod.Report() diff --git a/examples/frequency_domain/single_and_crossplot.py b/examples/frequency_domain/single_and_crossplot.py index 774ff846..f3b71b98 100644 --- a/examples/frequency_domain/single_and_crossplot.py +++ b/examples/frequency_domain/single_and_crossplot.py @@ -2,7 +2,10 @@ A simple frequency-domain example ================================= -For a single frequency and a crossplot frequency vs offset. +A simple frequency-domain empymod example for a + +- single frequency, and a +- crossplot of a range of frequencies versus a range of offsets. """ import empymod import numpy as np @@ -14,58 +17,44 @@ # Define models # ------------- -name = 'Example Model' # Model name -depth = [0, 300, 1000, 1200] # Layer boundaries -res = [2e14, 0.3, 1, 50, 1] # Anomaly resistivities -resBG = [2e14, 0.3, 1, 1, 1] # Background resistivities -aniso = [1, 1, 1.5, 1.5, 1.5] # Layer anis. (same for anomaly & backg.) +depth = [0, -300, -1000, -1200] # Layer boundaries +res_tg = [2e14, 0.3, 1, 50, 1] # Anomaly resistivities +res_bg = [2e14, 0.3, 1, 1, 1] # Background resistivities +aniso = [1, 1, 1.5, 1.5, 1.5] # Layer anis. (same for anomaly & backg.) # Modelling parameters verb = 0 ab = 11 # source and receiver x-directed # Spatial parameters -zsrc = 250 # Src-depth -zrec = 300 # Rec-depth -fx = np.arange(20, 101)*100 # Offsets -fy = np.zeros(fx.size) # 0s +zsrc = -250 # Source depth +zrec = -300 # Receiver depth +recx = np.arange(20, 101)*100 # Receiver offsets ############################################################################### # Plot models # ~~~~~~~~~~~ -pdepth = np.repeat(np.r_[-100, depth], 2) -pdepth[:-1] = pdepth[1:] -pdepth[-1] = 2*depth[-1] -pres = np.repeat(res, 2) -presBG = np.repeat(resBG, 2) -pani = np.repeat(aniso, 2) +p_depth = np.repeat(np.r_[100, depth, 2*depth[-1]], 2)[1:-1] # Create figure -fig = plt.figure(figsize=(7, 5), facecolor='w') -fig.subplots_adjust(wspace=.25, hspace=.4) -plt.suptitle(name, fontsize=20) +fig, (ax1, ax2) = plt.subplots(1, 2, constrained_layout=True, sharey=True) +fig.suptitle("Model", fontsize=16) # Plot Resistivities -ax1 = plt.subplot(1, 2, 1) -plt.plot(pres, pdepth, 'r') -plt.plot(presBG, pdepth, 'k') -plt.xscale('log') -plt.xlim([.2*np.array(res).min(), 2*np.array(res)[1:].max()]) -plt.ylim([1.5*depth[-1], -100]) -plt.ylabel('Depth (m)') -plt.xlabel(r'Resistivity $\rho_h\ (\Omega\,\rm{m})$') +ax1.semilogx(np.repeat(res_tg, 2), p_depth, 'C0') +ax1.semilogx(np.repeat(res_bg, 2), p_depth, 'k') +ax1.set_xlim([0.08, 500]) +ax1.set_ylim([-1800, 100]) +ax1.set_ylabel('Depth (m)') +ax1.set_xlabel('Resistivity ρₕ (Ω m)') # Plot anisotropies -ax2 = plt.subplot(1, 2, 2) -plt.plot(pani, pdepth, 'k') -plt.xlim([0, 2]) -plt.ylim([1.5*depth[-1], -100]) -plt.xlabel(r'Anisotropy $\lambda (-)$') +ax2.plot(np.repeat(aniso, 2), p_depth, 'k') +ax2.set_xlim([0, 2]) +ax2.set_xlabel('Anisotropy λ (-)') ax2.yaxis.tick_right() -plt.show() - ############################################################################### # 1. Frequency response for f = 1 Hz # ---------------------------------- @@ -73,39 +62,40 @@ # Compute # ~~~~~~~ -inpdat = {'src': [0, 0, zsrc], 'rec': [fx, fy, zrec], 'depth': depth, - 'freqtime': 1, 'aniso': aniso, 'ab': ab, - 'htarg': {'pts_per_dec': -1}, 'verb': verb} - -fEM = empymod.dipole(**inpdat, res=res) -fEMBG = empymod.dipole(**inpdat, res=resBG) - +# For 1 frequency, f=1Hz +inpdat = { + 'src': [0, 0, zsrc], + 'rec': [recx, 0, zrec], + 'depth': depth, + 'freqtime': 1, + 'aniso': aniso, + 'ab': ab, + 'htarg': {'pts_per_dec': -1}, + 'verb': verb +} + +fEM_tg = empymod.dipole(res=res_tg, **inpdat) +fEM_bg = empymod.dipole(res=res_bg, **inpdat) ############################################################################### # Plot # ~~~~ -fig = plt.figure(figsize=(8, 6), facecolor='w') -fig.subplots_adjust(wspace=.25, hspace=.4) -fig.suptitle(name+': src-x, rec-x; f = 1 Hz', fontsize=16, y=1) +fig, (ax1, ax2) = plt.subplots(2, 1, sharex=True, constrained_layout=True) + +ax1.set_title("Eₓₓ; f = 1 Hz") # Plot Amplitude -ax1 = plt.subplot(2, 2, 1) -plt.semilogy(fx/1000, fEMBG.amp(), label='BG') -plt.semilogy(fx/1000, fEM.amp(), label='Anomaly') -plt.legend(loc='best') -plt.title(r'Amplitude (V/(A m$^2$))') -plt.xlabel('Offset (km)') +ax1.semilogy(recx/1000, fEM_bg.amp(), label='Dipole: background') +ax1.semilogy(recx/1000, fEM_tg.amp(), label='Dipole: anomaly') +ax1.set_ylabel('Amplitude (V/(Am²))') +ax1.legend(loc='lower left') # Plot Phase -ax2 = plt.subplot(2, 2, 2) -plt.title(r'Phase ($^\circ$)') -plt.plot(fx/1000, fEMBG.pha(deg=True), label='BG') -plt.plot(fx/1000, fEM.pha(deg=True), label='Anomaly') -plt.xlabel('Offset (km)') - -plt.show() - +ax2.plot(recx/1000, fEM_bg.pha(deg=True)) +ax2.plot(recx/1000, fEM_tg.pha(deg=True)) +ax2.set_xlabel('Offset (km)') +ax2.set_ylabel('Phase (°)') ############################################################################### # 2. Crossplot @@ -114,63 +104,58 @@ # Compute # ~~~~~~~ -# Compute responses -freq = np.logspace(-1.5, .5, 33) # 33 frequencies from -1.5 to 0.5 (logspace) -inpdat = {'src': [0, 0, zsrc], 'rec': [fx, fy, zrec], 'depth': depth, - 'freqtime': freq, 'aniso': aniso, 'ab': ab, - 'htarg': {'pts_per_dec': -1}, 'verb': verb} - -xfEM = empymod.dipole(**inpdat, res=res) -xfEMBG = empymod.dipole(**inpdat, res=resBG) - +# For 33 frequencies from -1.5 to 0.5 (logspace) +freq = np.logspace(-1.5, .5, 33) +inpdat = { + 'src': [0, 0, zsrc], + 'rec': [recx, 0, zrec], + 'depth': depth, + 'freqtime': freq, + 'aniso': aniso, + 'ab': ab, + 'htarg': {'pts_per_dec': -1}, + 'verb': verb, +} + +xfEM_tg = empymod.dipole(**inpdat, res=res_tg) +xfEM_bg = empymod.dipole(**inpdat, res=res_bg) ############################################################################### # Plot # ~~~~ lfreq = np.log10(freq) +lamp = np.log10(xfEM_tg.amp()) +namp = (xfEM_tg/xfEM_bg).amp() # Target divided by background # Create figure -fig = plt.figure(figsize=(10, 4), facecolor='w') -fig.subplots_adjust(wspace=.25, hspace=.4) +fig, (ax1, ax2) = plt.subplots( + 1, 2, sharex=True, sharey=True, constrained_layout=True) # Plot absolute (amplitude) in log10 -ax1 = plt.subplot(1, 2, 2) -plt.title(r'Normalized $|E_A/E_{BG}|\ (-)$') -plt.imshow(np.abs(xfEM/xfEMBG), interpolation='bicubic', - extent=[fx[0]/1000, fx[-1]/1000, lfreq[0], lfreq[-1]], - origin='lower', aspect='auto') -plt.grid(False) -plt.colorbar() -CS = plt.contour(fx/1000, lfreq, np.abs(xfEM/xfEMBG), [1, 3, 5, 7], colors='k') -plt.clabel(CS, inline=1, fontsize=10) -plt.ylim([lfreq[0], lfreq[-1]]) -plt.xlim([fx[0]/1000, fx[-1]/1000]) -plt.xlabel('Offset (km)') -plt.ylabel('Frequency (Hz)') -plt.yticks([-1.5, -1, -.5, 0, .5], ('0.03', '0.10', '0.32', '1.00', '3.16')) +ax1.set_title('Amplitude') +cf1 = ax1.contourf(recx/1000, lfreq, lamp, levels=50) +CS1 = ax1.contour(recx/1000, lfreq, lamp, [-14, -13, -12, -11], colors='k') +plt.clabel(CS1, inline=1, fontsize=10) +ax1.set_xlabel('Offset (km)') +ax1.set_ylabel('Frequency (Hz)') +ax1.set_yticks([-1.5, -1, -.5, 0, .5], + ('0.03', '0.10', '0.32', '1.00', '3.16')) +cb1 = plt.colorbar(cf1, ax=ax1, orientation='horizontal', + ticks=np.arange(-14., -9)) +cb1.set_label('log10|Eᵗ| (V/(Am²)') # Plot normalized -ax2 = plt.subplot(1, 2, 1) -plt.title(r'Absolute log10$|E_A|$ (V/A/m$^2$)') -plt.imshow(np.log10(np.abs(xfEM)), interpolation='bicubic', - extent=[fx[0]/1000, fx[-1]/1000, lfreq[0], lfreq[-1]], - origin='lower', aspect='auto') -plt.grid(False) -plt.colorbar() -CS = plt.contour(fx/1000, lfreq, np.log10(np.abs(xfEM)), - [-14, -13, -12, -11], colors='k') -plt.clabel(CS, inline=1, fontsize=10) -plt.ylim([lfreq[0], lfreq[-1]]) -plt.xlim([fx[0]/1000, fx[-1]/1000]) -plt.xlabel('Offset (km)') -plt.ylabel('Frequency (Hz)') -plt.yticks([-1.5, -1, -.5, 0, .5], ('0.03', '0.10', '0.32', '1.00', '3.16')) - -fig.suptitle(name+': src-x, rec-x', fontsize=18, y=1.05) - -plt.show() +ax2.set_title('Normalized Amplitude') +cf2 = ax2.contourf(recx/1000, lfreq, namp, levels=50, cmap='plasma') +CS2 = ax2.contour(recx/1000, lfreq, namp, [1, 3, 5, 7], colors='k') +plt.clabel(CS2, inline=1, fontsize=10) +ax2.set_ylim([lfreq[0], lfreq[-1]]) +ax2.set_xlim([recx[0]/1000, recx[-1]/1000]) +ax2.set_xlabel('Offset (km)') +cb2 = plt.colorbar(cf2, ax=ax2, orientation='horizontal', + ticks=np.arange(1., 9)) +cb2.set_label('|Eᵗ/Eᵇ| (-)') ############################################################################### - empymod.Report() diff --git a/examples/frequency_domain/src_rec_comparison.py b/examples/frequency_domain/src_rec_comparison.py index e3dee77d..e8d55342 100644 --- a/examples/frequency_domain/src_rec_comparison.py +++ b/examples/frequency_domain/src_rec_comparison.py @@ -1,12 +1,12 @@ """ -Comparison of all src-rec combinations -====================================== +Comparison of all source-receiver combinations +============================================== -Comparison of all source-receiver combinations; electric and magnetic +Comparison of all source-receiver combinations; both electric and magnetic. -We compute the secondary field for a simple model of a 1 Ohm.m halfspace below -air. Source is 50 m above the surface in the air, receivers are on the surface, -frequency is 1 Hz. +We compute the secondary field for a simple model of a 1 Ωm halfspace below +air. The source is 50 m above the surface in the air, receivers are on the +surface, frequency is 1 Hz. """ import empymod @@ -19,40 +19,43 @@ # ------------ x = np.linspace(-10, 10, 101)*1000 -rx = np.repeat([x, ], np.size(x), axis=0) +rx = np.tile(x[:, None], x.size) ry = rx.transpose() -inp = {'src': [0, 0, -50], - 'rec': [rx.ravel(), ry.ravel(), 0], - 'depth': 0, - 'res': [2e14, 1], - 'freqtime': 1, - 'xdirect': None, # Secondary field comp., req. empymod >= v1.6.1. - 'htarg': {'pts_per_dec': -1}, # To speed-up the calculation - 'verb': 0} +inp = { + 'src': [0, 0, -50], + 'rec': [rx.ravel(), ry.ravel(), 0], + 'depth': 0, + 'res': [2e14, 1], + 'freqtime': 1, + 'xdirect': None, # Secondary field comp., req. empymod >= v1.6.1. + 'htarg': {'pts_per_dec': -1}, # To speed-up the computation + 'verb': 0, +} ############################################################################### # Compute # ------- # All possible combinations -pab = [11, 12, 13, 14, 15, 16, 21, 22, 23, 24, 25, 26, - 31, 32, 33, 34, 35, 36, 41, 42, 43, 44, 45, 46, - 51, 52, 53, 54, 55, 56, 61, 62, 63, 64, 65, 66] +pab = (np.arange(60)+11).reshape(6, 10)[:, :6].ravel() +print(pab) # Compute and store them in fs fs = dict() for ab in pab: - fs[str(ab)] = empymod.dipole(ab=ab, **inp).reshape(np.shape(rx)) + fs[str(ab)] = empymod.dipole(ab=ab, **inp).reshape(rx.shape).amp() ############################################################################### # Plot # ---- -fig, axs = plt.subplots(figsize=(10, 12), nrows=6, ncols=6) +fig, axs = plt.subplots(6, 6, figsize=(10, 11.5), constrained_layout=True) axs = axs.ravel() +fig.suptitle('Comparison of all source-receiver combinations, electric ' + + 'and magnetic', fontsize=16) # Labels -label1 = ['x', 'y', 'z'] +label1 = ['ˣ', 'ʸ', 'ᶻ'] label2 = ['E', 'H'] # Colour settings @@ -63,54 +66,47 @@ # Loop over combinations for i, val in enumerate(pab): - plt.sca(axs[i]) + ax = axs[i] # Axis settings - plt.xlim(min(x)/1000, max(x)/1000) - plt.ylim(min(x)/1000, max(x)/1000) - plt.axis('equal') + ax.set_xlim(min(x)/1000, max(x)/1000) + ax.set_ylim(min(x)/1000, max(x)/1000) + ax.axis('equal') # Plot the contour - cf = plt.contourf( - rx/1000, ry/1000, np.abs(fs[str(val)]).clip(vmin, vmax), **props) + cf = ax.contourf(rx/1000, ry/1000, fs[str(val)].clip(vmin, vmax), **props) # Add titels if i < 6: - label = r'Src: ' + label = 'Src: ' label += label2[0] if i < 3 else label2[1] - label += '$_' + label1[i % 3] + '$' - plt.title(label, fontsize=12) + label += label1[i % 3] + ax.xaxis.set_label_position("top") + ax.set_xlabel(label, fontsize=12) + if i % 6 == 5: + label = 'Rec: ' + label += label2[0] if i < 18 else label2[1] + label += label1[(i // 6) % 3] + ax.yaxis.set_label_position("right") + ax.set_ylabel(label, fontsize=12) - # Remove unnecessary x-tick labels + # Remove unnecessary tick labels if i < 30: - plt.xticks([-10, 0, 10], ()) - - # Remove unnecessary y-tick labels; add y-labels + ax.set_xticks([-10, 0, 10], ()) if i % 6 != 0: - plt.yticks([-10, 0, 10], ()) - else: - label = r'Rec: ' - label += label2[0] if i < 18 else label2[1] - label += '$_' + label1[(i // 6) % 3] + '$' - plt.ylabel(label, fontsize=12) + ax.set_yticks([-10, 0, 10], ()) + + # Add offset labels + if i == 32: + ax.set_xlabel('X-Offset (km)', fontsize=14) + elif i == 18: + ax.set_ylabel('y-Offset (km)', fontsize=14) # Colour bar -cax, kw = plt.matplotlib.colorbar.make_axes( - axs, location='bottom', fraction=.05, pad=0.1, aspect=30) cb = plt.colorbar( - cf, cax=cax, ticks=np.logspace(np.log10(vmin), np.log10(vmax), 8), - **kw) -cb.set_label(r'Amplitude V/m (el. rec) or T (mag. rec)') - -# Annotate -plt.suptitle('Comparison of all source-receiver combinations, electric ' + - 'and magnetic', y=0.93, fontsize=16) -fig.text(0.5, 0.18, 'X-Offset (km)', ha='center', fontsize=14) -fig.text(0.01, 0.5, 'Y-Offset (km)', va='center', rotation='vertical', - fontsize=14) - -plt.show() + cf, ax=axs, orientation='horizontal', + ticks=np.logspace(np.log10(vmin), np.log10(vmax), 8)) +cb.set_label('Amplitude in V/m (electric receiver) or T (magnetic receiver)') ############################################################################### - empymod.Report() diff --git a/examples/published/article_werthmuller-2017-GEO.py b/examples/published/article_werthmuller-2017-GEO.py index 960d9619..93197232 100644 --- a/examples/published/article_werthmuller-2017-GEO.py +++ b/examples/published/article_werthmuller-2017-GEO.py @@ -2,7 +2,7 @@ empymod-paper: Werthmüller, 2017, Geophysics ============================================ -See the notebooks in the repo `empymod/article-geo2017 +See the notebooks in the repo `emsig/article-geo2017 `_ for: Werthmüller, D., 2017, **An open-source full 3D electromagnetic modeler for diff --git a/examples/published/article_werthmuller-2019-GEO.py b/examples/published/article_werthmuller-2019-GEO.py index d6f02739..111aab20 100644 --- a/examples/published/article_werthmuller-2019-GEO.py +++ b/examples/published/article_werthmuller-2019-GEO.py @@ -2,7 +2,7 @@ fdesign-paper: Werthmüller et al., 2019, Geophysics =================================================== -See the notebooks in the repo `empymod/article-fdesign +See the notebooks in the repo `emsig/article-fdesign `_ for: Werthmüller, D., K. Key, and E. Slob, 2019, **A tool for designing digital @@ -16,7 +16,6 @@ transforms - GPR example with a digital filter - """ pass # THIS IS NOT AN ACTUAL EXAMPLE, see text above for the actual repo # sphinx_gallery_thumbnail_path = '_static/thumbs/werthmuller2019_GEO.jpg' diff --git a/examples/published/book_ziolkowski-slob-2019-CPU.py b/examples/published/book_ziolkowski-slob-2019-CPU.py index 2a9c1491..cf62acf6 100644 --- a/examples/published/book_ziolkowski-slob-2019-CPU.py +++ b/examples/published/book_ziolkowski-slob-2019-CPU.py @@ -2,7 +2,7 @@ CSEM-Book: Ziolkowski & Slob, 2019, CUP ======================================= -See the notebooks in the repo `empymod/csem-ziolkowski-and-slob +See the notebooks in the repo `emsig/csem-ziolkowski-and-slob `_ for: Ziolkowski, A., and E. Slob, 2019, **Introduction to Controlled-Source diff --git a/examples/published/tutorial_werthmuller-2017-TLE.py b/examples/published/tutorial_werthmuller-2017-TLE.py index 55821ca6..9ec99a31 100644 --- a/examples/published/tutorial_werthmuller-2017-TLE.py +++ b/examples/published/tutorial_werthmuller-2017-TLE.py @@ -2,7 +2,7 @@ empymod-tutorial: Werthmüller, 2017, The Leading Edge ===================================================== -See the notebooks in the repo `empymod/article-tle2017 +See the notebooks in the repo `emsig/article-tle2017 `_ for: Werthmüller, D., 2017, **Getting started with controlled-source diff --git a/examples/reproducing/constable2006.py b/examples/reproducing/constable2006.py index 1c0ff73d..9edc39d0 100644 --- a/examples/reproducing/constable2006.py +++ b/examples/reproducing/constable2006.py @@ -14,7 +14,6 @@ """ import empymod import numpy as np -from copy import deepcopy as dc import matplotlib.pyplot as plt empymod.set_minimum(min_off=1e-10) @@ -32,88 +31,86 @@ x = np.linspace(0, 20000, 101) # TG model -inp3 = {'src': [0, 0, 900], - 'rec': [x, np.zeros(x.shape), 1000], - 'depth': [0, 1000, 2000, 2100], - 'res': [2e14, 0.3, 1, 100, 1], - 'freqtime': 1, - 'verb': 1} +inp_tg = { + 'src': [0, 0, 900], + 'rec': [x, 0, 1000], + 'depth': [0, 1000, 2000, 2100], + 'res': [2e14, 0.3, 1, 100, 1], + 'freqtime': 1, + 'verb': 1, +} # HS model -inp4 = dc(inp3) -inp4['depth'] = inp3['depth'][:2] -inp4['res'] = inp3['res'][:3] +inp_hs = inp_tg.copy() +inp_hs['depth'] = inp_tg['depth'][:2] +inp_hs['res'] = inp_tg['res'][:3] # Compute radial responses -rhs = empymod.dipole(**inp4) # Step, HS -rhs = empymod.utils.EMArray(np.nan_to_num(rhs)) -rtg = empymod.dipole(**inp3) # " " Target -rtg = empymod.utils.EMArray(np.nan_to_num(rtg)) +rhs = empymod.dipole(ab=11, **inp_hs) # Halfspace +rtg = empymod.dipole(ab=11, **inp_tg) # Target # Compute azimuthal response -ahs = empymod.dipole(**inp4, ab=22) # Step, HS -ahs = empymod.utils.EMArray(np.nan_to_num(ahs)) -atg = empymod.dipole(**inp3, ab=22) # " " Target -atg = empymod.utils.EMArray(np.nan_to_num(atg)) +ahs = empymod.dipole(ab=22, **inp_hs) # Halfspace +atg = empymod.dipole(ab=22, **inp_tg) # Target ############################################################################### # Plot # ---- -plt.figure(figsize=(9, 13)) -plt.subplots_adjust(wspace=.3, hspace=.3) +fig, axs = plt.subplots(3, 2, figsize=(9, 13), constrained_layout=True) oldsettings = np.geterr() _ = np.seterr(all='ignore') # Radial amplitude -plt.subplot(321) -plt.title('(a) Radial mode fields') -plt.plot(x/1000, np.log10(rtg.amp()), 'k', label='Model') -plt.plot(x/1000, np.log10(rhs.amp()), 'k-.', label='Half-space response') -plt.axis([0, 20, -18, -8]) -plt.xlabel('Range (km)') -plt.ylabel(r'Log$_{10}$(E-field magnitude, V/Am$^2$)') -plt.legend() +axs[0, 0].set_title('(a) Radial mode fields') +axs[0, 0].plot(x/1000, np.log10(rtg.amp()), 'k', label='Model') +axs[0, 0].plot(x/1000, np.log10(rhs.amp()), 'k-.', label='Half-space response') +axs[0, 0].axis([0, 20, -18, -8]) +axs[0, 0].set_xlabel('Range (km)') +axs[0, 0].set_xticks([0, 5, 10, 15, 20]) +axs[0, 0].set_ylabel('Log10(E-field magnitude, V/Am²)') +axs[0, 0].legend() # Radial phase -plt.subplot(323) -plt.title('(b) Radial mode phase') -plt.plot(x/1000, rtg.pha(deg=True), 'k') -plt.plot(x/1000, rhs.pha(deg=True), 'k-.') -plt.axis([0, 20, -500, 0]) -plt.xlabel('Range (km)') -plt.ylabel('Phase (degrees)') +axs[1, 0].set_title('(b) Radial mode phase') +axs[1, 0].plot(x/1000, rtg.pha(deg=True), 'k') +axs[1, 0].plot(x/1000, rhs.pha(deg=True), 'k-.') +axs[1, 0].axis([0, 20, -500, 0]) +axs[1, 0].set_xlabel('Range (km)') +axs[1, 0].set_xticks([0, 5, 10, 15, 20]) +axs[1, 0].set_ylabel('Phase (degrees)') # Azimuthal amplitude -plt.subplot(325) -plt.title('(c) Azimuthal mode fields') -plt.plot(x/1000, np.log10(atg.amp()), 'k', label='Model') -plt.plot(x/1000, np.log10(ahs.amp()), 'k-.', label='Half-space response') -plt.axis([0, 20, -18, -8]) -plt.xlabel('Range (km)') -plt.ylabel(r'Log$_{10}$(E-field magnitude, V/Am$^2$)') -plt.legend() +axs[2, 0].set_title('(c) Azimuthal mode fields') +axs[2, 0].plot(x/1000, np.log10(atg.amp()), 'k', label='Model') +axs[2, 0].plot(x/1000, np.log10(ahs.amp()), 'k-.', label='Half-space response') +axs[2, 0].axis([0, 20, -18, -8]) +axs[2, 0].set_xlabel('Range (km)') +axs[2, 0].set_xticks([0, 5, 10, 15, 20]) +axs[2, 0].set_ylabel('Log10(E-field magnitude, V/Am²)') +axs[2, 0].legend() # Azimuthal phase -plt.subplot(322) -plt.title('(d) Azimuthal mode phase') -plt.plot(x/1000, atg.pha(deg=True)+180, 'k') -plt.plot(x/1000, ahs.pha(deg=True)+180, 'k-.') -plt.axis([0, 20, -500, 0]) -plt.xlabel('Range (km)') -plt.ylabel('Phase (degrees)') +axs[0, 1].set_title('(d) Azimuthal mode phase') +axs[0, 1].plot(x/1000, atg.pha(deg=True)+180, 'k') +axs[0, 1].plot(x/1000, ahs.pha(deg=True)+180, 'k-.') +axs[0, 1].axis([0, 20, -500, 0]) +axs[0, 1].set_xlabel('Range (km)') +axs[0, 1].set_xticks([0, 5, 10, 15, 20]) +axs[0, 1].set_ylabel('Phase (degrees)') # Normalized -plt.subplot(324) -plt.title('(e) Normalized E-field magnitude') -plt.plot(x/1000, np.abs(rtg/rhs), 'k', label='Radial') -plt.plot(x/1000, np.abs(atg/ahs), 'k--', label='Azimuthal') -plt.axis([0, 20, 0, 70]) -plt.xlabel('Range (km)') -plt.legend() - -plt.show() +axs[1, 1].set_title('(e) Normalized E-field magnitude') +axs[1, 1].plot(x/1000, np.abs(rtg/rhs), 'k', label='Radial') +axs[1, 1].plot(x/1000, np.abs(atg/ahs), 'k--', label='Azimuthal') +axs[1, 1].axis([0, 20, 0, 70]) +axs[1, 1].set_xlabel('Range (km)') +axs[1, 1].set_xticks([0, 5, 10, 15, 20]) +axs[1, 1].legend() + +axs[2, 1].axis('off') + _ = np.seterr(**oldsettings) ############################################################################### @@ -126,5 +123,4 @@ # ############################################################################### - empymod.Report() diff --git a/examples/reproducing/hunziker2015.py b/examples/reproducing/hunziker2015.py index 200a7727..d0273228 100644 --- a/examples/reproducing/hunziker2015.py +++ b/examples/reproducing/hunziker2015.py @@ -2,13 +2,13 @@ Hunziker et al., 2015, Geophysics ================================= -Reproducing Figure 3 of the manual from `EMmod`. This example does, as such, +Reproducing Figure 3 of the manual from ``EMmod``. This example does, as such, not actually reproduce a figure of Hunziker et al., 2015, but of the manual that comes with the software accompanying the paper. With the software comes an -example input file named `simplemod.scr`, and the corresponding result is shown -in the manual of the code in Figure 3. +example input file named ``simplemod.scr``, and the corresponding result is +shown in the manual of the code in Figure 3. -If you are interested in reproducing the figures of the actual paper have a +If you are interested in reproducing the figures of the actual paper, have a look at the notebooks in the repo `article-geo2017 `_. @@ -18,10 +18,10 @@ response in a layered vertical transverse isotropic medium: A new look at an old problem: Geophysics, 80(1), F1–F18; DOI: `10.1190/geo2013-0411.1 `_; Software: - `software.seg.org/2015/0001 `_. + `wiki.seg.org/wiki/Software:emmod + `_. """ - import empymod import numpy as np import matplotlib.pyplot as plt @@ -30,22 +30,21 @@ # Compute the data # ---------------- # -# Compute the electric field with the parameters defined in `simplemod.scr`. +# Compute the electric field with the parameters defined in ``simplemod.scr``. # x- and y-offsets -x = np.arange(4000)*7-1999.5*7 -y = np.arange(1500)*10-749.5*10 +x = np.arange(4000)*7 - 1999.5*7 +y = np.arange(1500)*10 - 749.5*10 # Create 2D arrays of them -rx = np.repeat([x, ], np.size(y), axis=0) -ry = np.repeat([y, ], np.size(x), axis=0) -ry = ry.transpose() +rx = np.tile(x[:, None], y.size).T +ry = np.tile(y[:, None], x.size) # Compute the electric field efield = empymod.dipole( - src=[0, 0, 150], - rec=[rx.ravel(), ry.ravel(), 200], - depth=[0, 200, 1000, 1200], + src=[0, 0, -150], + rec=[rx.ravel(), ry.ravel(), -200], + depth=[0, -200, -1000, -1200], res=[2e14, 1/3, 1, 50, 1], aniso=[1, 1, np.sqrt(10), 1, 1], freqtime=0.5, @@ -55,8 +54,7 @@ mpermV=[1, 1, 1, 1, 1], ab=11, htarg={'pts_per_dec': -1}, -).reshape(np.shape(rx)) - +).reshape(rx.shape) ############################################################################### # Plot @@ -65,28 +63,31 @@ # Create a similar colormap as Hunziker et al., 2015. cmap = plt.get_cmap("jet", 61) -plt.figure(figsize=(9, 8)) +fig, (ax1, ax2) = plt.subplots( + 2, 1, figsize=(8, 7), sharex=True, constrained_layout=True) # 1. Amplitude -plt.subplot(211) -plt.title('Amplitude (V/m)') -plt.xlabel('Offset (km)') -plt.ylabel('Offset (km)') -plt.pcolormesh(x/1e3, y/1e3, np.log10(efield.amp()), - cmap=cmap, vmin=-16, vmax=-7, shading='nearest') -plt.colorbar() +ax1.set_title('Amplitude (V/m)') +cf1 = ax1.pcolormesh( + x/1e3, y/1e3, np.log10(efield.amp()), + cmap=cmap, vmin=-16, vmax=-7, shading='nearest', +) +plt.colorbar(cf1, ticks=np.array([-16, -14, -12, -10, -8])) # 2. Phase -plt.subplot(212) -plt.title('Phase (°)') -plt.xlabel('Offset (km)') -plt.ylabel('Offset (km)') -plt.pcolormesh(x/1e3, y/1e3, efield.pha(deg=False, unwrap=False, lag=True), - cmap=cmap, vmin=-np.pi, vmax=np.pi, shading='nearest') -plt.colorbar() - -plt.tight_layout() -plt.show() +ax2.set_title('Phase (°)') +ax2.set_xlabel('Offset (km)') +cf2 = ax2.pcolormesh( + x/1e3, y/1e3, efield.pha(deg=False, unwrap=False, lag=True), + cmap=cmap, vmin=-np.pi, vmax=np.pi, shading='nearest', +) +plt.colorbar(cf2, ticks=np.array([-2, 0, 2])) + +for ax in [ax1, ax2]: + ax.axis('equal') + ax.set_ylim([y.max(), y.min()]) + ax.set_yticks([5, 0, -5]) + ax.set_ylabel('Offset (km)') ############################################################################### diff --git a/examples/reproducing/ward1988.py b/examples/reproducing/ward1988.py index 1b1f2f46..8292729c 100644 --- a/examples/reproducing/ward1988.py +++ b/examples/reproducing/ward1988.py @@ -71,7 +71,7 @@ def hz(t, res, r, m=1.): t : array Times (t) res : float - Halfspace resistivity (Ohm.m) + Halfspace resistivity (Ωm) r : float Offset (m) m : float, optional @@ -106,7 +106,7 @@ def dhzdt(t, res, r, m=1.): t : array Times (t) res : float - Halfspace resistivity (Ohm.m) + Halfspace resistivity (Ωm) r : float Offset (m) m : float, optional @@ -130,65 +130,61 @@ def dhzdt(t, res, r, m=1.): ############################################################################### -# Survey parameters -# ~~~~~~~~~~~~~~~~~ -time = np.logspace(-8, 0, 301) +def pos(data): + """Return positive data; set negative data to NaN.""" + return np.where(data > 0, data, np.nan) -src = [0, 0, 0, 0, 90] -rec = [100, 0, 0, 0, 90] -depth = 0 -res = [2e14, 100] ############################################################################### # Analytical result # ~~~~~~~~~~~~~~~~~ -hz_ana = hz(time, res[1], rec[0]) -dhz_ana = dhzdt(time, res[1], rec[0]) +time = np.logspace(-8, 0, 301) +offset = 100 +resistivity = 100 +hz_ana = hz(time, resistivity, offset) +dhz_ana = dhzdt(time, resistivity, offset) ############################################################################### # Numerical result # ~~~~~~~~~~~~~~~~ -eperm = [0, 0] # Reduce early time numerical noise (diffusive approx for air) -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'freqtime': time, 'verb': 1, 'xdirect': True, 'epermH': eperm} +inp1 = { + 'src': [0, 0, 0, 0, 90], + 'rec': [offset, 0, 0, 0, 90], + 'depth': 0, + 'res': [2e24, resistivity], + 'freqtime': time, + 'verb': 1, + 'xdirect': True, + 'epermH': [0, 0], # Reduce early time numerical noise (diff. approx.) +} -hz_num = empymod.loop(signal=-1, **inp) -dhz_num = empymod.loop(signal=0, **inp) +hz_num = empymod.loop(signal=-1, **inp1) +dhz_num = empymod.loop(signal=0, **inp1) ############################################################################### # Plot the result # ~~~~~~~~~~~~~~~ +fig1, ax1 = plt.subplots(1, 1, figsize=(5, 6)) -def pos(data): - """Return positive data; set negative data to NaN.""" - return np.where(data > 0, data, np.nan) - - -plt.figure(figsize=(5, 6)) - -plt.plot(time*1e3, pos(dhz_ana), 'k-', lw=2, label='Ward & Hohmann') -plt.plot(time*1e3, pos(-dhz_ana), 'k--', lw=2) -plt.plot(time*1e3, pos(dhz_num), 'C1-', label='empymod; dHz/dt') -plt.plot(time*1e3, pos(-dhz_num), 'C1--') - -plt.plot(time*1e3, pos(hz_ana), 'k-', lw=2) -plt.plot(time*1e3, pos(-hz_ana), 'k--', lw=2) -plt.plot(time*1e3, pos(hz_num), 'C0-', label='empymod; Hz') -plt.plot(time*1e3, pos(-hz_num), 'C0--') +ax1.loglog(time*1e3, pos(dhz_ana), 'k-', lw=2, label='Ward & Hohmann') +ax1.loglog(time*1e3, pos(-dhz_ana), 'k--', lw=2) +ax1.loglog(time*1e3, pos(dhz_num), 'C1-', label='empymod; dHz/dt') +ax1.loglog(time*1e3, pos(-dhz_num), 'C1--') -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-5, 1e3]) -plt.yticks(10**np.arange(-11., 0)) -plt.ylim([1e-11, 1e-1]) -plt.xlabel('time (ms)') -plt.legend() +ax1.loglog(time*1e3, pos(hz_ana), 'k-', lw=2) +ax1.loglog(time*1e3, pos(-hz_ana), 'k--', lw=2) +ax1.loglog(time*1e3, pos(hz_num), 'C0-', label='empymod; Hz') +ax1.loglog(time*1e3, pos(-hz_num), 'C0--') -plt.show() +ax1.set_xlim([1e-5, 1e3]) +ax1.set_yticks(10**np.arange(-11., 0)) +ax1.set_ylim([1e-11, 1e-1]) +ax1.set_xlabel('time (ms)') +ax1.legend() ############################################################################### # Original Figure @@ -206,38 +202,32 @@ def pos(data): # Ward and Hohmann, 1988, Fig 4.2 # ------------------------------- -# Survey parameters +# Frequencies freq = np.logspace(-1, 5, 301) -src = [0, 0, 0, 0, 90] -rec = [100, 0, 0, 0, 90] -depth = 0 -res = [2e14, 100] # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'freqtime': freq, 'verb': 1} -fhz_num = empymod.loop(**inp) +fhz_num = empymod.loop( + src=[0, 0, 0, 0, 90], + rec=[100, 0, 0, 0, 90], + depth=0, + res=[2e14, 100], + freqtime=freq, + verb=1, +) # Figure -plt.figure(figsize=(5, 5)) - -plt.plot(freq, pos(fhz_num.real), 'C0-', label='Real') -plt.plot(freq, pos(-fhz_num.real), 'C0--') - -plt.plot(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') -plt.plot(freq, pos(-fhz_num.imag), 'C1--') +fig2, ax2 = plt.subplots(1, 1, figsize=(5, 5), constrained_layout=True) -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-1, 1e5]) -plt.ylim([1e-12, 1e-6]) -plt.xlabel('FREQUENCY (Hz)') -plt.ylabel('$H_z$ (A/m)') -plt.legend() +ax2.loglog(freq, pos(fhz_num.real), 'C0-', label='Real') +ax2.loglog(freq, pos(-fhz_num.real), 'C0--') -plt.tight_layout() +ax2.loglog(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') +ax2.loglog(freq, pos(-fhz_num.imag), 'C1--') -plt.show() +ax2.axis([1e-1, 1e5, 1e-12, 1e-6]) +ax2.set_xlabel('FREQUENCY (Hz)') +ax2.set_ylabel('Hz (A/m)') +ax2.legend() ############################################################################### # Original Figure @@ -248,38 +238,32 @@ def pos(data): # Ward and Hohmann, 1988, Fig 4.3 # ------------------------------- -# Survey parameters +# Frequencies freq = np.logspace(-1, 5, 301) -src = [0, 0, 0, 0, 90] -rec = [100, 0, 0, 0, 0] -depth = 0 -res = [2e14, 100] # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'freqtime': freq, 'verb': 1} -fhz_num = empymod.loop(**inp) +fhz_num = empymod.loop( + src=[0, 0, 0, 0, 90], + rec=[100, 0, 0, 0, 0], + depth=0, + res=[2e14, 100], + freqtime=freq, + verb=1, +) # Figure -plt.figure(figsize=(5, 5)) +fig3, ax3 = plt.subplots(1, 1, figsize=(5, 5), constrained_layout=True) -plt.plot(freq, pos(fhz_num.real), 'C0-', label='Real') -plt.plot(freq, pos(-fhz_num.real), 'C0--') +ax3.loglog(freq, pos(fhz_num.real), 'C0-', label='Real') +ax3.loglog(freq, pos(-fhz_num.real), 'C0--') -plt.plot(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') -plt.plot(freq, pos(-fhz_num.imag), 'C1--') +ax3.loglog(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') +ax3.loglog(freq, pos(-fhz_num.imag), 'C1--') -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-1, 1e5]) -plt.ylim([1e-12, 1e-6]) -plt.xlabel('FREQUENCY (Hz)') -plt.ylabel(r'$H_{\rho}$ (A/m)') -plt.legend() - -plt.tight_layout() - -plt.show() +ax3.axis([1e-1, 1e5, 1e-12, 1e-6]) +ax3.set_xlabel('FREQUENCY (Hz)') +ax3.set_ylabel('Hρ (A/m)') +ax3.legend() ############################################################################### # Original Figure @@ -289,50 +273,40 @@ def pos(data): # Ward and Hohmann, 1988, Fig 4.5 # ------------------------------- -# Survey parameters +# Times time = np.logspace(-6, 0.5, 301) -src = [0, 0, 0, 0, 90] -rec = [100, 0, 0, 0, 0] -depth = 0 -res = [2e14, 100] # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'epermH': eperm, 'freqtime': time, 'verb': 1} -fhz_num = empymod.loop(signal=1, **inp) -fdhz_num = empymod.loop(signal=0, **inp) +inp4 = { + 'src': [0, 0, 0, 0, 90], + 'rec': [100, 0, 0, 0, 0], + 'depth': 0, + 'res': [2e14, 100], + 'epermH': [0, 0], + 'freqtime': time, + 'verb': 1, +} +fhz_num = empymod.loop(signal=1, **inp4) +fdhz_num = empymod.loop(signal=0, **inp4) # Figure -plt.figure(figsize=(5, 6)) - -ax1 = plt.subplot(111) -plt.plot(time*1e3, pos(fdhz_num), 'C0-', label='dHz/dt') -plt.plot(time*1e3, pos(-fdhz_num), 'C0--') - -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-3, 2e3]) -plt.yticks(10**np.arange(-11., -1)) -plt.ylim([1e-11, 1e-1]) -plt.xlabel('time (ms)') -plt.ylabel(r'$\frac{\partial h_{\rho}}{\partial t}$ (A/m-s)') -plt.legend(loc=8) - -ax2 = ax1.twinx() - -plt.plot(time*1e3, pos(fhz_num), 'C1-', label='Hz') -plt.plot(time*1e3, pos(-fhz_num), 'C1--') - -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-3, 2e3]) -plt.yticks(10**np.arange(-16., -7)) -plt.ylim([1e-17, 1e-7]) -plt.ylabel(r'$h_{\rho}$ (A/m)') -plt.legend(loc=5) - -plt.tight_layout() -plt.show() +fig4, ax4 = plt.subplots(1, 1, figsize=(5, 6), constrained_layout=True) + +ax4.loglog(time*1e3, pos(fdhz_num), 'C0-', label='dHz/dt') +ax4.loglog(time*1e3, pos(-fdhz_num), 'C0--') +ax4.axis([1e-3, 2e3, 1e-11, 1e-1]) +ax4.set_yticks(10**np.arange(-11., -1)) +ax4.set_xlabel('time (ms)') +ax4.set_ylabel('∂hρ/∂t (A/m-s)') +ax4.legend(loc=8) + +ax4b = ax4.twinx() +ax4b.loglog(time*1e3, pos(fhz_num), 'C1-', label='Hz') +ax4b.loglog(time*1e3, pos(-fhz_num), 'C1--') +ax4b.axis([1e-3, 2e3, 1e-17, 1e-7]) +ax4b.set_yticks(10**np.arange(-16., -7)) +ax4b.set_ylabel('hρ (A/m)') +ax4b.legend(loc=5) ############################################################################### # Original Figure @@ -343,43 +317,36 @@ def pos(data): # Ward and Hohmann, 1988, Fig 4.7 # ------------------------------- -# Survey parameters +# Frequencies and loop characteristics +freq = np.logspace(-1, np.log10(250000), 301) radius = 50 area = radius**2*np.pi -freq = np.logspace(-1, np.log10(250000), 301) -src = [radius, 0, 0, 90, 0] -rec = [0, 0, 0, 0, 90] -depth = 0 -res = [2e14, 100] -strength = area/(radius/2) -mrec = True # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'freqtime': freq, 'strength': strength, 'mrec': mrec, - 'verb': 1} -fhz_num = empymod.bipole(**inp) +fhz_num = empymod.bipole( + src=[radius, 0, 0, 90, 0], + rec=[0, 0, 0, 0, 90], + depth=0, + res=[2e14, 100], + freqtime=freq, + strength=area/(radius/2), + mrec=True, + verb=1, +) # Figure -plt.figure(figsize=(5, 5)) +fig5, ax5 = plt.subplots(1, 1, figsize=(5, 5), constrained_layout=True) -plt.plot(freq, pos(fhz_num.real), 'C0-', label='Real') -plt.plot(freq, pos(-fhz_num.real), 'C0--') +ax5.loglog(freq, pos(fhz_num.real), 'C0-', label='Real') +ax5.loglog(freq, pos(-fhz_num.real), 'C0--') -plt.plot(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') -plt.plot(freq, pos(-fhz_num.imag), 'C1--') +ax5.loglog(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') +ax5.loglog(freq, pos(-fhz_num.imag), 'C1--') -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-1, 1e6]) -plt.ylim([1e-8, 1e-1]) -plt.xlabel('frequency (Hz)') -plt.ylabel('$H_z$ (A/m)') -plt.legend() - -plt.tight_layout() - -plt.show() +ax5.axis([1e-1, 1e6, 1e-8, 1e-1]) +ax5.set_xlabel('frequency (Hz)') +ax5.set_ylabel('Hz (A/m)') +ax5.legend() ############################################################################### # Original Figure @@ -390,46 +357,40 @@ def pos(data): # Ward and Hohmann, 1988, Fig 4.8 # ------------------------------- -# Survey parameters +# Times and loop characteristics +time = np.logspace(-7, -1, 301) radius = 50 area = radius**2*np.pi -time = np.logspace(-7, -1, 301) -src = [radius, 0, 0, 90, 0] -rec = [0, 0, 0, 0, 90] -depth = 0 -res = [2e14, 100] -strength = area/(radius/2) -mrec = True # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'freqtime': time, 'strength': strength, 'mrec': mrec, - 'epermH': eperm, 'verb': 1} - -fhz_num = empymod.bipole(signal=-1, **inp) -fdhz_num = empymod.bipole(signal=0, **inp) +inp6 = { + 'src': [radius, 0, 0, 90, 0], + 'rec': [0, 0, 0, 0, 90], + 'depth': 0, + 'res': [2e14, 100], + 'freqtime': time, + 'strength': area/(radius/2), + 'mrec': True, + 'epermH': [0, 0], + 'verb': 1, +} + +fhz_num = empymod.bipole(signal=-1, **inp6) +fdhz_num = empymod.bipole(signal=0, **inp6) # Figure -plt.figure(figsize=(4, 6)) +fig6, ax6 = plt.subplots(1, 1, figsize=(4, 6), constrained_layout=True) -ax1 = plt.subplot(111) -plt.plot(time*1e3, pos(fdhz_num), 'C0-', label=r'dhz/dt (A/m-s)') -plt.plot(time*1e3, pos(-fdhz_num), 'C0--') +ax6.loglog(time*1e3, pos(fdhz_num), 'C0-', label='dhz/dt (A/m-s)') +ax6.loglog(time*1e3, pos(-fdhz_num), 'C0--') -plt.plot(time*1e3, pos(fhz_num), 'C1-', label='hz (A/m)') -plt.plot(time*1e3, pos(-fhz_num), 'C1--') +ax6.plot(time*1e3, pos(fhz_num), 'C1-', label='hz (A/m)') +ax6.plot(time*1e3, pos(-fhz_num), 'C1--') -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-4, 1e2]) -plt.yticks(10**np.arange(-7., 4)) -plt.ylim([1e-7, 5e3]) - -plt.xlabel('time (ms)') -plt.legend() - -plt.tight_layout() -plt.show() +ax6.axis([1e-4, 1e2, 1e-7, 5e3]) +ax6.set_yticks(10**np.arange(-7., 4)) +ax6.set_xlabel('time (ms)') +ax6.legend() ############################################################################### # Original Figure @@ -440,38 +401,32 @@ def pos(data): # Ward and Hohmann, 1988, Fig 2.2 # ------------------------------- -# Survey parameters +# Frequencies freq = np.logspace(-2, 5, 301) -src = [0, 0, 0, 0, 0] -rec = [0, 100, 0, 0, 0] -depth = [] -res = 100 # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'freqtime': freq, 'verb': 1} -fhz_num = empymod.loop(**inp) +fhz_num = empymod.loop( + src=[0, 0, 0, 0, 0], + rec=[0, 100, 0, 0, 0], + depth=[], + res=100, + freqtime=freq, + verb=1, +) # Figure -plt.figure(figsize=(5, 5)) - -plt.plot(freq, pos(fhz_num.real), 'C0-', label='Real') -plt.plot(freq, pos(-fhz_num.real), 'C0--') +fig7, ax7 = plt.subplots(1, 1, figsize=(5, 5), constrained_layout=True) -plt.plot(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') -plt.plot(freq, pos(-fhz_num.imag), 'C1--') +ax7.loglog(freq, pos(fhz_num.real), 'C0-', label='Real') +ax7.loglog(freq, pos(-fhz_num.real), 'C0--') -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-2, 1e5]) -plt.ylim([1e-13, 1e-6]) -plt.xlabel('frequency (Hz)') -plt.ylabel('$H_z$ (A/m)') -plt.legend() +ax7.loglog(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') +ax7.loglog(freq, pos(-fhz_num.imag), 'C1--') -plt.tight_layout() - -plt.show() +ax7.axis([1e-2, 1e5, 1e-13, 1e-6]) +ax7.set_xlabel('frequency (Hz)') +ax7.set_ylabel('Hz (A/m)') +ax7.legend() ############################################################################### # Original Figure @@ -482,37 +437,32 @@ def pos(data): # Ward and Hohmann, 1988, Fig 2.3 # ------------------------------- -# Survey parameters +# Frequencies freq = np.logspace(-2, 5, 301) -src = [0, 0, 0, 0, 0] -rec = [100, 0, 0, 0, 0] -depth = [] -res = 100 # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'freqtime': freq, 'verb': 1} -fhz_num = empymod.loop(**inp) +fhz_num = empymod.loop( + src=[0, 0, 0, 0, 0], + rec=[100, 0, 0, 0, 0], + depth=[], + res=100, + freqtime=freq, + verb=1, +) # Figure -plt.figure(figsize=(5, 5)) - -plt.plot(freq, pos(fhz_num.real), 'C0-', label='Real') -plt.plot(freq, pos(-fhz_num.real), 'C0--') +fig8, ax8 = plt.subplots(1, 1, figsize=(5, 5), constrained_layout=True) -plt.plot(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') -plt.plot(freq, pos(-fhz_num.imag), 'C1--') +ax8.loglog(freq, pos(fhz_num.real), 'C0-', label='Real') +ax8.loglog(freq, pos(-fhz_num.real), 'C0--') -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-2, 1e5]) -plt.ylim([1e-13, 1e-6]) -plt.xlabel('Frequency (Hz)') -plt.ylabel(r'$H_{\rho}$ (A/m)') -plt.legend() +ax8.loglog(freq, pos(fhz_num.imag), 'C1-', label='Imaginary') +ax8.loglog(freq, pos(-fhz_num.imag), 'C1--') -plt.tight_layout() -plt.show() +ax8.axis([1e-2, 1e5, 1e-13, 1e-6]) +ax8.set_xlabel('Frequency (Hz)') +ax8.set_ylabel('Hρ (A/m)') +ax8.legend() ############################################################################### # Original Figure @@ -523,51 +473,43 @@ def pos(data): # Ward and Hohmann, 1988, Fig 2.4 # ------------------------------- -# Survey parameters +# Times time = np.logspace(-7, 0, 301) -src = [0, 0, 0, 0, 0] -rec = [0, 100, 0, 0, 0] -depth = [] -res = 100 # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'xdirect': True, 'freqtime': time, 'verb': 1} -fhz_num = empymod.loop(signal=1, **inp) -fdhz_num = empymod.loop(signal=0, **inp) +inp9 = { + 'src': [0, 0, 0, 0, 0], + 'rec': [0, 100, 0, 0, 0], + 'depth': [], + 'res': 100, + 'xdirect': True, + 'freqtime': time, + 'verb': 1, +} +fhz_num = empymod.loop(signal=1, **inp9) +fdhz_num = empymod.loop(signal=0, **inp9) # Figure -plt.figure(figsize=(5, 5)) +fig9, ax9 = plt.subplots(1, 1, figsize=(5, 5), constrained_layout=True) -ax1 = plt.subplot(111) +ax9.loglog(time*1e3, pos(fdhz_num), 'C0-', label='dHz/dt') +ax9.loglog(time*1e3, pos(-fdhz_num), 'C0--') -plt.plot(time*1e3, pos(fdhz_num), 'C0-', label='dHz/dt') -plt.plot(time*1e3, pos(-fdhz_num), 'C0--') +ax9.axis([1e-4, 1e3, 1e-12, 1e-2]) +ax9.set_yticks(10**np.arange(-12., -1)) +ax9.set_xlabel('time (ms)') +ax9.set_ylabel('∂hρ/∂t (A/m-s)') +ax9.legend(loc=8) -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-4, 1e3]) -plt.yticks(10**np.arange(-12., -1)) -plt.ylim([1e-12, 1e-2]) -plt.xlabel('time (ms)') -plt.ylabel(r'$\frac{\partial h_{\rho}}{\partial t}$ (A/m-s)') -plt.legend(loc=8) +ax9b = ax9.twinx() -ax2 = ax1.twinx() +ax9b.loglog(time*1e3, pos(fhz_num), 'C1-', label='Hz') +ax9b.loglog(time*1e3, pos(-fhz_num), 'C1--') -plt.plot(time*1e3, pos(fhz_num), 'C1-', label='Hz') -plt.plot(time*1e3, pos(-fhz_num), 'C1--') - -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-4, 1e3]) -plt.yticks(10**np.arange(-14., -3)) -plt.ylim([1e-14, 1e-4]) -plt.ylabel(r'$h_{\rho}$ (A/m)') -plt.legend(loc=5) - -plt.tight_layout() -plt.show() +ax9b.axis([1e-4, 1e3, 1e-14, 1e-4]) +ax9b.set_yticks(10**np.arange(-14., -3)) +ax9b.set_ylabel('hρ (A/m)') +ax9b.legend(loc=5) ############################################################################### # Original Figure @@ -578,51 +520,43 @@ def pos(data): # Ward and Hohmann, 1988, Fig 2.5 # ------------------------------- -# Survey parameters +# Times time = np.logspace(-7, 0, 301) -src = [0, 0, 0, 0, 0] -rec = [100, 0, 0, 0, 0] -depth = [] -res = 100 # Computation -inp = {'src': src, 'rec': rec, 'depth': depth, 'res': res, - 'xdirect': True, 'freqtime': time, 'verb': 1} -fhz_num = empymod.loop(signal=1, **inp) -fdhz_num = empymod.loop(signal=0, **inp) +inp10 = { + 'src': [0, 0, 0, 0, 0], + 'rec': [100, 0, 0, 0, 0], + 'depth': [], + 'res': 100, + 'xdirect': True, + 'freqtime': time, + 'verb': 1, +} +fhz_num = empymod.loop(signal=1, **inp10) +fdhz_num = empymod.loop(signal=0, **inp10) # Figure -plt.figure(figsize=(5, 5)) - -ax1 = plt.subplot(111) - -plt.plot(time*1e3, pos(fdhz_num), 'C0-', label='dHz/dt') -plt.plot(time*1e3, pos(-fdhz_num), 'C0--') +fig10, ax10 = plt.subplots(1, 1, figsize=(5, 5), constrained_layout=True) -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-4, 1e3]) -plt.yticks(10**np.arange(-12., -1)) -plt.ylim([1e-12, 1e-2]) -plt.xlabel('time (ms)') -plt.ylabel(r'$\frac{\partial h_{\rho}}{\partial t}$ (A/m-s)') -plt.legend(loc=8) +ax10.loglog(time*1e3, pos(fdhz_num), 'C0-', label='dHz/dt') +ax10.loglog(time*1e3, pos(-fdhz_num), 'C0--') -ax2 = ax1.twinx() +ax10.axis([1e-4, 1e3, 1e-12, 1e-2]) +ax10.set_yticks(10**np.arange(-12., -1)) +ax10.set_xlabel('time (ms)') +ax10.set_ylabel('∂hρ/∂t (A/m-s)') +ax10.legend(loc=8) -plt.plot(time*1e3, pos(fhz_num), 'C1-', label='Hz') -plt.plot(time*1e3, pos(-fhz_num), 'C1--') +ax10b = ax10.twinx() -plt.xscale('log') -plt.yscale('log') -plt.xlim([1e-4, 1e3]) -plt.yticks(10**np.arange(-16., -5)) -plt.ylim([1e-16, 1e-6]) -plt.ylabel(r'$h_{\rho}$ (A/m)') -plt.legend(loc=5) +ax10b.loglog(time*1e3, pos(fhz_num), 'C1-', label='Hz') +ax10b.loglog(time*1e3, pos(-fhz_num), 'C1--') -plt.tight_layout() -plt.show() +ax10b.axis([1e-4, 1e3, 1e-16, 1e-6]) +ax10b.set_yticks(10**np.arange(-16., -5)) +ax10b.set_ylabel('hρ (A/m)') +ax10b.legend(loc=5) ############################################################################### # Original Figure diff --git a/examples/reproducing/ziolkowski2007.py b/examples/reproducing/ziolkowski2007.py index 992c9b56..8a5b85af 100644 --- a/examples/reproducing/ziolkowski2007.py +++ b/examples/reproducing/ziolkowski2007.py @@ -14,7 +14,6 @@ """ import empymod import numpy as np -from copy import deepcopy as dc import matplotlib.pyplot as plt ############################################################################### @@ -25,58 +24,54 @@ t = np.linspace(0.001, 0.06, 101) # Target model -inp2 = {'src': [0, 0, 0.001], - 'rec': [1000, 0, 0.001], - 'depth': [0, 500, 525], - 'res': [2e14, 20, 500, 20], - 'freqtime': t, - 'verb': 1} +inp_tg = { + 'src': [0, 0, 0.001], + 'rec': [1000, 0, 0.001], + 'depth': [0, 500, 525], + 'res': [2e14, 20, 500, 20], + 'freqtime': t, + 'verb': 1, +} # HS model -inp1 = dc(inp2) -inp1['depth'] = inp2['depth'][0] -inp1['res'] = inp2['res'][:2] +inp_hs = inp_tg.copy() +inp_hs['depth'] = inp_tg['depth'][0] +inp_hs['res'] = inp_tg['res'][:2] # Compute responses -sths = empymod.dipole(**inp1, signal=1) # Step, HS -sttg = empymod.dipole(**inp2, signal=1) # " " Target -imhs = empymod.dipole(**inp1, signal=0, ft='fftlog') # Impulse, HS -imtg = empymod.dipole(**inp2, signal=0, ft='fftlog') # " " Target +sths = empymod.dipole(**inp_hs, signal=1) # Step, Halfspace +sttg = empymod.dipole(**inp_tg, signal=1) # Step, Target +imhs = empymod.dipole(**inp_hs, signal=0, ft='fftlog') # Impulse, Halfspace +imtg = empymod.dipole(**inp_tg, signal=0, ft='fftlog') # Impulse, Target ############################################################################### # Plot # ---- -plt.figure(figsize=(9, 4)) -plt.subplots_adjust(wspace=.3) +fig, (ax1, ax2) = plt.subplots( + 1, 2, figsize=(8, 4), sharex=True, constrained_layout=True) # Step response -plt.subplot(121) -plt.title('(a)') -plt.plot(np.r_[0, 0, t], np.r_[0, sths[0], sths], 'k', +ax1.set_title('(a)') +ax1.plot(np.r_[0, 0, t], np.r_[0, sths[0], sths], 'k', label='Uniform half-space') -plt.plot(np.r_[0, 0, t], np.r_[0, sttg[0], sttg], 'r', +ax1.plot(np.r_[0, 0, t], np.r_[0, sttg[0], sttg], 'r', label='Hydrocarbon reservoir') -plt.axis([-.02, 0.06, 0, 8e-9]) -plt.xlabel('Time (s)') -plt.ylabel('Electric field amplitude (V/m/A-m)') -plt.legend() +ax1.axis([-.02, 0.06, 0, 8e-9]) +ax1.set_xlabel('Time (s)') +ax1.set_ylabel('Electric field amplitude (V/m/A-m)') +ax1.legend() # Impulse response -plt.subplot(122) -plt.title('(b)') - -# Normalize by max-response -ntg = np.max(np.r_[imtg, imhs]) - -plt.plot(np.r_[0, 0, t], np.r_[2, 0, imhs/ntg], 'k', - label='Uniform half-space') -plt.plot(np.r_[0, t], np.r_[0, imtg/ntg], 'r', label='Hydrocarbon reservoir') -plt.axis([-.02, 0.06, 0, 1.02]) -plt.xlabel('Time (s)') -plt.ylabel(r'Normalized derivative ($\Omega$/m$^2$/s)') -plt.legend() -plt.show() +ax2.set_title('(b)') +ax2.plot(np.r_[0, 0, t], np.r_[2, 0, imhs/imtg.max()], + 'k', label='Uniform half-space') +ax2.plot(np.r_[0, t], np.r_[0, imtg/imtg.max()], + 'r', label='Hydrocarbon reservoir') +ax2.axis([-.02, 0.06, 0, 1.02]) +ax2.set_xlabel('Time (s)') +ax2.set_ylabel('Normalized derivative (Ω/m²/s)') +ax2.legend() ############################################################################### # Original Figure @@ -88,5 +83,4 @@ # ############################################################################### - empymod.Report() diff --git a/examples/time_domain/cole_cole_ip.py b/examples/time_domain/cole_cole_ip.py index f8abe00e..405f0958 100644 --- a/examples/time_domain/cole_cole_ip.py +++ b/examples/time_domain/cole_cole_ip.py @@ -257,7 +257,7 @@ def pos(data): return np.where(data > 0, data, np.nan) -plt.figure() +plt.figure(constrained_layout=True) plt.title('Switch-off') plt.plot(times, pos(out_bipole), '-', label='Regular Bipole') plt.plot(times, pos(-out_bipole), '--', label='') @@ -277,8 +277,6 @@ def pos(data): plt.xscale('log') plt.ylabel('$H_z$ (A/m)') plt.xlabel('time (s)') -plt.tight_layout() -plt.show() ############################################################################### diff --git a/examples/time_domain/dc_rho-a_dip-dip.py b/examples/time_domain/dc_rho-a_dip-dip.py index a3c92d67..52365958 100644 --- a/examples/time_domain/dc_rho-a_dip-dip.py +++ b/examples/time_domain/dc_rho-a_dip-dip.py @@ -123,8 +123,6 @@ def plotit(depth, a, n, res1, res2, res3, title): plt.xlabel('AB/2 (m)') plt.ylabel(r'Apparent resistivity $\rho_a (\Omega\,$m)') - plt.show() - ############################################################################### # Model 1: 2 layers diff --git a/examples/time_domain/note_for_land_csem.py b/examples/time_domain/note_for_land_csem.py index c253523d..94242ab6 100644 --- a/examples/time_domain/note_for_land_csem.py +++ b/examples/time_domain/note_for_land_csem.py @@ -85,8 +85,6 @@ plt.ylabel(r'Amplitude $[V/(m\,s)]$') plt.legend() -plt.show() - ############################################################################### # Version 1.7.0 and older # ~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/examples/time_domain/step_and_impulse.py b/examples/time_domain/step_and_impulse.py index 07239d9a..88853e25 100644 --- a/examples/time_domain/step_and_impulse.py +++ b/examples/time_domain/step_and_impulse.py @@ -161,7 +161,6 @@ def ee_xx_step(res, aniso, off, time): plt.semilogx(t, fft, 'C3:', label='FFT') plt.legend(loc='best') plt.ylim([-.1*np.max(ex), 1.1*np.max(ex)]) -plt.show() ############################################################################### @@ -174,7 +173,6 @@ def ee_xx_step(res, aniso, off, time): plt.plot(t, abs(ftl-ex)/ex, 'C2-.', label='FFTLog') plt.plot(t, abs(fft-ex)/ex, 'C3:', label='FFT') plt.legend(loc='best') -plt.show() ############################################################################### # => The error is comparable in all cases. `FFT` is not too good at later @@ -218,7 +216,6 @@ def ee_xx_step(res, aniso, off, time): plt.semilogx(t, sin, 'C1--', label='Sine Filter') plt.semilogx(t, ftl, 'C2-.', label='FFTLog') plt.legend(loc='best') -plt.show() ############################################################################### @@ -230,7 +227,6 @@ def ee_xx_step(res, aniso, off, time): plt.plot(t, abs(sin-ex)/ex, 'C1--', label='Sine Filter') plt.plot(t, abs(ftl-ex)/ex, 'C2-.', label='FFTLog') plt.legend(loc='best') -plt.show() ############################################################################### # Switch-off @@ -262,7 +258,6 @@ def ee_xx_step(res, aniso, off, time): plt.semilogx(t, sin, 'C1--', label='Cosine/Sine Filter') plt.semilogx(t, ftl, 'C2-.', label='FFTLog') plt.legend(loc='best') -plt.show() ############################################################################### @@ -274,7 +269,6 @@ def ee_xx_step(res, aniso, off, time): plt.plot(t, abs(sin-ex)/ex, 'C1--', label='Sine Filter') plt.plot(t, abs(ftl-ex)/ex, 'C2-.', label='FFTLog') plt.legend(loc='best') -plt.show() ############################################################################### # Example 2: Air-seawater-halfspace @@ -328,7 +322,6 @@ def ee_xx_step(res, aniso, off, time): plt.semilogx(t, ftl, 'C2-.', label='FFTLog') plt.semilogx(t, fft, 'C3:', label='FFT') plt.legend(loc='best') -plt.show() ############################################################################### # Step response @@ -358,7 +351,6 @@ def ee_xx_step(res, aniso, off, time): plt.semilogx(t, ftl, 'C2-.', label='FFTLog') plt.ylim([-.1e-12, 1.5*qwe.max()]) plt.legend(loc='best') -plt.show() ############################################################################### diff --git a/examples/time_domain/tem_walktem.py b/examples/time_domain/tem_walktem.py index d2427b50..8fbb8fbb 100644 --- a/examples/time_domain/tem_walktem.py +++ b/examples/time_domain/tem_walktem.py @@ -123,7 +123,6 @@ plt.xlabel('Time (ms)') plt.xlim([-9, 0.5]) plt.legend() -plt.show() ############################################################################### @@ -387,7 +386,7 @@ def walktem(moment, depth, res): # 4. Comparison # ------------- -plt.figure(figsize=(9, 5)) +plt.figure(figsize=(9, 5), constrained_layout=True) # Plot result resistive model ax1 = plt.subplot(121) @@ -449,9 +448,5 @@ def walktem(moment, depth, res): ax2.yaxis.set_minor_formatter(NullFormatter()) plt.grid(which='both', c='w') -# Finish off -plt.tight_layout() -plt.show() - ############################################################################### empymod.Report() diff --git a/requirements-dev.txt b/requirements-dev.txt index 24c8a00b..8910ec0a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -8,15 +8,16 @@ matplotlib setuptools_scm # FOR DOCUMENTATION -sphinx +sphinx>=7.3 numpydoc sphinx_design sphinx_numfig -sphinx_gallery +sphinx_gallery>=0.16 memory_profiler pydata_sphinx_theme sphinx_automodapi ipykernel +ipympl # FOR TESTING asv diff --git a/tests/test_fdesign.py b/tests/test_fdesign.py index 3967a80b..970ec036 100644 --- a/tests/test_fdesign.py +++ b/tests/test_fdesign.py @@ -133,6 +133,7 @@ def test_save_load_filter(tmpdir): assert_allclose(filt.base, dat2[1].base) +@pytest.mark.filterwarnings("ignore:FigureCanvasAgg is non-interactive") @pytest.mark.skipif(not plt, reason="Matplotlib not installed.") class TestFiguresMatplotlib: