def fields(self, m): if m is not None: self.model = m if self.verbose: print(">> Compute fields") # TODO: this for loop can slow down the speed, cythonize below for loop T1 = self.rho[self.n_layer - 1] * np.ones_like(self.lambd) for ii in range(self.n_layer - 1, 0, -1): rho0 = self.rho[ii - 1] t0 = self.thicknesses[ii - 1] T0 = (T1 + rho0 * np.tanh(self.lambd * t0)) / ( 1.0 + (T1 * np.tanh(self.lambd * t0) / rho0)) T1 = T0 PJ = (T0, None, None) try: voltage = dlf( PJ, self.lambd, self.offset, self.fhtfilt, self.hankel_pts_per_dec, factAng=None, ab=33, ).real / (2 * np.pi) except TypeError: voltage = dlf( PJ, self.lambd, self.offset, self.fhtfilt, self.hankel_pts_per_dec, ang_fact=None, ab=33, ).real / (2 * np.pi) # Assume dipole-dipole V = voltage.reshape((self.survey.nD, 4), order="F") data = V[:, 0] + V[:, 1] - (V[:, 2] + V[:, 3]) if self.data_type == "apparent_resistivity": data /= self.geometric_factor return data
def test_dlf(): # 10. dlf # DLF is integral of hankel_dlf and fourier_dlf, and therefore tested a lot # through those. Here we just ensure status quo. And if a problem arises in # hankel_dlf or fourier_dlf, it would make it obvious if the problem arises # from dlf or not. # Check DLF for Fourier t = DATA['t'][()] for i in [0, 1, 2]: dat = DATA['fourier_dlf' + str(i)][()] tres = DATA['tEM' + str(i)][()] finp = dat['fEM'] ftarg = dat['ftarg'] if i > 0: finp /= 2j * np.pi * dat['f'] if i > 1: finp *= -1 if ftarg['pts_per_dec'] == 0: finp = finp.reshape(t.size, -1) tEM = transform.dlf(finp, 2 * np.pi * dat['f'], t, ftarg['dlf'], ftarg['pts_per_dec'], kind=ftarg['kind']) assert_allclose(tEM * 2 / np.pi, tres, rtol=1e-3) # Check DLF for Hankel for ab in [12, 22, 13, 33]: model = utils.check_model([], 10, 2, 2, 5, 1, 10, True, 0) depth, res, aniso, epermH, epermV, mpermH, mpermV, _ = model frequency = utils.check_frequency(1, res, aniso, epermH, epermV, mpermH, mpermV, 0) _, etaH, etaV, zetaH, zetaV = frequency src = [0, 0, 0] src, nsrc = utils.check_dipole(src, 'src', 0) ab, msrc, mrec = utils.check_ab(ab, 0) ht, htarg = utils.check_hankel('dlf', {}, 0) xdirect = False # Important, as we want to comp. wavenumber-frequency! rec = [np.arange(1, 11) * 500, np.zeros(10), 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) lsrc, zsrc = utils.get_layer_nr(src, depth) lrec, zrec = utils.get_layer_nr(rec, depth) dlf = htarg['dlf'] pts_per_dec = htarg['pts_per_dec'] # # # 0. No Spline # # # # dlf calculation lambd = dlf.base / off[:, None] PJ = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec) # Angle factor, one example with None instead of 1's. if ab != 13: ang_fact = kernel.angle_factor(angle, ab, msrc, mrec) else: ang_fact = None # dlf calculation fEM0 = transform.dlf(PJ, lambd, off, dlf, 0, ang_fact=ang_fact, ab=ab) # Analytical frequency-domain solution freq1 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(np.squeeze(fEM0), np.squeeze(freq1)) # # # 1. Spline; One angle # # # # dlf calculation lambd, _ = transform.get_dlf_points(dlf, off, pts_per_dec) PJ1 = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec) # dlf calculation fEM1 = transform.dlf(PJ1, lambd, off, dlf, pts_per_dec, ang_fact=ang_fact, ab=ab) # Compare assert_allclose(np.squeeze(fEM1), np.squeeze(freq1), rtol=1e-4) # # # 2.a Lagged; One angle # # # rec = [np.arange(1, 11) * 500, np.arange(-5, 5) * 0, 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) # dlf calculation lambd, _ = transform.get_dlf_points(dlf, off, -1) PJ2 = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec) ang_fact = kernel.angle_factor(angle, ab, msrc, mrec) # dlf calculation fEM2 = transform.dlf(PJ2, lambd, off, dlf, -1, ang_fact=ang_fact, ab=ab) # Analytical frequency-domain solution freq2 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(np.squeeze(fEM2), np.squeeze(freq2), rtol=1e-4) # # # 2.b Lagged; Multi angle # # # rec = [np.arange(1, 11) * 500, np.arange(-5, 5) * 200, 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) # dlf calculation lambd, _ = transform.get_dlf_points(dlf, off, -1) PJ2 = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec) ang_fact = kernel.angle_factor(angle, ab, msrc, mrec) # dlf calculation fEM2 = transform.dlf(PJ2, lambd, off, dlf, -1, ang_fact=ang_fact, ab=ab) # Analytical frequency-domain solution freq2 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(np.squeeze(fEM2), np.squeeze(freq2), rtol=1e-4) # # # 3. Spline; Multi angle # # # lambd, _ = transform.get_dlf_points(dlf, off, 30) # dlf calculation PJ3 = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec) # dlf calculation fEM3 = transform.dlf(PJ3, lambd, off, dlf, 30, ang_fact=ang_fact, ab=ab) # Compare assert_allclose(np.squeeze(fEM3), np.squeeze(freq2), rtol=1e-3)
def test_dlf(): # 10. dlf # DLF is integral of fht and ffht, and therefore tested a lot through # those. Here we just ensure status quo. And if a problem arises in fht or # ffht, it would make it obvious if the problem arises from dlf or not. # Check DLF for Fourier t = DATA['t'][()] for i in [0, 1, 2]: dat = DATA['ffht' + str(i)][()] tres = DATA['tEM' + str(i)][()] finp = dat['fEM'] ftarg = dat['ftarg'] if i > 0: finp /= 2j * np.pi * dat['f'] if i > 1: finp *= -1 if ftarg[1] == 0: finp = finp.reshape(t.size, -1) tEM = transform.dlf(finp, 2 * np.pi * dat['f'], t, ftarg[0], ftarg[1], kind=ftarg[2]) assert_allclose(tEM * 2 / np.pi, tres, rtol=1e-3) # Check DLF for Hankel for ab in [12, 22, 13, 33]: model = utils.check_model([], 10, 2, 2, 5, 1, 10, True, 0) depth, res, aniso, epermH, epermV, mpermH, mpermV, isfullspace = model frequency = utils.check_frequency(1, res, aniso, epermH, epermV, mpermH, mpermV, 0) freq, etaH, etaV, zetaH, zetaV = frequency src = [0, 0, 0] src, nsrc = utils.check_dipole(src, 'src', 0) ab, msrc, mrec = utils.check_ab(ab, 0) ht, htarg = utils.check_hankel('fht', None, 0) options = utils.check_opt(None, None, ht, htarg, 0) use_ne_eval, loop_freq, loop_off = options xdirect = False # Important, as we want to comp. wavenumber-frequency! rec = [np.arange(1, 11) * 500, np.zeros(10), 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) lsrc, zsrc = utils.get_layer_nr(src, depth) lrec, zrec = utils.get_layer_nr(rec, depth) fhtfilt = htarg[0] pts_per_dec = htarg[1] # # # 0. No Spline # # # # fht calculation lambd = fhtfilt.base / off[:, None] PJ = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec, use_ne_eval) factAng = kernel.angle_factor(angle, ab, msrc, mrec) # dlf calculation fEM0 = transform.dlf(PJ, lambd, off, fhtfilt, 0, factAng=factAng, ab=ab) # Analytical frequency-domain solution freq1 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(np.squeeze(fEM0), np.squeeze(freq1)) # # # 1. Spline; One angle # # # options = utils.check_opt('spline', None, ht, htarg, 0) use_ne_eval, loop_freq, loop_off = options # fht calculation lambd, _ = transform.get_spline_values(fhtfilt, off, pts_per_dec) PJ1 = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec, use_ne_eval) # dlf calculation fEM1 = transform.dlf(PJ1, lambd, off, fhtfilt, pts_per_dec, factAng=factAng, ab=ab) # Compare assert_allclose(np.squeeze(fEM1), np.squeeze(freq1), rtol=1e-4) # # # 2.a Lagged; One angle # # # rec = [np.arange(1, 11) * 500, np.arange(-5, 5) * 0, 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) # fht calculation lambd, _ = transform.get_spline_values(fhtfilt, off, -1) PJ2 = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec, use_ne_eval) factAng = kernel.angle_factor(angle, ab, msrc, mrec) # dlf calculation fEM2 = transform.dlf(PJ2, lambd, off, fhtfilt, -1, factAng=factAng, ab=ab) # Analytical frequency-domain solution freq2 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(np.squeeze(fEM2), np.squeeze(freq2), rtol=1e-4) # # # 2.b Lagged; Multi angle # # # rec = [np.arange(1, 11) * 500, np.arange(-5, 5) * 200, 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) # fht calculation lambd, _ = transform.get_spline_values(fhtfilt, off, -1) PJ2 = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec, use_ne_eval) factAng = kernel.angle_factor(angle, ab, msrc, mrec) # dlf calculation fEM2 = transform.dlf(PJ2, lambd, off, fhtfilt, -1, factAng=factAng, ab=ab) # Analytical frequency-domain solution freq2 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(np.squeeze(fEM2), np.squeeze(freq2), rtol=1e-4) # # # 3. Spline; Multi angle # # # lambd, _ = transform.get_spline_values(fhtfilt, off, 10) # fht calculation PJ3 = kernel.wavenumber(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec, use_ne_eval) # dlf calculation fEM3 = transform.dlf(PJ3, lambd, off, fhtfilt, 10, factAng=factAng, ab=ab) # Compare assert_allclose(np.squeeze(fEM3), np.squeeze(freq2), rtol=1e-3)
def forward(self, m, output_type='response'): """ Return Bz or dBzdt """ self.model = m n_frequency = self.survey.n_frequency flag = self.survey.field_type n_layer = self.survey.n_layer depth = self.survey.depth I = self.survey.I n_filter = self.n_filter # Get lambd and offset, will depend on pts_per_dec if self.survey.src_type == "VMD": r = self.survey.offset else: # a is the radius of the loop r = self.survey.a * np.ones(n_frequency) # Use function from empymod # size of lambd is (n_frequency x n_filter) lambd = np.empty([self.survey.frequency.size, n_filter], order='F') lambd[:, :], _ = get_spline_values(self.fhtfilt, r, self.hankel_pts_per_dec) # lambd, _ = get_spline_values(self.fhtfilt, r, self.hankel_pts_per_dec) # TODO: potentially store f = np.empty([self.survey.frequency.size, n_filter], order='F') f[:,:] = np.tile(self.survey.frequency.reshape([-1, 1]), (1, n_filter)) # h is an inversion parameter if self.hMap is not None: h = self.h else: h = self.survey.h z = h + self.survey.dz chi = self.chi if np.isscalar(self.chi): chi = np.ones_like(self.sigma) * self.chi # TODO: potentially store sig = self.sigma_cole() if output_type == 'response': # for simulation if self.survey.src_type == 'VMD': hz = self.hz_kernel_vertical_magnetic_dipole( lambd, f, n_layer, sig, chi, depth, h, z, flag, output_type=output_type ) # kernels for each bessel function # (j0, j1, j2) PJ = (hz, None, None) # PJ0 elif self.survey.src_type == 'CircularLoop': hz = self.hz_kernel_circular_loop( lambd, f, n_layer, sig, chi, depth, h, z, I, r, flag, output_type=output_type ) # kernels for each bessel function # (j0, j1, j2) PJ = (None, hz, None) # PJ1 # TODO: This has not implemented yet! elif self.survey.src_type == "piecewise_line": # Need to compute y hz = self.hz_kernel_horizontal_electric_dipole( lambd, f, n_layer, sig, chi, depth, h, z, I, r, flag, output_type=output_type ) # kernels for each bessel function # (j0, j1, j2) PJ = (None, hz, None) # PJ1 else: raise Exception("Src options are only VMD or CircularLoop!!") elif output_type == 'sensitivity_sigma': # for simulation if self.survey.src_type == 'VMD': hz = self.hz_kernel_vertical_magnetic_dipole( lambd, f, n_layer, sig, chi, depth, h, z, flag, output_type=output_type ) PJ = (hz, None, None) # PJ0 elif self.survey.src_type == 'CircularLoop': hz = self.hz_kernel_circular_loop( lambd, f, n_layer, sig, chi, depth, h, z, I, r, flag, output_type=output_type ) PJ = (None, hz, None) # PJ1 else: raise Exception("Src options are only VMD or CircularLoop!!") r = np.tile(r, (n_layer, 1)) elif output_type == 'sensitivity_height': # for simulation if self.survey.src_type == 'VMD': hz = self.hz_kernel_vertical_magnetic_dipole( lambd, f, n_layer, sig, chi, depth, h, z, flag, output_type=output_type ) PJ = (hz, None, None) # PJ0 elif self.survey.src_type == 'CircularLoop': hz = self.hz_kernel_circular_loop( lambd, f, n_layer, sig, chi, depth, h, z, I, r, flag, output_type=output_type ) PJ = (None, hz, None) # PJ1 else: raise Exception("Src options are only VMD or CircularLoop!!") # Carry out Hankel DLF # ab=66 => 33 (vertical magnetic src and rec) # For response # HzFHT size = (n_frequency,) # For sensitivity # HzFHT size = (n_layer, n_frequency) HzFHT = dlf(PJ, lambd, r, self.fhtfilt, self.hankel_pts_per_dec, factAng=None, ab=33) if output_type == "sensitivity_sigma": return HzFHT.T return HzFHT
def forward(self, m, output_type='response'): """ Return Bz or dBzdt """ self.model = m n_frequency = self.survey.n_frequency flag = self.survey.field_type n_layer = self.survey.n_layer depth = self.survey.depth I = self.survey.I n_filter = self.n_filter # Get lambd and offset, will depend on pts_per_dec if self.survey.src_type == "VMD": r = self.survey.offset else: # a is the radius of the loop r = self.survey.a * np.ones(n_frequency) # Use function from empymod # size of lambd is (n_frequency x n_filter) lambd = np.empty([self.survey.frequency.size, n_filter], order='F') lambd[:, :], _ = get_spline_values( self.fhtfilt, r, self.hankel_pts_per_dec ) # TODO: potentially store f = np.empty([self.survey.frequency.size, n_filter], order='F') f[:, :] = np.tile( self.survey.frequency.reshape([-1, 1]), (1, n_filter) ) # h is an inversion parameter if self.hMap is not None: h = self.h else: h = self.survey.h z = h + self.survey.dz chi = self.chi if np.isscalar(self.chi): chi = np.ones_like(self.sigma) * self.chi # TODO: potentially store sig = self.sigma_cole() if output_type == 'response': # for simulation if self.survey.src_type == 'VMD': hz = self.hz_kernel_vertical_magnetic_dipole( lambd, f, n_layer, sig, chi, depth, h, z, flag, output_type=output_type ) # kernels for each bessel function # (j0, j1, j2) PJ = (hz, None, None) # PJ0 elif self.survey.src_type == 'CircularLoop': hz = self.hz_kernel_circular_loop( lambd, f, n_layer, sig, chi, depth, h, z, I, r, flag, output_type=output_type ) # kernels for each bessel function # (j0, j1, j2) PJ = (None, hz, None) # PJ1 # TODO: This has not implemented yet! elif self.survey.src_type == "piecewise_line": # Need to compute y hz = self.hz_kernel_horizontal_electric_dipole( lambd, f, n_layer, sig, chi, depth, h, z, I, r, flag, output_type=output_type ) # kernels for each bessel function # (j0, j1, j2) PJ = (None, hz, None) # PJ1 else: raise Exception("Src options are only VMD or CircularLoop!!") elif output_type == 'sensitivity_sigma': # for simulation if self.survey.src_type == 'VMD': hz = self.hz_kernel_vertical_magnetic_dipole( lambd, f, n_layer, sig, chi, depth, h, z, flag, output_type=output_type ) PJ = (hz, None, None) # PJ0 elif self.survey.src_type == 'CircularLoop': hz = self.hz_kernel_circular_loop( lambd, f, n_layer, sig, chi, depth, h, z, I, r, flag, output_type=output_type ) PJ = (None, hz, None) # PJ1 else: raise Exception("Src options are only VMD or CircularLoop!!") r = np.tile(r, (n_layer, 1)) elif output_type == 'sensitivity_height': # for simulation if self.survey.src_type == 'VMD': hz = self.hz_kernel_vertical_magnetic_dipole( lambd, f, n_layer, sig, chi, depth, h, z, flag, output_type=output_type ) PJ = (hz, None, None) # PJ0 elif self.survey.src_type == 'CircularLoop': hz = self.hz_kernel_circular_loop( lambd, f, n_layer, sig, chi, depth, h, z, I, r, flag, output_type=output_type ) PJ = (None, hz, None) # PJ1 else: raise Exception("Src options are only VMD or CircularLoop!!") # Carry out Hankel DLF # ab=66 => 33 (vertical magnetic src and rec) # For response # HzFHT size = (n_frequency,) # For sensitivity # HzFHT size = (n_layer, n_frequency) HzFHT = dlf(PJ, lambd, r, self.fhtfilt, self.hankel_pts_per_dec, factAng=None, ab=33) if output_type == "sensitivity_sigma": return HzFHT.T return HzFHT
def time_dlf(self, data, size, htype): transform.dlf(**data[size][htype])
def setup_cache(self): """setup_cache is not parametrized, so we do it manually. """ data = {} for size in self.params[0]: # size data[size] = {} # One big, one small model if size == 'Small': # Small; Total size: 5*1*1*1 = 5 x = np.array([500., 1000.]) else: # Big; Total size: 5*100*100*201 = 10'050'000 x = np.arange(1, 101)*200. # Define model parameters freq = np.array([1]) src = [0, 0, 250] rec = [x, np.zeros(x.shape), 300] depth = np.array([-np.infty, 0, 300, 2000, 2100]) res = np.array([2e14, .3, 1, 50, 1]) ab = 11 xdirect = False verb = 0 if not VERSION2: use_ne_eval = False # Checks (since DLF exists the `utils`-checks haven't changed, so # we just use them here. model = utils.check_model(depth, res, None, None, None, None, None, xdirect, verb) depth, res, aniso, epermH, epermV, mpermH, mpermV, _ = model frequency = utils.check_frequency(freq, res, aniso, epermH, epermV, mpermH, mpermV, verb) freq, etaH, etaV, zetaH, zetaV = frequency ab, msrc, mrec = utils.check_ab(ab, verb) src, nsrc = utils.check_dipole(src, 'src', verb) rec, nrec = utils.check_dipole(rec, 'rec', verb) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, verb) lsrc, zsrc = utils.get_layer_nr(src, depth) lrec, zrec = utils.get_layer_nr(rec, depth) for htype in self.params[1]: # htype # pts_per_dec depending on htype if htype == 'Standard': pts_per_dec = 0 elif htype == 'Lagged': pts_per_dec = -1 else: pts_per_dec = 10 # Compute kernels for dlf if VERSION2: # HT arguments _, fhtarg = utils.check_hankel( 'dlf', {'dlf': 'key_201_2009', 'pts_per_dec': pts_per_dec}, 0) inp = (fhtarg['dlf'], off, fhtarg['pts_per_dec']) lambd, _ = transform.get_dlf_points(*inp) else: # HT arguments _, fhtarg = utils.check_hankel( 'fht', ['key_201_2009', pts_per_dec], 0) inp = (fhtarg[0], off, fhtarg[1]) lambd, _ = transform.get_spline_values(*inp) if VERSION2: inp = (zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec) else: inp = (zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd, ab, xdirect, msrc, mrec, use_ne_eval) PJ = kernel.wavenumber(*inp) factAng = kernel.angle_factor(angle, ab, msrc, mrec) # Signature changed at commit a15af07 (20/05/2018; before # v1.6.2) try: dlf = {'signal': PJ, 'points': lambd, 'out_pts': off, 'ab': ab} if VERSION2: dlf['ang_fact'] = factAng dlf['filt'] = fhtarg['dlf'] dlf['pts_per_dec'] = fhtarg['pts_per_dec'] else: dlf['factAng'] = factAng dlf['filt'] = fhtarg[0] dlf['pts_per_dec'] = fhtarg[1] transform.dlf(**dlf) except VariableCatch: dlf = {'signal': PJ, 'points': lambd, 'out_pts': off, 'targ': fhtarg, 'factAng': factAng} data[size][htype] = dlf return data