def test_get_layer_nr(): bip = np.array([0, 0, 300]) lbip, zbip = utils.get_layer_nr(bip, np.array([-np.infty, 500])) assert lbip == 0 assert zbip == 300 lbip, _ = utils.get_layer_nr(bip, np.array([-np.infty, 0, 300, 500])) assert lbip == 1 lbip, _ = utils.get_layer_nr(bip, np.array([-np.infty, 0, 200])) assert lbip == 2 bip = np.array([np.zeros(4), np.zeros(4), np.arange(4) * 100]) lbip, _ = utils.get_layer_nr(bip, np.array([-np.infty, 0, 200])) assert_allclose(lbip, [0, 1, 1, 2])
def dipole(src, rec, depth, res, freqtime, aniso=None, eperm=None, mperm=None, verb=2): r"""Return the electromagnetic field due to a dipole source. This is a modified version of :func:`empymod.model.dipole`. It returns the separated contributions of TM--, TM-+, TM+-, TM++, TMdirect, TE--, TE-+, TE+-, TE++, and TEdirect. Parameters ---------- src, rec : list of floats or arrays Source and receiver coordinates (m): [x, y, z]. The x- and y-coordinates can be arrays, z is a single value. The x- and y-coordinates must have the same dimension. Sources or receivers placed on a layer interface are considered in the upper layer. Sources and receivers must be in the same layer. depth : list Absolute layer interfaces z (m); #depth = #res - 1 (excluding +/- infinity). res : array_like Horizontal resistivities rho_h (Ohm.m); #res = #depth + 1. freqtime : float Frequency f (Hz). (The name `freqtime` is kept for consistency with :func:`empymod.model.dipole`. Only one frequency at once. aniso : array_like, optional Anisotropies lambda = sqrt(rho_v/rho_h) (-); #aniso = #res. Defaults to ones. eperm : array_like, optional Relative electric permittivities epsilon (-); #eperm = #res. Default is ones. mperm : array_like, optional Relative magnetic permeabilities mu (-); #mperm = #res. Default is ones. verb : {0, 1, 2, 3, 4}, optional Level of verbosity, default is 2: - 0: Print nothing. - 1: Print warnings. - 2: Print additional runtime and kernel calls - 3: Print additional start/stop, condensed parameter information. - 4: Print additional full parameter information Returns ------- TM, TE : list of ndarrays, (nfreq, nrec, nsrc) Frequency-domain EM field [V/m], separated into TM = [TM--, TM-+, TM+-, TM++, TMdirect] and TE = [TE--, TE-+, TE+-, TE++, TEdirect]. However, source and receiver are normalised. So the source strength is 1 A and its length is 1 m. Therefore the electric field could also be written as [V/(A.m2)]. The shape of EM is (nfreq, nrec, nsrc). However, single dimensions are removed. """ # === 1. LET'S START ============ t0 = printstartfinish(verb) # === 2. CHECK INPUT ============ # Check layer parameters model = check_model(depth, res, aniso, eperm, eperm, mperm, mperm, False, verb) depth, res, aniso, epermH, epermV, mpermH, mpermV, _ = model # Check frequency => get etaH, etaV, zetaH, and zetaV frequency = check_frequency(freqtime, res, aniso, epermH, epermV, mpermH, mpermV, verb) freq, etaH, etaV, zetaH, zetaV = frequency # Check src and rec src, nsrc = check_dipole(src, 'src', verb) rec, nrec = check_dipole(rec, 'rec', verb) # Get offsets off, ang = get_off_ang(src, rec, nsrc, nrec, verb) # Get layer number in which src and rec reside (lsrc/lrec) lsrc, zsrc = get_layer_nr(src, depth) lrec, zrec = get_layer_nr(rec, depth) # Check limitations of this routine compared to the standard `dipole` if lsrc != lrec: # src and rec in same layer raise ValueError("src and rec must be in the same layer; " f"<lsrc>/<lrec> provided: {lsrc}/{lrec}.") if depth.size < 2: # at least two layers raise ValueError("model must have more than one layer; " f"<depth> provided: {_strvar(depth[1:])}.") if freq.size > 1: # only 1 frequency raise ValueError("only one frequency permitted; " f"<freqtime> provided: {_strvar(freqtime)}.") # === 3. EM-FIELD CALCULATION ============ # This part is a simplification of: # - model.fem() # - transform.dlf() # - kernel.wavenumber() # DLF filter we use filt = key_201_2012() # 3.1. COMPUTE REQUIRED LAMBDAS for given hankel-filter-base lambd = filt.base / off[:, None] # 3.2. CALL THE KERNEL PTM, PTE = greenfct(zsrc, zrec, lsrc, lrec, depth, etaH, etaV, zetaH, zetaV, lambd) # 3.3. CARRY OUT THE HANKEL TRANSFORM WITH DLF ang_fact = angle_factor(ang, 11, False, False) zm_ang_fact = (ang_fact[:, np.newaxis] - 1) / 2 zp_ang_fact = (ang_fact[:, np.newaxis] + 1) / 2 fact = 4 * np.pi * off # TE [uu, ud, du, dd, df] for i, val in enumerate(PTE): PTE[i] = (ang_fact * np.dot(-val, filt.j1) / off + np.dot(zm_ang_fact * val * lambd, filt.j0)) / fact # TM [uu, ud, du, dd, df] for i, val in enumerate(PTM): PTM[i] = (ang_fact * np.dot(-val, filt.j1) / off + np.dot(zp_ang_fact * val * lambd, filt.j0)) / fact # 3.4. Remove non-physical contributions # (Note: The T*dd corrections differ slightly from the equations given in # the accompanying pdf, due to the way the direct field is accounted for # in the book.) # General parameters Gam = np.sqrt((zetaH * etaH)[:, None, :, None]) # Gam for lambd=0 iGam = Gam[:, :, lsrc, 0] lgam = np.sqrt(zetaH[:, lsrc] * etaH[:, lsrc]) ddepth = np.r_[depth, np.inf] ds = ddepth[lsrc + 1] - ddepth[lsrc] def get_rp_rm(z_eta): r"""Return Rp, Rm.""" # Get Rp/Rm for lambd=0 Rp, Rm = reflections(depth, z_eta, Gam, lrec, lsrc) # Depending on model Rp/Rm have 3 or 4 dimensions. Last two are # wavenumbers and layers btw src and rec, which both are 1. if Rp.ndim == 4: Rp = np.squeeze(Rp, axis=3) if Rm.ndim == 4: Rm = np.squeeze(Rm, axis=3) Rp = np.squeeze(Rp, axis=2) Rm = np.squeeze(Rm, axis=2) # Calculate reverberation M and general factor npfct Ms = 1 - Rp * Rm * np.exp(-2 * iGam * ds) npfct = ang_fact * zetaH[:, lsrc] / (fact * off * lgam * Ms) return Rp, Rm, npfct # TE modes TE[uu, ud, du, dd] Rp, Rm, npfct = get_rp_rm(zetaH) PTE[0] += npfct * Rp * Rm * np.exp(-lgam * (2 * ds - zrec + zsrc)) PTE[1] += npfct * Rp * np.exp(-lgam * (2 * ddepth[lrec + 1] - zrec - zsrc)) PTE[2] += npfct * Rm * np.exp(-lgam * (zrec + zsrc)) PTE[3] += npfct * Rp * Rm * np.exp(-lgam * (2 * ds + zrec - zsrc)) # TM modes TM[uu, ud, du, dd] Rp, Rm, npfct = get_rp_rm(etaH) PTM[0] -= npfct * Rp * Rm * np.exp(-lgam * (2 * ds - zrec + zsrc)) PTM[1] += npfct * Rp * np.exp(-lgam * (2 * ddepth[lrec + 1] - zrec - zsrc)) PTM[2] += npfct * Rm * np.exp(-lgam * (zrec + zsrc)) PTM[3] -= npfct * Rp * Rm * np.exp(-lgam * (2 * ds + zrec - zsrc)) # 3.5 Reshape for number of sources for i, val in enumerate(PTE): PTE[i] = np.squeeze(val.reshape((-1, nrec, nsrc), order='F')) for i, val in enumerate(PTM): PTM[i] = np.squeeze(val.reshape((-1, nrec, nsrc), order='F')) # === 4. FINISHED ============ printstartfinish(verb, t0) # return [TMuu, TMud, TMdu, TMdd, TMdf], [TEuu, TEud, TEdu, TEdd, TEdf] return PTM, PTE
fqwe0['intervals'] = intervals # # G -- QWE - HQWE # # # Model 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, nsrc = utils.check_dipole([0, 0, 0], 'src', 0) ab, msrc, mrec = utils.check_ab(11, 0) ht, htarg = utils.check_hankel('qwe', None, 0) 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) # Frequency-domain result freqres = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # The following is a condensed version of transform.hqwe etaH = etaH[0, :] etaV = etaV[0, :] zetaH = zetaH[0, :] zetaV = zetaV[0, :] rtol, atol, nquad, maxint, pts_per_dec, diff_quad, a, b, limit = htarg g_x, g_w = special.p_roots(nquad) b_zero = np.pi * np.arange(1.25, maxint + 1) for i in range(10): b_x0 = special.j1(b_zero) b_x1 = special.jv(2, b_zero)
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_hankel(htype): # 1. DLF / 2. QWE / 3. QUAD # Compare wavenumber-domain calculation / DLF with analytical # frequency-domain fullspace solution calc = getattr(transform, 'hankel_' + htype) 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) for ab_inp in [11, 12, 13, 33]: ab, msrc, mrec = utils.check_ab(ab_inp, 0) _, htarg = utils.check_hankel(htype, {}, 0) xdirect = False # Important, as we want to compare wavenr-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) ang_fact = kernel.angle_factor(angle, ab, msrc, mrec) lsrc, zsrc = utils.get_layer_nr(src, depth) lrec, zrec = utils.get_layer_nr(rec, depth) # # # 0. No Spline # # # if htype != 'quad': # quad is always using spline # Wavenumber solution plus transform # Adjust htarg for dlf if htype == 'dlf': lambd, int_pts = transform.get_dlf_points( htarg['dlf'], off, htarg['pts_per_dec']) htarg['lambd'] = lambd htarg['int_pts'] = int_pts wvnr0, _, conv = calc(zsrc, zrec, lsrc, lrec, off, ang_fact, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, msrc, mrec) # Analytical frequency-domain solution freq0 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr0), np.squeeze(freq0)) # # # 1. Spline; One angle # # # _, htarg = utils.check_hankel(htype, {'pts_per_dec': 80}, 0) if htype == 'quad': # Lower atol to ensure convergence _, htarg = utils.check_hankel('quad', {'rtol': 1e-8}, 0) elif htype == 'dlf': # Adjust htarg for dlf lambd, int_pts = transform.get_dlf_points(htarg['dlf'], off, htarg['pts_per_dec']) htarg['lambd'] = lambd htarg['int_pts'] = int_pts # Wavenumber solution plus transform wvnr1, _, conv = calc(zsrc, zrec, lsrc, lrec, off, ang_fact, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, msrc, mrec) # Analytical frequency-domain solution freq1 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare if htype == 'qwe' and ab in [13, 33]: assert_allclose(conv, False) else: assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr1), np.squeeze(freq1), rtol=1e-4) # # # 2. Spline; 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) ang_fact = kernel.angle_factor(angle, ab, msrc, mrec) if htype == 'qwe': # Put a very low diff_quad, to test it.; lower err _, htarg = utils.check_hankel( 'qwe', { 'rtol': 1e-8, 'maxint': 200, 'pts_per_dec': 80, 'diff_quad': .1, 'a': 1e-6, 'b': .1, 'limit': 1000 }, 0) elif htype == 'dlf': # Adjust htarg for dlf lambd, int_pts = transform.get_dlf_points(htarg['dlf'], off, htarg['pts_per_dec']) htarg['lambd'] = lambd htarg['int_pts'] = int_pts # Analytical frequency-domain solution wvnr2, _, conv = calc(zsrc, zrec, lsrc, lrec, off, ang_fact, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, msrc, mrec) # Analytical frequency-domain solution freq2 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr2), np.squeeze(freq2), rtol=1e-4) # # # 3. Spline; pts_per_dec # # # if htype == 'dlf': _, htarg = utils.check_hankel('dlf', { 'dlf': 'key_201_2012', 'pts_per_dec': 20 }, 0) lambd, int_pts = transform.get_dlf_points(htarg['dlf'], off, htarg['pts_per_dec']) htarg['lambd'] = lambd htarg['int_pts'] = int_pts elif htype == 'qwe': _, htarg = utils.check_hankel('qwe', { 'maxint': 80, 'pts_per_dec': 100 }, 0) if htype != 'quad': # quad is always pts_per_dec # Analytical frequency-domain solution wvnr3, _, conv = calc(zsrc, zrec, lsrc, lrec, off, ang_fact, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, msrc, mrec) # Analytical frequency-domain solution freq3 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr3), np.squeeze(freq3), rtol=1e-4) # # # 4. Spline; Only one offset # # # rec = [5000, 0, 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) ang_fact = kernel.angle_factor(angle, ab, msrc, mrec) if htype == 'qwe': _, htarg = utils.check_hankel('qwe', { 'maxint': 200, 'pts_per_dec': 80 }, 0) elif htype == 'quad': _, htarg = utils.check_hankel('quad', {}, 0) elif htype == 'dlf': lambd, int_pts = transform.get_dlf_points(htarg['dlf'], off, htarg['pts_per_dec']) htarg['lambd'] = lambd htarg['int_pts'] = int_pts # Analytical frequency-domain solution wvnr4, _, conv = calc(zsrc, zrec, lsrc, lrec, off, ang_fact, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, msrc, mrec) # Analytical frequency-domain solution freq4 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr4), np.squeeze(freq4), rtol=1e-4)
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 test_hankel(htype): # 1. fht / 2. hqwe / 3. hquad # Compare wavenumber-domain calculation / FHT with analytical # frequency-domain fullspace solution calc = getattr(transform, htype) 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(11, 0) ht, htarg = utils.check_hankel(htype, None, 0) options = utils.check_opt(None, None, htype, htarg, 0) use_ne_eval, loop_freq, loop_off = options xdirect = False # Important, as we want to compare 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) # # # 0. No Spline # # # if htype != 'hquad': # hquad is always using spline # Wavenumber solution plus transform wvnr0, _, conv = calc(zsrc, zrec, lsrc, lrec, off, angle, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq0 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr0), np.squeeze(freq0)) # # # 1. Spline; One angle # # # htarg, opt = utils.spline_backwards_hankel(htype, None, 'spline') ht, htarg = utils.check_hankel(htype, htarg, 0) options = utils.check_opt(None, None, htype, htarg, 0) use_ne_eval, loop_freq, loop_off = options if htype == 'hquad': # Lower atol to ensure convergence ht, htarg = utils.check_hankel('quad', [1e-8], 0) # Wavenumber solution plus transform wvnr1, _, conv = calc(zsrc, zrec, lsrc, lrec, off, angle, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq1 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr1), np.squeeze(freq1), rtol=1e-4) # # # 2. Spline; 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) if htype == 'hqwe': # Put a very low diff_quad, to test it.; lower err ht, htarg = utils.check_hankel( 'qwe', [1e-8, '', '', 200, 80, .1, 1e-6, .1, 1000], 0) # Analytical frequency-domain solution wvnr2, _, conv = calc(zsrc, zrec, lsrc, lrec, off, angle, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq2 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr2), np.squeeze(freq2), rtol=1e-4) # # # 3. Spline; pts_per_dec # # # if htype == 'fht': ht, htarg = utils.check_hankel('fht', ['key_201_2012', 20], 0) elif htype == 'hqwe': ht, htarg = utils.check_hankel('qwe', ['', '', '', 80, 100], 0) if htype != 'hquad': # hquad is always pts_per_dec # Analytical frequency-domain solution wvnr3, _, conv = calc(zsrc, zrec, lsrc, lrec, off, angle, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq3 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr3), np.squeeze(freq3), rtol=1e-4) # # # 4. Spline; Only one offset # # # rec = [5000, 0, 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) if htype == 'hqwe': ht, htarg = utils.check_hankel('qwe', ['', '', '', 200, 80], 0) elif htype == 'hquad': ht, htarg = utils.check_hankel('quad', None, 0) # Analytical frequency-domain solution wvnr4, _, conv = calc(zsrc, zrec, lsrc, lrec, off, angle, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq4 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr4), np.squeeze(freq4), rtol=1e-4)
def test_hankel(htype): # 1. fht / 2. hqwe / 3. hquad # Compare wavenumber-domain calculation / FHT with analytical # frequency-domain fullspace solution calc = getattr(transform, htype) 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) for ab_inp in [11, 12, 13, 33]: ab, msrc, mrec = utils.check_ab(ab_inp, 0) _, htarg = utils.check_hankel(htype, None, 0) xdirect = False # Important, as we want to compare wavenr-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) factAng = kernel.angle_factor(angle, ab, msrc, mrec) lsrc, zsrc = utils.get_layer_nr(src, depth) lrec, zrec = utils.get_layer_nr(rec, depth) # # # 0. No Spline # # # if htype != 'hquad': # hquad is always using spline # Wavenumber solution plus transform # Adjust htarg for fht if htype == 'fht': lambd, int_pts = transform.get_spline_values(htarg[0], off, htarg[1]) htarg = (htarg[0], htarg[1], lambd, int_pts) wvnr0, _, conv = calc(zsrc, zrec, lsrc, lrec, off, factAng, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq0 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr0), np.squeeze(freq0)) # # # 1. Spline; One angle # # # htarg, _ = utils.spline_backwards_hankel(htype, None, 'spline') _, htarg = utils.check_hankel(htype, htarg, 0) if htype == 'hquad': # Lower atol to ensure convergence _, htarg = utils.check_hankel('quad', [1e-8], 0) elif htype == 'fht': # Adjust htarg for fht lambd, int_pts = transform.get_spline_values(htarg[0], off, htarg[1]) htarg = (htarg[0], htarg[1], lambd, int_pts) # Wavenumber solution plus transform wvnr1, _, conv = calc(zsrc, zrec, lsrc, lrec, off, factAng, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq1 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare if htype == 'hqwe' and ab in [13, 33]: assert_allclose(conv, False) else: assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr1), np.squeeze(freq1), rtol=1e-4) # # # 2. Spline; 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) factAng = kernel.angle_factor(angle, ab, msrc, mrec) if htype == 'hqwe': # Put a very low diff_quad, to test it.; lower err _, htarg = utils.check_hankel('qwe', [1e-8, '', '', 200, 80, .1, 1e-6, .1, 1000], 0) elif htype == 'fht': # Adjust htarg for fht lambd, int_pts = transform.get_spline_values(htarg[0], off, htarg[1]) htarg = (htarg[0], htarg[1], lambd, int_pts) # Analytical frequency-domain solution wvnr2, _, conv = calc(zsrc, zrec, lsrc, lrec, off, factAng, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq2 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr2), np.squeeze(freq2), rtol=1e-4) # # # 3. Spline; pts_per_dec # # # if htype == 'fht': _, htarg = utils.check_hankel('fht', ['key_201_2012', 20], 0) lambd, int_pts = transform.get_spline_values(htarg[0], off, htarg[1]) htarg = (htarg[0], htarg[1], lambd, int_pts) elif htype == 'hqwe': _, htarg = utils.check_hankel('qwe', ['', '', '', 80, 100], 0) if htype != 'hquad': # hquad is always pts_per_dec # Analytical frequency-domain solution wvnr3, _, conv = calc(zsrc, zrec, lsrc, lrec, off, factAng, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq3 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr3), np.squeeze(freq3), rtol=1e-4) # # # 4. Spline; Only one offset # # # rec = [5000, 0, 300] rec, nrec = utils.check_dipole(rec, 'rec', 0) off, angle = utils.get_off_ang(src, rec, nsrc, nrec, 0) factAng = kernel.angle_factor(angle, ab, msrc, mrec) if htype == 'hqwe': _, htarg = utils.check_hankel('qwe', ['', '', '', 200, 80], 0) elif htype == 'hquad': _, htarg = utils.check_hankel('quad', None, 0) elif htype == 'fht': lambd, int_pts = transform.get_spline_values(htarg[0], off, htarg[1]) htarg = (htarg[0], htarg[1], lambd, int_pts) # Analytical frequency-domain solution wvnr4, _, conv = calc(zsrc, zrec, lsrc, lrec, off, factAng, depth, ab, etaH, etaV, zetaH, zetaV, xdirect, htarg, False, msrc, mrec) # Analytical frequency-domain solution freq4 = kernel.fullspace(off, angle, zsrc, zrec, etaH, etaV, zetaH, zetaV, ab, msrc, mrec) # Compare assert_allclose(conv, True) assert_allclose(np.squeeze(wvnr4), np.squeeze(freq4), rtol=1e-4)
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