def run(plotIt=True): # Make un-gridded xyz points x = np.linspace(-50, 50, 30) x += np.random.randn(x.size)*0.1*x y = np.linspace(-50, 50, 30) y += np.random.randn(x.size)*0.1*y z = np.r_[50.] xyz = Utils.ndgrid(x, y, z) sig = 1. f = np.r_[1.] srcLoc = np.r_[0., 0., 0.] # Use analytic fuction to compute Ex, Ey, Ez Ex, Ey, Ez = EM.Analytics.E_from_ElectricDipoleWholeSpace( xyz, srcLoc, sig, f ) if plotIt: plt.figure() ax1 = plt.subplot(121) ax2 = plt.subplot(122) # Plot Real Ex (scalar) cont1, ax1, cont1l = Utils.plot2Ddata( xyz, Ex.real, dataloc=True, ax=ax1, contourOpts={"cmap": "viridis"}, ncontour=5, level=True, levelOpts={'colors': 'k', 'linestyles': 'dashed', 'linewidths': 1} ) # Make it as (ndata,2) matrix E = np.c_[Ex, Ey] # Plot Real E (vector) cont2, ax2 = Utils.plot2Ddata( xyz, E.real, vec=True, ax=ax2, contourOpts={"cmap": "viridis"}, ncontour=5 ) cb1 = plt.colorbar( cont1, ax=ax1, orientation="horizontal", format='%.1e' ) cb1.ax.set_xticklabels(cb1.ax.get_xticklabels(), rotation=45) cb2 = plt.colorbar( cont2, ax=ax2, orientation="horizontal", format='%.1e' ) cb2.ax.set_xticklabels(cb2.ax.get_xticklabels(), rotation=45) ax1.set_xlabel("x") ax1.set_ylabel("y") ax2.set_xlabel("x") ax2.set_ylabel("y") ax1.set_aspect('equal', adjustable='box') ax2.set_aspect('equal', adjustable='box')
def run(plotIt = True): """ Plotting 2D data ================ Often measured data is in 2D, but locations are not gridded. Data can be vectoral, hence we want to plot direction and amplitude of the vector. Following example use SimPEG's analytic function (electric dipole) to generate data at 2D plane. """ # Make un-gridded xyz points x = np.linspace(-50, 50, 30) x += np.random.randn(x.size)*0.1*x y = np.linspace(-50, 50, 30) y += np.random.randn(x.size)*0.1*y z = np.r_[50.] xyz = Utils.ndgrid(x, y, z) sig = 1. f = np.r_[1.] srcLoc = np.r_[0., 0., 0.] # Use analytic fuction to compute Ex, Ey, Ez Ex, Ey, Ez = EM.Analytics.E_from_ElectricDipoleWholeSpace(xyz, srcLoc, sig, f) if plotIt: import matplotlib.pyplot as plt plt.figure() ax1 = plt.subplot(121) ax2 = plt.subplot(122) # Plot Real Ex (scalar) cont1, ax1 = Utils.plot2Ddata(xyz, Ex.real, dataloc=True, ax=ax1, contourOpts={"cmap": "viridis"}) # Make it as (ndata,2) matrix E = np.c_[Ex, Ey] # Plot Real E (vector) cont2, ax2 = Utils.plot2Ddata(xyz, E.real, vec=True, ax=ax2, contourOpts={"cmap": "viridis"}) cb1 = plt.colorbar(cont1, ax=ax1, orientation="horizontal") cb2 = plt.colorbar(cont2, ax=ax2, orientation="horizontal") ax1.set_xlabel("x") ax1.set_ylabel("y") ax2.set_xlabel("x") ax2.set_ylabel("y") ax1.set_aspect('equal', adjustable='box') ax2.set_aspect('equal', adjustable='box') plt.show()
def run(runIt=False, plotIt=True, saveIt=False, saveFig=False, cleanup=True): """ Run the bookpurnong 1D stitched RESOLVE inversions. :param bool runIt: re-run the inversions? Default downloads and plots saved results :param bool plotIt: show the plots? :param bool saveIt: save the re-inverted results? :param bool saveFig: save the figure :param bool cleanup: remove the downloaded results """ # download the data downloads, directory = download_and_unzip_data() # Load resolve data resolve = h5py.File( os.path.sep.join([directory, "booky_resolve.hdf5"]), "r" ) river_path = resolve["river_path"][()] # River path nSounding = resolve["data"].shape[0] # the # of soundings # Bird height from surface b_height_resolve = resolve["src_elevation"][()] # fetch the frequencies we are considering cpi_inds = [0, 2, 6, 8, 10] # Indices for HCP in-phase cpq_inds = [1, 3, 7, 9, 11] # Indices for HCP quadrature frequency_cp = resolve["frequency_cp"][()] # build a mesh cs, ncx, ncz, npad = 1., 10., 10., 20 hx = [(cs, ncx), (cs, npad, 1.3)] npad = 12 temp = np.logspace(np.log10(1.), np.log10(12.), 19) temp_pad = temp[-1] * 1.3 ** np.arange(npad) hz = np.r_[temp_pad[::-1], temp[::-1], temp, temp_pad] mesh = Mesh.CylMesh([hx, 1, hz], '00C') active = mesh.vectorCCz < 0. # survey parameters rxOffset = 7.86 # tx-rx separation bp = -mu_0/(4*np.pi*rxOffset**3) # primary magnetic field # re-run the inversion if runIt: # set up the mappings - we are inverting for 1D log conductivity # below the earth's surface. actMap = Maps.InjectActiveCells( mesh, active, np.log(1e-8), nC=mesh.nCz ) mapping = Maps.ExpMap(mesh) * Maps.SurjectVertical1D(mesh) * actMap # build starting and reference model sig_half = 1e-1 sig_air = 1e-8 sigma = np.ones(mesh.nCz)*sig_air sigma[active] = sig_half m0 = np.log(1e-1) * np.ones(active.sum()) # starting model mref = np.log(1e-1) * np.ones(active.sum()) # reference model # initalize empty lists for storing inversion results mopt_re = [] # recovered model dpred_re = [] # predicted data dobs_re = [] # observed data # downsample the data for the inversion nskip = 40 # set up a noise model # 10% for the 3 lowest frequencies, 15% for the two highest std = np.repeat(np.r_[np.ones(3)*0.1, np.ones(2)*0.15], 2) floor = abs(20 * bp * 1e-6) # floor of 20ppm # loop over the soundings and invert each for rxind in range(nSounding): # convert data from ppm to magnetic field (A/m^2) dobs = np.c_[ resolve["data"][rxind, :][cpi_inds].astype(float), resolve["data"][rxind, :][cpq_inds].astype(float) ].flatten() * bp * 1e-6 # perform the inversion src_height = b_height_resolve[rxind].astype(float) mopt, dpred, dobs = resolve_1Dinversions( mesh, dobs, src_height, frequency_cp, m0, mref, mapping, std=std, floor=floor ) # add results to our list mopt_re.append(mopt) dpred_re.append(dpred) dobs_re.append(dobs) # save results mopt_re = np.vstack(mopt_re) dpred_re = np.vstack(dpred_re) dobs_re = np.vstack(dobs_re) if saveIt: np.save("mopt_re_final", mopt_re) np.save("dobs_re_final", dobs_re) np.save("dpred_re_final", dpred_re) mopt_re = resolve["mopt"][()] dobs_re = resolve["dobs"][()] dpred_re = resolve["dpred"][()] sigma = np.exp(mopt_re) indz = -7 # depth index # so that we can visually compare with literature (eg Viezzoli, 2010) cmap = "jet" # dummy figure for colobar fig = plt.figure() out = plt.scatter( np.ones(3), np.ones(3), c=np.linspace(-2, 1, 3), cmap=cmap ) plt.close(fig) # plot from the paper fs = 13 # fontsize # matplotlib.rcParams['font.size'] = fs plt.figure(figsize=(13, 7)) ax0 = plt.subplot2grid((2, 3), (0, 0), rowspan=2, colspan=2) ax1 = plt.subplot2grid((2, 3), (0, 2) ) ax2 = plt.subplot2grid((2, 3), (1, 2)) # titles of plots title = [ ("(a) Recovered model, %.1f m depth")%(-mesh.vectorCCz[active][indz]), "(b) Obs (Real 400 Hz)", "(c) Pred (Real 400 Hz)" ] temp = sigma[:, indz] tree = cKDTree(list(zip(resolve["xy"][:, 0], resolve["xy"][:, 1]))) d, d_inds = tree.query( list(zip(resolve["xy"][:, 0], resolve["xy"][:, 1])), k=20 ) w = 1. / (d+100.)**2. w = Utils.sdiag(1./np.sum(w, axis=1)) * (w) xy = resolve["xy"] temp = (temp.flatten()[d_inds] * w).sum(axis=1) Utils.plot2Ddata( xy, temp, ncontour=100, scale="log", dataloc=False, contourOpts={"cmap": cmap, "vmin": 1e-2, "vmax": 1e1}, ax=ax0 ) ax0.plot( resolve["xy"][:, 0], resolve["xy"][:, 1], 'k.', alpha=0.02, ms=1 ) cb = plt.colorbar( out, ax=ax0, ticks=np.linspace(-2, 1, 4), format="$10^{%.1f}$" ) cb.set_ticklabels(["0.01", "0.1", "1", "10"]) cb.set_label("Conductivity (S/m)") ax0.plot(river_path[:, 0], river_path[:, 1], 'k-', lw=0.5) # plot observed and predicted data freq_ind = 0 axs = [ax1, ax2] temp_dobs = dobs_re[:, freq_ind].copy() ax1.plot(river_path[:, 0], river_path[:, 1], 'k-', lw=0.5) out = Utils.plot2Ddata( resolve["xy"][()], temp_dobs/abs(bp)*1e6, ncontour=100, scale="log", dataloc=False, ax=ax1, contourOpts={"cmap": "viridis"} ) vmin, vmax = out[0].get_clim() cb = plt.colorbar(out[0], ticks=np.linspace(vmin, vmax, 3), ax=ax1, format="%.1e", fraction=0.046, pad=0.04) cb.set_label("Bz (ppm)") temp_dpred = dpred_re[:, freq_ind].copy() # temp_dpred[mask_:_data] = np.nan ax2.plot(river_path[:, 0], river_path[:, 1], 'k-', lw=0.5) Utils.plot2Ddata( resolve["xy"][()], temp_dpred/abs(bp)*1e6, ncontour=100, scale="log", dataloc=False, contourOpts={"vmin": 10**vmin, "vmax": 10**vmax, "cmap": "viridis"}, ax=ax2 ) cb = plt.colorbar( out[0], ticks=np.linspace(vmin, vmax, 3), ax=ax2, format="%.1e", fraction=0.046, pad=0.04 ) cb.set_label("Bz (ppm)") for i, ax in enumerate([ax0, ax1, ax2]): xticks = [460000, 463000] yticks = [6195000, 6198000, 6201000] xloc, yloc = 462100.0, 6196500.0 ax.set_xticks(xticks) ax.set_yticks(yticks) # ax.plot(xloc, yloc, 'wo') ax.plot(river_path[:, 0], river_path[:, 1], 'k', lw=0.5) ax.set_aspect("equal") ax.plot( resolve["xy"][:, 0], resolve["xy"][:, 1], 'k.', alpha=0.02, ms=1 ) ax.set_yticklabels([str(f) for f in yticks]) ax.set_ylabel("Northing (m)") ax.set_xlabel("Easting (m)") ax.set_title(title[i]) plt.tight_layout() if plotIt: plt.show() if saveFig is True: fig.savefig("obspred_resolve.png", dpi=200) resolve.close() if cleanup: os.remove(downloads) shutil.rmtree(directory)
def run(plotIt=True, saveFig=False, cleanup=True): """ Run 1D inversions for a single sounding of the RESOLVE and SkyTEM bookpurnong data :param bool plotIt: show the plots? :param bool saveFig: save the figure :param bool cleanup: remove the downloaded results """ downloads, directory = download_and_unzip_data() resolve = h5py.File( os.path.sep.join([directory, "booky_resolve.hdf5"]), "r" ) skytem = h5py.File( os.path.sep.join([directory, "booky_skytem.hdf5"]), "r" ) river_path = resolve["river_path"].value # Choose a sounding location to invert xloc, yloc = 462100.0, 6196500.0 rxind_skytem = np.argmin( abs(skytem["xy"][:, 0]-xloc)+abs(skytem["xy"][:, 1]-yloc) ) rxind_resolve = np.argmin( abs(resolve["xy"][:, 0]-xloc)+abs(resolve["xy"][:, 1]-yloc) ) # Plot both resolve and skytem data on 2D plane fig = plt.figure(figsize=(13, 6)) title = ["RESOLVE In-phase 400 Hz", "SkyTEM High moment 156 $\mu$s"] ax1 = plt.subplot(121) ax2 = plt.subplot(122) axs = [ax1, ax2] out_re = Utils.plot2Ddata( resolve["xy"], resolve["data"][:, 0], ncontour=100, contourOpts={"cmap": "viridis"}, ax=ax1 ) vmin, vmax = out_re[0].get_clim() cb_re = plt.colorbar( out_re[0], ticks=np.linspace(vmin, vmax, 3), ax=ax1, fraction=0.046, pad=0.04 ) temp_skytem = skytem["data"][:, 5].copy() temp_skytem[skytem["data"][:, 5] > 7e-10] = 7e-10 out_sky = Utils.plot2Ddata( skytem["xy"][:, :2], temp_skytem, ncontour=100, contourOpts={"cmap": "viridis", "vmax": 7e-10}, ax=ax2 ) vmin, vmax = out_sky[0].get_clim() cb_sky = plt.colorbar( out_sky[0], ticks=np.linspace(vmin, vmax*0.99, 3), ax=ax2, format="%.1e", fraction=0.046, pad=0.04 ) cb_re.set_label("Bz (ppm)") cb_sky.set_label("dB$_z$ / dt (V/A-m$^4$)") for i, ax in enumerate(axs): xticks = [460000, 463000] yticks = [6195000, 6198000, 6201000] ax.set_xticks(xticks) ax.set_yticks(yticks) ax.plot(xloc, yloc, 'wo') ax.plot(river_path[:, 0], river_path[:, 1], 'k', lw=0.5) ax.set_aspect("equal") if i == 1: ax.plot( skytem["xy"][:, 0], skytem["xy"][:, 1], 'k.', alpha=0.02, ms=1 ) ax.set_yticklabels([str(" ") for f in yticks]) else: ax.plot( resolve["xy"][:, 0], resolve["xy"][:, 1], 'k.', alpha=0.02, ms=1 ) ax.set_yticklabels([str(f) for f in yticks]) ax.set_ylabel("Northing (m)") ax.set_xlabel("Easting (m)") ax.set_title(title[i]) ax.axis('equal') # plt.tight_layout() if saveFig is True: fig.savefig("resolve_skytem_data.png", dpi=600) # ------------------ Mesh ------------------ # # Step1: Set 2D cylindrical mesh cs, ncx, ncz, npad = 1., 10., 10., 20 hx = [(cs, ncx), (cs, npad, 1.3)] npad = 12 temp = np.logspace(np.log10(1.), np.log10(12.), 19) temp_pad = temp[-1] * 1.3 ** np.arange(npad) hz = np.r_[temp_pad[::-1], temp[::-1], temp, temp_pad] mesh = Mesh.CylMesh([hx, 1, hz], '00C') active = mesh.vectorCCz < 0. # Step2: Set a SurjectVertical1D mapping # Note: this sets our inversion model as 1D log conductivity # below subsurface active = mesh.vectorCCz < 0. actMap = Maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = Maps.ExpMap(mesh) * Maps.SurjectVertical1D(mesh) * actMap sig_half = 1e-1 sig_air = 1e-8 sigma = np.ones(mesh.nCz)*sig_air sigma[active] = sig_half # Initial and reference model m0 = np.log(sigma[active]) # ------------------ RESOLVE Forward Simulation ------------------ # # Step3: Invert Resolve data # Bird height from the surface b_height_resolve = resolve["src_elevation"].value src_height_resolve = b_height_resolve[rxind_resolve] # Set Rx (In-phase and Quadrature) rxOffset = 7.86 bzr = EM.FDEM.Rx.Point_bSecondary( np.array([[rxOffset, 0., src_height_resolve]]), orientation='z', component='real' ) bzi = EM.FDEM.Rx.Point_b( np.array([[rxOffset, 0., src_height_resolve]]), orientation='z', component='imag' ) # Set Source (In-phase and Quadrature) frequency_cp = resolve["frequency_cp"].value freqs = frequency_cp.copy() srcLoc = np.array([0., 0., src_height_resolve]) srcList = [EM.FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation='Z') for freq in freqs] # Set FDEM survey (In-phase and Quadrature) survey = EM.FDEM.Survey(srcList) prb = EM.FDEM.Problem3D_b( mesh, sigmaMap=mapping, Solver=Solver ) prb.pair(survey) # ------------------ RESOLVE Inversion ------------------ # # Primary field bp = - mu_0/(4*np.pi*rxOffset**3) # Observed data cpi_inds = [0, 2, 6, 8, 10] cpq_inds = [1, 3, 7, 9, 11] dobs_re = np.c_[ resolve["data"][rxind_resolve, :][cpi_inds], resolve["data"][rxind_resolve, :][cpq_inds] ].flatten() * bp * 1e-6 # Uncertainty std = np.repeat(np.r_[np.ones(3)*0.1, np.ones(2)*0.15], 2) floor = 20 * abs(bp) * 1e-6 uncert = abs(dobs_re) * std + floor # Data Misfit survey.dobs = dobs_re dmisfit = DataMisfit.l2_DataMisfit(survey) dmisfit.W = 1./uncert # Regularization regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh, mapping=Maps.IdentityMap(regMesh)) # Optimization opt = Optimization.InexactGaussNewton(maxIter=5) # statement of the inverse problem invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion directives and parameters target = Directives.TargetMisfit() # stop when we hit target misfit invProb.beta = 2. # betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) inv = Inversion.BaseInversion(invProb, directiveList=[target]) reg.alpha_s = 1e-3 reg.alpha_x = 1. reg.mref = m0.copy() opt.LSshorten = 0.5 opt.remember('xc') # run the inversion mopt_re = inv.run(m0) dpred_re = invProb.dpred # ------------------ SkyTEM Forward Simulation ------------------ # # Step4: Invert SkyTEM data # Bird height from the surface b_height_skytem = skytem["src_elevation"].value src_height = b_height_skytem[rxind_skytem] srcLoc = np.array([0., 0., src_height]) # Radius of the source loop area = skytem["area"].value radius = np.sqrt(area/np.pi) rxLoc = np.array([[radius, 0., src_height]]) # Parameters for current waveform t0 = skytem["t0"].value times = skytem["times"].value waveform_skytem = skytem["waveform"].value offTime = t0 times_off = times - t0 # Note: we are Using theoretical VTEM waveform, # but effectively fits SkyTEM waveform peakTime = 1.0000000e-02 a = 3. dbdt_z = EM.TDEM.Rx.Point_dbdt( locs=rxLoc, times=times_off[:-3]+offTime, orientation='z' ) # vertical db_dt rxList = [dbdt_z] # list of receivers srcList = [ EM.TDEM.Src.CircularLoop( rxList, loc=srcLoc, radius=radius, orientation='z', waveform=EM.TDEM.Src.VTEMWaveform( offTime=offTime, peakTime=peakTime, a=3. ) ) ] # solve the problem at these times timeSteps = [ (peakTime/5, 5), ((offTime-peakTime)/5, 5), (1e-5, 5), (5e-5, 5), (1e-4, 10), (5e-4, 15) ] prob = EM.TDEM.Problem3D_e( mesh, timeSteps=timeSteps, sigmaMap=mapping, Solver=Solver ) survey = EM.TDEM.Survey(srcList) prob.pair(survey) src = srcList[0] rx = src.rxList[0] wave = [] for time in prob.times: wave.append(src.waveform.eval(time)) wave = np.hstack(wave) out = survey.dpred(m0) # plot the waveform fig = plt.figure(figsize=(5, 3)) times_off = times-t0 plt.plot(waveform_skytem[:, 0], waveform_skytem[:, 1], 'k.') plt.plot(prob.times, wave, 'k-', lw=2) plt.legend(("SkyTEM waveform", "Waveform (fit)"), fontsize=10) for t in rx.times: plt.plot(np.ones(2)*t, np.r_[-0.03, 0.03], 'k-') plt.ylim(-0.1, 1.1) plt.grid(True) plt.xlabel("Time (s)") plt.ylabel("Normalized current") if saveFig: fig.savefig("skytem_waveform", dpi=200) # Observed data dobs_sky = skytem["data"][rxind_skytem, :-3] * area # ------------------ SkyTEM Inversion ------------------ # # Uncertainty std = 0.12 floor = 7.5e-12 uncert = abs(dobs_sky) * std + floor # Data Misfit survey.dobs = -dobs_sky dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = 0.12*abs(dobs_sky) + 7.5e-12 dmisfit.W = Utils.sdiag(1./uncert) # Regularization regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh, mapping=Maps.IdentityMap(regMesh)) # Optimization opt = Optimization.InexactGaussNewton(maxIter=5) # statement of the inverse problem invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Directives and Inversion Parameters target = Directives.TargetMisfit() # betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) invProb.beta = 20. inv = Inversion.BaseInversion(invProb, directiveList=[target]) reg.alpha_s = 1e-1 reg.alpha_x = 1. opt.LSshorten = 0.5 opt.remember('xc') reg.mref = mopt_re # Use RESOLVE model as a reference model # run the inversion mopt_sky = inv.run(m0) dpred_sky = invProb.dpred # Plot the figure from the paper plt.figure(figsize=(12, 8)) fs = 13 # fontsize matplotlib.rcParams['font.size'] = fs ax0 = plt.subplot2grid((2, 2), (0, 0), rowspan=2) ax1 = plt.subplot2grid((2, 2), (0, 1)) ax2 = plt.subplot2grid((2, 2), (1, 1)) # Recovered Models sigma_re = np.repeat(np.exp(mopt_re), 2, axis=0) sigma_sky = np.repeat(np.exp(mopt_sky), 2, axis=0) z = np.repeat(mesh.vectorCCz[active][1:], 2, axis=0) z = np.r_[mesh.vectorCCz[active][0], z, mesh.vectorCCz[active][-1]] ax0.semilogx(sigma_re, z, 'k', lw=2, label="RESOLVE") ax0.semilogx(sigma_sky, z, 'b', lw=2, label="SkyTEM") ax0.set_ylim(-50, 0) # ax0.set_xlim(5e-4, 1e2) ax0.grid(True) ax0.set_ylabel("Depth (m)") ax0.set_xlabel("Conducivity (S/m)") ax0.legend(loc=3) ax0.set_title("(a) Recovered Models") # RESOLVE Data ax1.loglog( frequency_cp, dobs_re.reshape((5, 2))[:, 0]/bp*1e6, 'k-', label="Obs (real)" ) ax1.loglog( frequency_cp, dobs_re.reshape((5, 2))[:, 1]/bp*1e6, 'k--', label="Obs (imag)" ) ax1.loglog( frequency_cp, dpred_re.reshape((5, 2))[:, 0]/bp*1e6, 'k+', ms=10, markeredgewidth=2., label="Pred (real)" ) ax1.loglog( frequency_cp, dpred_re.reshape((5, 2))[:, 1]/bp*1e6, 'ko', ms=6, markeredgecolor='k', markeredgewidth=0.5, label="Pred (imag)" ) ax1.set_title("(b) RESOLVE") ax1.set_xlabel("Frequency (Hz)") ax1.set_ylabel("Bz (ppm)") ax1.grid(True) ax1.legend(loc=3, fontsize=11) # SkyTEM data ax2.loglog(times_off[3:]*1e6, dobs_sky/area, 'b-', label="Obs") ax2.loglog( times_off[3:]*1e6, -dpred_sky/area, 'bo', ms=4, markeredgecolor='k', markeredgewidth=0.5, label="Pred" ) ax2.set_xlim(times_off.min()*1e6*1.2, times_off.max()*1e6*1.1) ax2.set_xlabel("Time ($\mu s$)") ax2.set_ylabel("dBz / dt (V/A-m$^4$)") ax2.set_title("(c) SkyTEM High-moment") ax2.grid(True) ax2.legend(loc=3) a3 = plt.axes([0.86, .33, .1, .09], facecolor=[0.8, 0.8, 0.8, 0.6]) a3.plot(prob.times*1e6, wave, 'k-') a3.plot( rx.times*1e6, np.zeros_like(rx.times), 'k|', markeredgewidth=1, markersize=12 ) a3.set_xlim([prob.times.min()*1e6*0.75, prob.times.max()*1e6*1.1]) a3.set_title('(d) Waveform', fontsize=11) a3.set_xticks([prob.times.min()*1e6, t0*1e6, prob.times.max()*1e6]) a3.set_yticks([]) # a3.set_xticklabels(['0', '2e4']) a3.set_xticklabels(['-1e4', '0', '1e4']) plt.tight_layout() if saveFig: plt.savefig("booky1D_time_freq.png", dpi=600) if plotIt: plt.show() resolve.close() skytem.close() if cleanup: print( os.path.split(directory)[:-1]) os.remove( os.path.sep.join( directory.split()[:-1] + ["._bookpurnong_inversion"] ) ) os.remove(downloads) shutil.rmtree(directory)
def plotField(self, Field='B', ComplexNumber="real", view="vec", scale="linear", ifreq=0): fig = plt.figure(figsize=(5, 6)) ax = plt.subplot(111) vec = False if view == "vec": tname = "Vector " title = tname+Field+"-field" elif view == "amp": tname = "|" title = tname+Field+"|-field" else: if ComplexNumber == "real": tname = "Re(" elif ComplexNumber == "imag": tname = "Im(" elif ComplexNumber == "amplitude": tname = "Amp(" elif ComplexNumber == "phase": tname = "Phase(" title = tname + Field + view+")-field" if Field == "B": label = "Magnetic field (T)" if view == "vec": vec = True if ComplexNumber == "real": val = np.c_[self.Bx.real, self.Bz.real] elif ComplexNumber == "imag": val = np.c_[self.Bx.imag, self.Bz.imag] elif view=="x": if ComplexNumber == "real": val = self.Bx.real elif ComplexNumber == "imag": val = self.Bx.imag elif ComplexNumber == "amplitude": val = abs(self.Bx) elif ComplexNumber == "phase": val = np.angle(self.Bx) elif view=="z": if ComplexNumber == "real": val = self.Bz.real elif ComplexNumber == "imag": val = self.Bz.imag elif ComplexNumber == "amplitude": val = abs(self.Bz) elif ComplexNumber == "phase": val = np.angle(self.Bz) else: ax.imshow(self.im) ax.set_xticks([]) ax.set_yticks([]) return "Dude, think twice ... no By for VMD" elif Field == "E": label = "Electric field (V/m)" if view=="y": if ComplexNumber == "real": val = self.Ey.real elif ComplexNumber == "imag": val = self.Ey.imag elif ComplexNumber == "amplitude": val = abs(self.Ey) elif ComplexNumber == "phase": val = np.angle(self.Ey) else: ax.imshow(self.im) ax.set_xticks([]) ax.set_yticks([]) return "Dude, think twice ... only Ey for VMD" elif Field == "J": label = "Current density (A/m$^2$)" if view=="y": if ComplexNumber == "real": val = self.Jy.real elif ComplexNumber == "imag": val = self.Jy.imag elif ComplexNumber == "amplitude": val = abs(self.Jy) elif ComplexNumber == "phase": val = np.angle(self.Jy) out = Utils.plot2Ddata(self.gridCCactive, val, vec=vec, ax=ax, contourOpts={"cmap":"viridis"}, ncontour=50, scale=scale) if scale == "linear": cb = plt.colorbar(out[0], ax=ax, ticks=np.linspace(out[0].vmin, out[0].vmax, 3), format="%.1e") elif scale == "log": cb = plt.colorbar(out[0], ax=ax, ticks=np.linspace(out[0].vmin, out[0].vmax, 3), format="$10^{%.1f}$") else: raise Exception("We consdier only linear and log scale!") cb.set_label(label) xmax = self.gridCCactive[:,0].max() ax.plot(np.r_[0, xmax], np.ones(2)*self.srcLoc[2], 'k-', lw=0.5) ax.plot(np.r_[0, xmax], np.ones(2)*self.z0, 'k--', lw=0.5) ax.plot(np.r_[0, xmax], np.ones(2)*self.z1, 'k--', lw=0.5) ax.plot(np.r_[0, xmax], np.ones(2)*self.z2, 'k--', lw=0.5) ax.plot(0, self.srcLoc[2], 'ko', ms=4) ax.plot(self.rxLoc[0, 0], self.srcLoc[2], 'ro', ms=4) ax.set_xlabel("Distance (m)") ax.set_ylabel("Depth (m)") ax.set_title(title)
def plotPseudoSection( self, data_type="apparent_resistivity", data=None, dataloc=True, aspect_ratio=2, scale="log", cmap="viridis", ncontour=10, ax=None, figname=None, clim=None, label=None, iline=0, ): """ Plot 2D pseudo-section for DC-IP data """ matplotlib.rcParams['font.size'] = 12 if ax is None: fig = plt.figure(figsize=(10, 5)) ax = plt.subplot(111) if self.dimension == 2: inds = np.ones(self.n_data, dtype=bool) grids = self.grids.copy() elif self.dimension == 3: inds = self.line_inds == iline grids = self.grids[inds, :][:, [0, 2]] else: raise NotImplementedError() if data_type == "apparent_resistivity": if data is None: val = self.apparent_resistivity[inds] else: val = data.copy()[inds] label = "Apparent Res. ($\Omega$m)" elif data_type == "volt": if data is None: val = self.voltages[inds] else: val = data.copy()[inds] label = "Voltage (V)" elif data_type == "apparent_conductivity": if data is None: val = self.apparent_conductivity[inds] else: val = data.copy()[inds] label = "Apparent Cond. (S/m)" elif data_type == "apparent_chargeability": if data is not None: val = data.copy()[inds] else: val = self.apparent_chargeability.copy()[inds] * 1e3 label = "Apparent Charg. (mV/V)" elif data_type == "volt_ip": if data is not None: val = data.copy()[inds] else: val = self.voltages_ip.copy()[inds] * 1e3 label = "Secondary voltage. (mV)" else: print(data_type) raise NotImplementedError() if scale == "log": fmt = "10$^{%.1f}$" elif scale == "linear": fmt = "%.1e" else: raise NotImplementedError() out = Utils.plot2Ddata( grids, val, contourOpts={'cmap': cmap}, ax=ax, dataloc=dataloc, scale=scale, ncontour=ncontour, clim=clim ) ax.invert_yaxis() ax.set_xlabel("x (m)") ax.set_yticklabels([]) ax.set_ylabel("n-spacing") cb = plt.colorbar( out[0], fraction=0.01, format=fmt, ax=ax ) cb.set_label(label) cb.set_ticks(out[0].levels) ax.set_aspect(aspect_ratio) plt.tight_layout() if figname is not None: fig.savefig(figname, dpi=200)
def run(plotIt=True, saveIt=False, saveFig=False, cleanup=True): """ Download and plot the Bookpurnong data. Here, we parse the data into a dictionary that can be easily saved and loaded into other worflows (for later on when we are doing the inversion) :param bool plotIt: show the Figures? :param bool saveIt: re-save the parsed data? :param bool saveFig: save the matplotlib figures? :param bool cleanUp: remove the downloaded and saved data? """ downloads, directory = download_and_unzip_data() # data are in a directory inside bookpurnong_inversion data_directory = os.path.sep.join([directory, "bookpurnong_data"]) # Load RESOLVE (2008) header_resolve = "Survey Date Flight fid utctime helicopter_easting helicopter_northing gps_height bird_easting bird_northing bird_gpsheight elevation bird_height bird_roll bird_pitch bird_yaw em[0] em[1] em[2] em[3] em[4] em[5] em[6] em[7] em[8] em[9] em[10] em[11] Line " header_resolve = header_resolve.split() resolve = np.loadtxt( os.path.sep.join([data_directory, "Bookpurnong_Resolve_Exported.XYZ"]), skiprows=8 ) # Omit the cross lines resolve = resolve[(resolve[:, -1] > 30002) & (resolve[:, -1] < 38000), :] dat_header_resolve = "CPI400_F CPQ400_F CPI1800_F CPQ1800_F CXI3300_F CXQ3300_F CPI8200_F CPQ8200_F CPI40k_F CPQ40k_F CPI140k_F CPQ140k_F " dat_header_resolve = dat_header_resolve.split() xyz_resolve = resolve[:, 8:11] data_resolve = resolve[:, 16:-1] line_resolve = np.unique(resolve[:, -1]) # Load SkyTEM (2006) fid = open( os.path.sep.join( [data_directory, "SK655CS_Bookpurnong_ZX_HM_TxInc_newDTM.txt"] ), "rb" ) lines = fid.readlines() fid.close() header_skytem = lines[0].split() info_skytem = [] data_skytem = [] for i, line in enumerate(lines[1:]): if len(line.split()) != 65: info_skytem.append(np.array(line.split()[:16], dtype="O")) data_skytem.append(np.array(line.split()[16:16+24], dtype="float")) else: info_skytem.append(np.array(line.split()[:16], dtype="O")) data_skytem.append(np.array(line.split()[17:17+24], dtype="float")) info_skytem = np.vstack(info_skytem) data_skytem = np.vstack(data_skytem) lines_skytem = info_skytem[:, 1].astype(float) line_skytem = np.unique(lines_skytem) inds = (lines_skytem < 2026) info_skytem = info_skytem[inds, :] data_skytem = data_skytem[inds, :].astype(float) xyz_skytem = info_skytem[:, [13, 12]].astype(float) lines_skytem = info_skytem[:, 1].astype(float) line_skytem = np.unique(lines_skytem) # Load path of Murray River river_path = np.loadtxt(os.path.sep.join([directory, "MurrayRiver.txt"])) # Plot the data nskip = 40 fig = plt.figure(figsize = (12*0.8,6*0.8)) title = ["Resolve In-phase 400 Hz", "SkyTEM High moment 156 $\mu$s"] ax1 = plt.subplot(121) ax2 = plt.subplot(122) axs = [ax1, ax2] out_re = Utils.plot2Ddata(xyz_resolve[::nskip, :2], data_resolve[::nskip, 0], ncontour=100, contourOpts={"cmap":"viridis"}, ax=ax1) vmin, vmax = out_re[0].get_clim() cb_re = plt.colorbar(out_re[0], ticks=np.linspace(vmin, vmax, 3), ax=ax1, fraction=0.046, pad=0.04) temp_skytem = data_skytem[:, 5].copy() temp_skytem[data_skytem[:, 5] > 7e-10] = 7e-10 out_sky = Utils.plot2Ddata(xyz_skytem[:,:2], temp_skytem, ncontour=100, contourOpts={"cmap":"viridis", "vmax":7e-10}, ax=ax2) vmin, vmax = out_sky[0].get_clim() cb_sky = plt.colorbar(out_sky[0], ticks=np.linspace(vmin, vmax, 3), ax=ax2, format="%.1e", fraction=0.046, pad=0.04) cb_re.set_label("Bz (ppm)") cb_sky.set_label("Voltage (V/A-m$^4$)") for i, ax in enumerate(axs): xticks = [460000, 463000] yticks = [6195000, 6198000, 6201000] ax.set_xticks(xticks) ax.set_yticks(yticks) ax.plot(river_path[:, 0], river_path[:, 1], 'k', lw=0.5) ax.set_aspect("equal") if i == 1: ax.plot( xyz_skytem[:, 0], xyz_skytem[:, 1], 'k.', alpha=0.02, ms=1 ) ax.set_yticklabels([str(" ") for f in yticks]) else: ax.plot( xyz_resolve[:, 0], xyz_resolve[:, 1], 'k.', alpha=0.02, ms=1 ) ax.set_yticklabels([str(f) for f in yticks]) ax.set_ylabel("Northing (m)") ax.set_xlabel("Easting (m)") ax.set_title(title[i]) plt.tight_layout() if plotIt: plt.show() if saveFig: fig.savefig("bookpurnong_data.png") cs, ncx, ncz, npad = 1., 10., 10., 20 hx = [(cs, ncx), (cs, npad, 1.3)] npad = 12 temp = np.logspace(np.log10(1.), np.log10(12.), 19) temp_pad = temp[-1] * 1.3 ** np.arange(npad) hz = np.r_[temp_pad[::-1], temp[::-1], temp, temp_pad] mesh = Mesh.CylMesh([hx, 1, hz], '00C') active = mesh.vectorCCz < 0. dobs_re = np.load(os.path.sep.join([directory, "dobs_re_final.npy"])) dpred_re = np.load(os.path.sep.join([directory, "dpred_re_final.npy"])) mopt_re = np.load(os.path.sep.join([directory, "mopt_re_final.npy"])) # Down sample resolve data nskip = 40 inds_resolve = np.r_[np.array(range(0, data_resolve.shape[0]-1, nskip)), 16730] booky_resolve = { "data": data_resolve[inds_resolve, :], "data_header": dat_header_resolve, "line": resolve[:, -1][inds_resolve], "xy": xyz_resolve[:, :2][inds_resolve], "src_elevation": resolve[:, 12][inds_resolve], "ground_elevation": resolve[:, 11][inds_resolve], "dobs": dobs_re, "dpred": dpred_re, "mopt": mopt_re, "z": mesh.vectorCCz[active], "frequency_cp": np.r_[382, 1822, 7970, 35920, 130100], "frequency_cx": np.r_[3258.], "river_path": river_path } area = 314. waveform = np.loadtxt(os.path.sep.join([directory, "skytem_hm.wf"])) times = np.loadtxt(os.path.sep.join([directory, "skytem_hm.tc"])) booky_skytem = { "data": data_skytem, "data_header": header_skytem[17:17+24], "line": lines_skytem, "xy": xyz_skytem, "src_elevation": info_skytem[:, 10].astype(float), "ground_elevation": info_skytem[:, 15].astype(float), "area": area, "radius": np.sqrt(area / np.pi), "t0": 0.01004, "waveform": waveform, "times": times } if saveIt: save_dict_to_hdf5( os.path.sep.join([directory, "booky_resolve.hdf5"]), booky_resolve ) save_dict_to_hdf5( os.path.sep.join([directory, "booky_skytem.hdf5"]), booky_skytem ) if cleanup: os.remove(downloads) shutil.rmtree(directory)
def plotField(self, Field='B', view="vec", scale="linear", itime=0, Geometry=True): fig = plt.figure(figsize=(10, 6)) ax = plt.subplot(111) vec = False if view == "vec": tname = "Vector " title = tname + Field + "-field" elif view == "amp": tname = "|" title = tname + Field + "|-field" else: title = Field + view + "-field" if Field == "B": label = "Magnetic field (T)" if view == "vec": vec = True val = np.c_[self.Bx, self.Bz] elif view == "x": val = self.Bx elif view == "z": val = self.Bz else: # ax.imshow(self.im) ax.set_xticks([]) ax.set_yticks([]) return "Dude, think twice ... no By for VMD" elif Field == "dBdt": label = "Time derivative of magnetic field (T/s)" if view == "vec": vec = True val = np.c_[self.dBxdt, self.dBzdt] elif view == "x": val = self.dBxdt elif view == "z": val = self.dBzdt else: # ax.imshow(self.im) ax.set_xticks([]) ax.set_yticks([]) return "Dude, think twice ... no dBydt for VMD" elif Field == "E": label = "Electric field (V/m)" if view == "y": val = self.Ey else: # ax.imshow(self.im) ax.set_xticks([]) ax.set_yticks([]) return "Dude, think twice ... only Ey for VMD" elif Field == "J": label = "Current density (A/m$^2$)" if view == "y": val = self.Jy else: # ax.imshow(self.im) ax.set_xticks([]) ax.set_yticks([]) return "Dude, think twice ... only Jy for VMD" out = Utils.plot2Ddata(self.mesh2D.gridCC, val, vec=vec, ax=ax, contourOpts={"cmap": "viridis"}, ncontour=50, scale=scale) if scale == "linear": cb = plt.colorbar(out[0], ax=ax, ticks=np.linspace(out[0].vmin, out[0].vmax, 3), format="%.1e") elif scale == "log": cb = plt.colorbar(out[0], ax=ax, ticks=np.linspace(out[0].vmin, out[0].vmax, 3), format="$10^{%.1f}$") else: raise Exception("We consdier only linear and log scale!") cb.set_label(label) xmax = self.mesh2D.gridCC[:, 0].max() if Geometry: ax.plot(np.r_[-xmax, xmax], np.ones(2) * self.srcLoc[2], 'k-', lw=0.5) ax.plot(np.r_[-xmax, xmax], np.ones(2) * self.z0, 'k--', lw=0.5) ax.plot(np.r_[-xmax, xmax], np.ones(2) * self.z1, 'k--', lw=0.5) ax.plot(np.r_[-xmax, xmax], np.ones(2) * self.z2, 'k--', lw=0.5) ax.plot(0, self.srcLoc[2], 'ko', ms=4) ax.plot(self.rxLoc[0, 0], self.srcLoc[2], 'ro', ms=4) ax.set_xlabel("Distance (m)") ax.set_ylabel("Depth (m)") ax.set_title(title) ax.text(-85, 90, ("Time at %.3f ms") % (self.prb.times[itime] * 1e3), fontsize=12) plt.show()
def plotPseudoSection( self, data_type="apparent_resistivity", data=None, dataloc=True, aspect_ratio=2, scale="log", cmap="viridis", ncontour=10, ax=None, figname=None, clim=None, label=None, iline=0, ): """ Plot 2D pseudo-section for DC-IP data """ matplotlib.rcParams['font.size'] = 12 if ax is None: fig = plt.figure(figsize=(10, 5)) ax = plt.subplot(111) if self.dimension == 2: inds = np.ones(self.n_data, dtype=bool) grids = self.grids.copy() elif self.dimension == 3: inds = self.line_inds == iline grids = self.grids[inds, :][:, [0, 2]] else: raise NotImplementedError() if data_type == "apparent_resistivity": if data is None: val = self.apparent_resistivity[inds] else: val = data.copy()[inds] label = "Apparent Res. ($\Omega$m)" elif data_type == "volt": if data is None: val = self.voltages[inds] else: val = data.copy()[inds] label = "Voltage (V)" elif data_type == "apparent_conductivity": if data is None: val = self.apparent_conductivity[inds] else: val = data.copy()[inds] label = "Apparent Cond. (S/m)" elif data_type == "apparent_chargeability": if data is not None: val = data.copy()[inds] else: val = self.apparent_chargeability.copy()[inds] * 1e3 label = "Apparent Charg. (mV/V)" elif data_type == "volt_ip": if data is not None: val = data.copy()[inds] else: val = self.voltages_ip.copy()[inds] * 1e3 label = "Secondary voltage. (mV)" else: print(data_type) raise NotImplementedError() if scale == "log": fmt = "10$^{%.1f}$" elif scale == "linear": fmt = "%.1e" else: raise NotImplementedError() out = Utils.plot2Ddata(grids, val, contourOpts={'cmap': cmap}, ax=ax, dataloc=dataloc, scale=scale, ncontour=ncontour, clim=clim) ax.invert_yaxis() ax.set_xlabel("x (m)") ax.set_yticklabels([]) ax.set_ylabel("n-spacing") cb = plt.colorbar(out[0], fraction=0.01, format=fmt, ax=ax) cb.set_label(label) ax.set_aspect(aspect_ratio) plt.tight_layout() if figname is not None: fig.savefig(figname, dpi=200)
def run(plotIt=True, saveFig=False, cleanup=True): """ Run 1D inversions for a single sounding of the RESOLVE and SkyTEM bookpurnong data :param bool plotIt: show the plots? :param bool saveFig: save the figure :param bool cleanup: remove the downloaded results """ downloads, directory = download_and_unzip_data() resolve = h5py.File(os.path.sep.join([directory, "booky_resolve.hdf5"]), "r") skytem = h5py.File(os.path.sep.join([directory, "booky_skytem.hdf5"]), "r") river_path = resolve["river_path"].value # Choose a sounding location to invert xloc, yloc = 462100.0, 6196500.0 rxind_skytem = np.argmin( abs(skytem["xy"][:, 0] - xloc) + abs(skytem["xy"][:, 1] - yloc)) rxind_resolve = np.argmin( abs(resolve["xy"][:, 0] - xloc) + abs(resolve["xy"][:, 1] - yloc)) # Plot both resolve and skytem data on 2D plane fig = plt.figure(figsize=(13, 6)) title = ["RESOLVE In-phase 400 Hz", "SkyTEM High moment 156 $\mu$s"] ax1 = plt.subplot(121) ax2 = plt.subplot(122) axs = [ax1, ax2] out_re = Utils.plot2Ddata(resolve["xy"], resolve["data"][:, 0], ncontour=100, contourOpts={"cmap": "viridis"}, ax=ax1) vmin, vmax = out_re[0].get_clim() cb_re = plt.colorbar(out_re[0], ticks=np.linspace(vmin, vmax, 3), ax=ax1, fraction=0.046, pad=0.04) temp_skytem = skytem["data"][:, 5].copy() temp_skytem[skytem["data"][:, 5] > 7e-10] = 7e-10 out_sky = Utils.plot2Ddata(skytem["xy"][:, :2], temp_skytem, ncontour=100, contourOpts={ "cmap": "viridis", "vmax": 7e-10 }, ax=ax2) vmin, vmax = out_sky[0].get_clim() cb_sky = plt.colorbar(out_sky[0], ticks=np.linspace(vmin, vmax * 0.99, 3), ax=ax2, format="%.1e", fraction=0.046, pad=0.04) cb_re.set_label("Bz (ppm)") cb_sky.set_label("dB$_z$ / dt (V/A-m$^4$)") for i, ax in enumerate(axs): xticks = [460000, 463000] yticks = [6195000, 6198000, 6201000] ax.set_xticks(xticks) ax.set_yticks(yticks) ax.plot(xloc, yloc, 'wo') ax.plot(river_path[:, 0], river_path[:, 1], 'k', lw=0.5) ax.set_aspect("equal") if i == 1: ax.plot(skytem["xy"][:, 0], skytem["xy"][:, 1], 'k.', alpha=0.02, ms=1) ax.set_yticklabels([str(" ") for f in yticks]) else: ax.plot(resolve["xy"][:, 0], resolve["xy"][:, 1], 'k.', alpha=0.02, ms=1) ax.set_yticklabels([str(f) for f in yticks]) ax.set_ylabel("Northing (m)") ax.set_xlabel("Easting (m)") ax.set_title(title[i]) ax.axis('equal') # plt.tight_layout() if saveFig is True: fig.savefig("resolve_skytem_data.png", dpi=600) # ------------------ Mesh ------------------ # # Step1: Set 2D cylindrical mesh cs, ncx, ncz, npad = 1., 10., 10., 20 hx = [(cs, ncx), (cs, npad, 1.3)] npad = 12 temp = np.logspace(np.log10(1.), np.log10(12.), 19) temp_pad = temp[-1] * 1.3**np.arange(npad) hz = np.r_[temp_pad[::-1], temp[::-1], temp, temp_pad] mesh = Mesh.CylMesh([hx, 1, hz], '00C') active = mesh.vectorCCz < 0. # Step2: Set a SurjectVertical1D mapping # Note: this sets our inversion model as 1D log conductivity # below subsurface active = mesh.vectorCCz < 0. actMap = Maps.InjectActiveCells(mesh, active, np.log(1e-8), nC=mesh.nCz) mapping = Maps.ExpMap(mesh) * Maps.SurjectVertical1D(mesh) * actMap sig_half = 1e-1 sig_air = 1e-8 sigma = np.ones(mesh.nCz) * sig_air sigma[active] = sig_half # Initial and reference model m0 = np.log(sigma[active]) # ------------------ RESOLVE Forward Simulation ------------------ # # Step3: Invert Resolve data # Bird height from the surface b_height_resolve = resolve["src_elevation"].value src_height_resolve = b_height_resolve[rxind_resolve] # Set Rx (In-phase and Quadrature) rxOffset = 7.86 bzr = EM.FDEM.Rx.Point_bSecondary(np.array( [[rxOffset, 0., src_height_resolve]]), orientation='z', component='real') bzi = EM.FDEM.Rx.Point_b(np.array([[rxOffset, 0., src_height_resolve]]), orientation='z', component='imag') # Set Source (In-phase and Quadrature) frequency_cp = resolve["frequency_cp"].value freqs = frequency_cp.copy() srcLoc = np.array([0., 0., src_height_resolve]) srcList = [ EM.FDEM.Src.MagDipole([bzr, bzi], freq, srcLoc, orientation='Z') for freq in freqs ] # Set FDEM survey (In-phase and Quadrature) survey = EM.FDEM.Survey(srcList) prb = EM.FDEM.Problem3D_b(mesh, sigmaMap=mapping, Solver=Solver) prb.pair(survey) # ------------------ RESOLVE Inversion ------------------ # # Primary field bp = -mu_0 / (4 * np.pi * rxOffset**3) # Observed data cpi_inds = [0, 2, 6, 8, 10] cpq_inds = [1, 3, 7, 9, 11] dobs_re = np.c_[resolve["data"][rxind_resolve, :][cpi_inds], resolve["data"][ rxind_resolve, :][cpq_inds]].flatten() * bp * 1e-6 # Uncertainty std = np.repeat(np.r_[np.ones(3) * 0.1, np.ones(2) * 0.15], 2) floor = 20 * abs(bp) * 1e-6 uncert = abs(dobs_re) * std + floor # Data Misfit survey.dobs = dobs_re dmisfit = DataMisfit.l2_DataMisfit(survey) dmisfit.W = 1. / uncert # Regularization regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh, mapping=Maps.IdentityMap(regMesh)) # Optimization opt = Optimization.InexactGaussNewton(maxIter=5) # statement of the inverse problem invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Inversion directives and parameters target = Directives.TargetMisfit() # stop when we hit target misfit invProb.beta = 2. # betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) inv = Inversion.BaseInversion(invProb, directiveList=[target]) reg.alpha_s = 1e-3 reg.alpha_x = 1. reg.mref = m0.copy() opt.LSshorten = 0.5 opt.remember('xc') # run the inversion mopt_re = inv.run(m0) dpred_re = invProb.dpred # ------------------ SkyTEM Forward Simulation ------------------ # # Step4: Invert SkyTEM data # Bird height from the surface b_height_skytem = skytem["src_elevation"].value src_height = b_height_skytem[rxind_skytem] srcLoc = np.array([0., 0., src_height]) # Radius of the source loop area = skytem["area"].value radius = np.sqrt(area / np.pi) rxLoc = np.array([[radius, 0., src_height]]) # Parameters for current waveform t0 = skytem["t0"].value times = skytem["times"].value waveform_skytem = skytem["waveform"].value offTime = t0 times_off = times - t0 # Note: we are Using theoretical VTEM waveform, # but effectively fits SkyTEM waveform peakTime = 1.0000000e-02 a = 3. dbdt_z = EM.TDEM.Rx.Point_dbdt(locs=rxLoc, times=times_off[:-3] + offTime, orientation='z') # vertical db_dt rxList = [dbdt_z] # list of receivers srcList = [ EM.TDEM.Src.CircularLoop(rxList, loc=srcLoc, radius=radius, orientation='z', waveform=EM.TDEM.Src.VTEMWaveform( offTime=offTime, peakTime=peakTime, a=3.)) ] # solve the problem at these times timeSteps = [(peakTime / 5, 5), ((offTime - peakTime) / 5, 5), (1e-5, 5), (5e-5, 5), (1e-4, 10), (5e-4, 15)] prob = EM.TDEM.Problem3D_e(mesh, timeSteps=timeSteps, sigmaMap=mapping, Solver=Solver) survey = EM.TDEM.Survey(srcList) prob.pair(survey) src = srcList[0] rx = src.rxList[0] wave = [] for time in prob.times: wave.append(src.waveform.eval(time)) wave = np.hstack(wave) out = survey.dpred(m0) # plot the waveform fig = plt.figure(figsize=(5, 3)) times_off = times - t0 plt.plot(waveform_skytem[:, 0], waveform_skytem[:, 1], 'k.') plt.plot(prob.times, wave, 'k-', lw=2) plt.legend(("SkyTEM waveform", "Waveform (fit)"), fontsize=10) for t in rx.times: plt.plot(np.ones(2) * t, np.r_[-0.03, 0.03], 'k-') plt.ylim(-0.1, 1.1) plt.grid(True) plt.xlabel("Time (s)") plt.ylabel("Normalized current") if saveFig: fig.savefig("skytem_waveform", dpi=200) # Observed data dobs_sky = skytem["data"][rxind_skytem, :-3] * area # ------------------ SkyTEM Inversion ------------------ # # Uncertainty std = 0.12 floor = 7.5e-12 uncert = abs(dobs_sky) * std + floor # Data Misfit survey.dobs = -dobs_sky dmisfit = DataMisfit.l2_DataMisfit(survey) uncert = 0.12 * abs(dobs_sky) + 7.5e-12 dmisfit.W = Utils.sdiag(1. / uncert) # Regularization regMesh = Mesh.TensorMesh([mesh.hz[mapping.maps[-1].indActive]]) reg = Regularization.Simple(regMesh, mapping=Maps.IdentityMap(regMesh)) # Optimization opt = Optimization.InexactGaussNewton(maxIter=5) # statement of the inverse problem invProb = InvProblem.BaseInvProblem(dmisfit, reg, opt) # Directives and Inversion Parameters target = Directives.TargetMisfit() # betaest = Directives.BetaEstimate_ByEig(beta0_ratio=1e0) invProb.beta = 20. inv = Inversion.BaseInversion(invProb, directiveList=[target]) reg.alpha_s = 1e-1 reg.alpha_x = 1. opt.LSshorten = 0.5 opt.remember('xc') reg.mref = mopt_re # Use RESOLVE model as a reference model # run the inversion mopt_sky = inv.run(m0) dpred_sky = invProb.dpred # Plot the figure from the paper plt.figure(figsize=(12, 8)) fs = 13 # fontsize matplotlib.rcParams['font.size'] = fs ax0 = plt.subplot2grid((2, 2), (0, 0), rowspan=2) ax1 = plt.subplot2grid((2, 2), (0, 1)) ax2 = plt.subplot2grid((2, 2), (1, 1)) # Recovered Models sigma_re = np.repeat(np.exp(mopt_re), 2, axis=0) sigma_sky = np.repeat(np.exp(mopt_sky), 2, axis=0) z = np.repeat(mesh.vectorCCz[active][1:], 2, axis=0) z = np.r_[mesh.vectorCCz[active][0], z, mesh.vectorCCz[active][-1]] ax0.semilogx(sigma_re, z, 'k', lw=2, label="RESOLVE") ax0.semilogx(sigma_sky, z, 'b', lw=2, label="SkyTEM") ax0.set_ylim(-50, 0) # ax0.set_xlim(5e-4, 1e2) ax0.grid(True) ax0.set_ylabel("Depth (m)") ax0.set_xlabel("Conducivity (S/m)") ax0.legend(loc=3) ax0.set_title("(a) Recovered Models") # RESOLVE Data ax1.loglog(frequency_cp, dobs_re.reshape((5, 2))[:, 0] / bp * 1e6, 'k-', label="Obs (real)") ax1.loglog(frequency_cp, dobs_re.reshape((5, 2))[:, 1] / bp * 1e6, 'k--', label="Obs (imag)") ax1.loglog(frequency_cp, dpred_re.reshape((5, 2))[:, 0] / bp * 1e6, 'k+', ms=10, markeredgewidth=2., label="Pred (real)") ax1.loglog(frequency_cp, dpred_re.reshape((5, 2))[:, 1] / bp * 1e6, 'ko', ms=6, markeredgecolor='k', markeredgewidth=0.5, label="Pred (imag)") ax1.set_title("(b) RESOLVE") ax1.set_xlabel("Frequency (Hz)") ax1.set_ylabel("Bz (ppm)") ax1.grid(True) ax1.legend(loc=3, fontsize=11) # SkyTEM data ax2.loglog(times_off[3:] * 1e6, dobs_sky / area, 'b-', label="Obs") ax2.loglog(times_off[3:] * 1e6, -dpred_sky / area, 'bo', ms=4, markeredgecolor='k', markeredgewidth=0.5, label="Pred") ax2.set_xlim(times_off.min() * 1e6 * 1.2, times_off.max() * 1e6 * 1.1) ax2.set_xlabel("Time ($\mu s$)") ax2.set_ylabel("dBz / dt (V/A-m$^4$)") ax2.set_title("(c) SkyTEM High-moment") ax2.grid(True) ax2.legend(loc=3) a3 = plt.axes([0.86, .33, .1, .09], facecolor=[0.8, 0.8, 0.8, 0.6]) a3.plot(prob.times * 1e6, wave, 'k-') a3.plot(rx.times * 1e6, np.zeros_like(rx.times), 'k|', markeredgewidth=1, markersize=12) a3.set_xlim([prob.times.min() * 1e6 * 0.75, prob.times.max() * 1e6 * 1.1]) a3.set_title('(d) Waveform', fontsize=11) a3.set_xticks([prob.times.min() * 1e6, t0 * 1e6, prob.times.max() * 1e6]) a3.set_yticks([]) # a3.set_xticklabels(['0', '2e4']) a3.set_xticklabels(['-1e4', '0', '1e4']) plt.tight_layout() if saveFig: plt.savefig("booky1D_time_freq.png", dpi=600) if plotIt: plt.show() resolve.close() skytem.close() if cleanup: print(os.path.split(directory)[:-1]) os.remove( os.path.sep.join(directory.split()[:-1] + ["._bookpurnong_inversion"])) os.remove(downloads) shutil.rmtree(directory)
def plot_section( self, i_layer=0, i_line=0, line_direction='x', show_layer=False, plot_type="contour", physical_property=None, clim=None, ax=None, cmap='viridis', ncontour=20, scale='log', show_colorbar=True, aspect=1, zlim=None, dx=20., contourOpts={} ): ind_line = self.line == self.unique_line[i_line] if physical_property is not None: physical_property_matrix = physical_property.reshape( (self.hz.size, self.n_sounding), order='F' ) else: physical_property_matrix = self.physical_property_matrix if line_direction.lower() == 'y': x_ind = 1 xlabel = 'Northing (m)' elif line_direction.lower() == 'x': x_ind = 0 xlabel = 'Easting (m)' yz = self.xyz[:, ind_line, :][:,:,[x_ind,2]].reshape( (int(self.hz.size*ind_line.sum()), 2), order='F' ) if ax is None: fig = plt.figure(figsize=(15, 10)) ax = plt.subplot(111) if clim is None: vmin = np.percentile(physical_property_matrix, 5) vmax = np.percentile(physical_property_matrix, 95) else: vmin, vmax = clim if plot_type == "contour": if scale == 'log': contourOpts['vmin'] = np.log10(vmin) contourOpts['vmax'] = np.log10(vmax) norm = LogNorm() else: norm=None contourOpts['cmap'] = cmap im = Utils.plot2Ddata( yz, Utils.mkvc(physical_property_matrix[:, ind_line]), scale='log', ncontour=40, dataloc=False, ax=ax, contourOpts=contourOpts ) ax.fill_between(self.topography[ind_line, 1], self.topography[ind_line, 2], y2=yz[:,1].max(), color='w') out = ax.scatter( yz[:, 0], yz[:, 1], c=Utils.mkvc(physical_property_matrix[:, ind_line]), s=0.1, vmin=vmin, vmax=vmax, cmap=cmap, alpha=1, norm=norm ) elif plot_type == "pcolor": if scale == 'log': norm = LogNorm() else: norm=None ind_line = np.arange(ind_line.size)[ind_line] for i in ind_line: inds_temp = [i, i] topo_temp = np.c_[ self.topography[i, x_ind]-dx, self.topography[i, x_ind]+dx ] out = ax.pcolormesh( topo_temp, -self.mesh_1d.vectorCCx+self.topography[i, 2], physical_property_matrix[:, inds_temp], cmap=cmap, alpha=0.7, vmin=vmin, vmax=vmax, norm=norm ) if show_layer: ax.plot( self.topography[ind_line, x_ind], self.topography[ind_line, 2]-self.mesh_1d.vectorCCx[i_layer], '--', lw=1, color='grey' ) if show_colorbar: from mpl_toolkits import axes_grid1 cb = plt.colorbar(out, ax=ax, fraction=0.01) cb.set_label("Conductivity (S/m)") ax.set_aspect(aspect) ax.set_xlabel(xlabel) ax.set_ylabel('Elevation (m)') if zlim is not None: ax.set_ylim(zlim) plt.tight_layout() if show_colorbar: return out, ax, cb else: return out, ax return ax,
def plot_plan( self, i_layer=0, i_line=0, show_line=False, physical_property=None, clim=None, ax=None, cmap='viridis', ncontour=20, scale='log', show_colorbar=True, aspect=1, contourOpts={} ): ind_line = self.line == self.unique_line[i_line] if physical_property is not None: physical_property_matrix = physical_property.reshape( (self.hz.size, self.n_sounding), order='F' ) else: physical_property_matrix = self.physical_property_matrix if ax is None: fig = plt.figure(figsize=(10, 10)) ax = plt.subplot(111) if clim is None: vmin = np.percentile(physical_property_matrix, 5) vmax = np.percentile(physical_property_matrix, 95) else: vmin, vmax = clim if scale == 'log': contourOpts['vmin'] = np.log10(vmin) contourOpts['vmax'] = np.log10(vmax) norm = LogNorm() else: norm = None contourOpts['cmap'] = cmap im = Utils.plot2Ddata( self.topography[:, :2], Utils.mkvc(physical_property_matrix[i_layer, :]), scale=scale, ncontour=ncontour, ax=ax, contourOpts=contourOpts, dataloc=False, ) out = ax.scatter( self.topography[:, 0], self.topography[:, 1], c=physical_property_matrix[i_layer, :], s=0.5, vmin=vmin, vmax=vmax, cmap=cmap, alpha=1, norm=norm ) if show_line: ax.plot(self.topography[ind_line,0], self.topography[ind_line,1], 'k.') if show_colorbar: from mpl_toolkits import axes_grid1 divider = axes_grid1.make_axes_locatable(ax) cax = divider.append_axes('right', size='5%', pad=0.05) cb = plt.colorbar(out, cax=cax) # cb.set_label("Conductivity (S/m)") ax.set_aspect(aspect) ax.set_title(("At %.1f m below surface")%(self.mesh_1d.vectorCCx[i_layer])) ax.set_xlabel("Easting (m)") ax.set_ylabel("Northing (m)") ax.grid(True) plt.tight_layout() # plt.show() if show_colorbar: return out, ax, cb else: return out, ax