Exemple #1
0
def test_nobackground():
    #=======================================================================
    "Check that dipolar kernel builds correctly without a background specified"
    t = np.linspace(0, 3, 80)
    r = np.linspace(2, 6, 100)

    K1 = dipolarkernel(t, r)

    K2 = dipolarkernel(t, r, bg=None)
    assert np.all(abs(K2 - K1) < 1e-5)
Exemple #2
0
def test_lambda():
    #=======================================================================
    "Check that dipolar kernel with modulation depth works"

    t = np.linspace(0, 4, 150)  # µs
    r = np.linspace(1, 5, 150)  # nm
    lam = 0.4
    Kref = ((1 - lam) + lam * dipolarkernel(t, r, integralop=False))
    K = dipolarkernel(t, r, mod=lam, integralop=False)

    assert np.all(abs(K - Kref) < 1e-14)
Exemple #3
0
def test_r_scaling():
    #=======================================================================
    """Check whether K matrix elements scale properly with t and r"""

    t = 2  # nm
    r = 3  # µs
    c = 1.2  # distance scaling factor

    K1 = dipolarkernel(t, r)
    K2 = dipolarkernel(t * c**3, r * c)

    assert np.max(K1 - K2) < 1e-15
Exemple #4
0
def test_orisel_uni_integral():
    #=======================================================================
    "Check that orientation selection works for a uniform distribution"

    t = 1
    r = 1
    Ptheta = lambda theta: np.ones_like(theta)

    Kref = dipolarkernel(t, r, method='integral')
    K = dipolarkernel(t, r, method='integral', orisel=Ptheta)

    assert np.max(K - Kref) < 1e-10
Exemple #5
0
def test_integralop():
    #=======================================================================
    """Check that integral operator-nature of kernel can be disabled"""

    t = np.linspace(0, 5, 101)
    r = np.linspace(2, 5, 101)
    dr = np.ones(len(r)) * np.mean(np.diff(r))
    dr[0] = dr[0] / 2
    dr[-1] = dr[-1] / 2
    Kref = dipolarkernel(t, r, integralop=True) / dr
    K = dipolarkernel(t, r, integralop=False)

    assert np.max(K - Kref) < 1e-14
Exemple #6
0
def test_negative_time_integral():
    #=======================================================================
    "Check that kernel is constructed properly for negative times using the integral method"

    tneg = np.linspace(-5, 0, 50)
    tpos = np.linspace(0, 5, 50)
    r = np.linspace(2, 6, 10)
    Kneg = dipolarkernel(tneg, r, method='integral')
    Kpos = dipolarkernel(tpos, r, method='integral')

    delta = abs(Kneg - np.flipud(Kpos))

    assert np.all(delta < 1e-12)
Exemple #7
0
def test_background():
    #=======================================================================
    "Check that dipolar kernel builds with the background included"
    t = np.linspace(0, 3, 80)
    r = np.linspace(2, 6, 100)
    B = bg_exp(t, 0.5)

    lam = 0.25
    KBref = (1 - lam +
             lam * dipolarkernel(t, r, integralop=False)) * B[:, np.newaxis]
    KB = dipolarkernel(t, r, mod=lam, bg=B, integralop=False)

    assert np.all(abs(KB - KBref) < 1e-5)
Exemple #8
0
def test_excbandwidth_inf_integral():
    #=======================================================================
    "Check that specifying a bandwidth effectively changes the kernel (integral method)"

    r = 2.5  # nm
    excitewidth = 15  # MHz
    t = np.linspace(0, 2, 501)  # µs

    # Reference kernel with infinite bandwidth
    Kinf = dipolarkernel(t, r, excbandwidth=inf, method='integral')

    # Kernel with limited bandwidth
    Klim = dipolarkernel(t, r, excbandwidth=excitewidth, method='integral')

    assert not np.array_equal(Kinf, Klim)
Exemple #9
0
    def Vnonlinear_fcn(*nonlin):
        """ Non-linear part of the dipolar signal function """
        # Make input arguments as array to access subsets easily
        nonlin = np.atleast_1d(nonlin)
        # Construct the basis function of the intermolecular contribution
        if Bmodel is None:
            Bfcn = np.ones_like(t)
        elif hasattr(Bmodel, 'lam'):
            Bfcn = lambda t, lam: Bmodel.nonlinmodel(
                t, *np.concatenate([nonlin[Bsubset], [lam]]))
        else:

            Bfcn = lambda t, _: Bmodel.nonlinmodel(t, *nonlin[Bsubset])
        # Construct the definition of the dipolar pathways
        pathways = PathsModel.nonlinmodel(*nonlin[PathsSubset])
        # Construct the dipolar kernel
        Kdipolar = dipolarkernel(t,
                                 r,
                                 pathways=pathways,
                                 bg=Bfcn,
                                 excbandwidth=excbandwidth,
                                 orisel=orisel,
                                 g=g,
                                 method=kernelmethod)
        # Compute the non-linear part of the distance distribution
        Pnonlin = Pmodel.nonlinmodel(*[r] * Nconstants, *nonlin[Psubset])
        # Forward calculation of the non-linear part of the dipolar signal
        Vnonlin = Kdipolar @ Pnonlin
        return Vnonlin
Exemple #10
0
def test_gvalues():
    #=======================================================================
    """Check whether K matrix elements scale properly g-values"""

    t = 2  # nm
    r = 3  # µs
    # isotropic g values of two spins
    g1 = 2.1
    g2 = 2.4

    ge = 2.00231930436256  # free-electron g factor (CODATA 2018 value)

    K1 = dipolarkernel(t, r, g=[g1, g2])
    K2 = dipolarkernel(t, r / (g1 * g2 / ge**2)**(1 / 3))

    assert np.max(K1 - K2) < 1e-15
Exemple #11
0
def test_multipath_harmonics():
    #=======================================================================
    "Check that multi-pathway kernels with higher harmonics are properly generated"

    r = np.linspace(2, 6, 50)
    t1 = np.linspace(0, 10, 300)
    t2 = 0.3
    tau1 = 4.24
    tau2 = 4.92
    t = (tau1 + tau2) - (t1 + t2)
    prob = 0.8
    lam = [prob**2, prob * (1 - prob)]
    T0 = [0, tau2 - t2]
    n = [2, 3]

    paths = []
    paths.append([1 - prob])
    paths.append([prob**2, 0, 2])
    paths.append([prob * (1 - prob), tau2 - t2, 3])

    K = dipolarkernel(t, r, pathways=paths, integralop=False)

    Kref = 1 - prob
    for p in range(len(lam)):
        Kref = Kref + lam[p] * elementarykernel(
            n[p] * (t - T0[p]), r, 'fresnel', [], [], [ge, ge], None)
    Kref = Kref

    assert np.max(K - Kref) < 1e-3
Exemple #12
0
def test_singledist():
    #=======================================================================
    "Check that one can generate a kernel with one single distance-domain point"

    t = np.linspace(0, 5, 50)
    r = 3.5
    K = dipolarkernel(t, r)

    assert np.shape(K)[1] == 1
Exemple #13
0
def test_matrixsize_fresnel():
    #=======================================================================
    "Check non-square kernel matrix construction"
    Ntime = 50
    Ndist = 70
    t = np.linspace(-0.5, 5, 50)
    r = np.linspace(2, 6, 70)
    K = dipolarkernel(t, r)
    assert K.shape == (Ntime, Ndist)
Exemple #14
0
def test_singletime():
    #=======================================================================
    "Check that one can generate a kernel with one single time-domain point"

    t = 0.5
    r = np.linspace(1, 5, 100)
    K = dipolarkernel(t, r)

    assert np.shape(K)[0] == 1
def test_complex_type_grid():
    #=======================================================================
    "Test that the values are complex-valued if requested."

    # Generate kernel numerically
    t = 1  # µs
    r = 1  # nm
    K = dipolarkernel(t, r, method='grid', complex=True)

    assert isinstance(K[0, 0], np.complex128)
Exemple #16
0
def test_nonuniform_r():
    #=======================================================================
    "Check that normalization is correct when using a non-uniform distance axis"

    t = 0
    r = np.sqrt(np.linspace(1, 7**2, 200))
    P = dd_gauss(r, 3, 0.5)
    K = dipolarkernel(t, r)
    V0 = K @ P
    assert np.round(V0, 3) == 1
Exemple #17
0
def test_memory_limit():
    # ======================================================================
    "Check that the memory limiter works"
    # Construct 12GB kernel (should fit in RAM)
    t = np.linspace(0, 5, int(3e4))
    r = np.linspace(1, 6, int(5e4))
    with pytest.raises(MemoryError):
        K = dipolarkernel(t, r)


# ======================================================================
def test_complex_value_grid_negative_time():
    #=======================================================================
    "Test whether comple-valued kernel matrix element (calculated using the grid method) is correct."

    # Generate kernel numerically
    t = -1  # µs
    r = 1  # nm
    K = dipolarkernel(t, r, method='grid', nKnots=2e6, complex=True)

    # Kernel value for 1us and 1nm computed using Mathematica (FresnelC and FresnelS)
    # and CODATA 2018 values for ge, muB, mu0, and h.
    Kref = 0.0246978198952619 - 1j * 0.01380433055548875

    assert abs(K - Kref) < 1e-6
Exemple #19
0
def test_value_integral():
    #=======================================================================
    "Test whether kernel matrix element (calculated using the integal method) is correct."

    # Generate kernel numerically
    t = 1  # µs
    r = 1  # nm
    K = dipolarkernel(t, r, method='integral')

    # Kernel value for 1us and 1nm computed using Mathematica (FresnelC and FresnelS)
    # and CODATA 2018 values for ge, muB, mu0, and h.
    Kref = 0.024697819895260188

    assert abs(K - Kref) < 1e-7
def test_complex_value_fresnel():
    #=======================================================================
    "Test whether comple-valued kernel matrix element (calculated using Fresnel integrals) is correct."

    # Generate kernel numerically
    t = 1  # µs
    r = 1  # nm
    K = dipolarkernel(t, r, method='fresnel', complex=True)

    # Kernel value for 1us and 1nm computed using Mathematica (FresnelC and FresnelS)
    # and CODATA 2018 values for ge, muB, mu0, and h.
    Kref = 0.0246978198952619 + 1j * 0.01380433055548875

    assert abs(K - Kref) < 1e-14
Exemple #21
0
def test_orisel_value_integral():
    #=======================================================================
    "Check that orientation selection works for a uniform distribution"

    t = 1
    r = 1
    thetamean = pi / 4
    sigma = pi / 3
    Ptheta = lambda theta: 1 / sigma / np.sqrt(2 * pi) * np.exp(-(
        theta - thetamean)**2 / 2 / sigma**2)

    # Kernel value for 1us and 1nm computed using Mathematica
    # and CODATA 2018 values for ge, muB, mu0, and h
    Kref = 0.02031864642707554

    K = dipolarkernel(t, r, method='integral', orisel=Ptheta)

    assert abs(K - Kref) < 1e-4
Exemple #22
0
def _hom3dex(t, conc, rex, lam):
    # Conversion: umol/L -> mol/L -> mol/m^3 -> spins/m^3
    conc = conc * 1e-6 * 1e3 * Nav

    # Excluded volume
    Vex = 4 * np.pi / 3 * (rex * 1e-9)**3

    # Averaging integral
    z = np.linspace(0, 1, 1000)[np.newaxis, :]
    Dt = D * t[:, np.newaxis] * 1e-6
    Is = 4 * np.pi / 3 * np.trapz(Dt * (1 - 3 * z**2) * sici(
        (Dt * (1 - 3 * z**2)) / ((rex * 1e-9)**3))[0],
                                  z,
                                  axis=1)

    # Background function
    C_k = -Vex + Is + np.squeeze(Vex *
                                 (dipolarkernel(t, rex, integralop=False)))
    B = np.exp(-lam * conc * C_k)

    return B
Exemple #23
0
def _hom3dex_phase(t, conc, rex, lam):
    # Conversion: umol/L -> mol/L -> mol/m^3 -> spins/m^3
    conc = conc * 1e-6 * 1e3 * Nav

    # Excluded volume
    Vex = 4 * np.pi / 3 * (rex * 1e-9)**3

    # Averaging integral
    ξ = 8 * pi**2 / 9 / np.sqrt(3) * (np.sqrt(3) +
                                      np.log(2 - np.sqrt(3))) / np.pi * D
    z = np.linspace(0, 1, 1000)[np.newaxis, :]
    Dt = D * t[:, np.newaxis] * 1e-6
    Ic = -ξ * (t * 1e-6) + 4 * np.pi / 3 * np.trapz(Dt * (1 - 3 * z**2) * sici(
        (Dt * np.abs(1 - 3 * z**2)) / ((rex * 1e-9)**3))[1],
                                                    z,
                                                    axis=1)

    # Background function
    C_k = -Ic - np.squeeze(
        Vex * (dipolarkernel(t, rex, integralop=False, complex=True)).imag)
    B = np.exp(-1j * lam * conc * C_k)

    return B
Exemple #24
0
def test_multipath_background():
    #=======================================================================
    "Check that multi-pathway kernels are properly generated with background"

    r = np.linspace(2, 6, 50)
    t1 = np.linspace(0, 10, 300)
    t2 = 0.3
    tau1 = 4.24
    tau2 = 4.92
    t = (tau1 + tau2) - (t1 + t2)
    prob = 0.8
    lam = [prob**2, prob * (1 - prob)]
    T0 = [0, tau2 - t2]
    conc = 50
    Bmodel = lambda t, lam: bg_hom3d(t, conc, lam)

    # Reference
    Kref = 1 - prob
    for p in range(len(lam)):
        Kref = Kref + lam[p] * elementarykernel(t - T0[p], r, 'fresnel', [],
                                                [], [ge, ge], None)
    Kref = Kref

    Bref = 1
    for p in range(len(lam)):
        Bref = Bref * Bmodel((t - T0[p]), lam[p])
    KBref = Kref * Bref[:, np.newaxis]

    paths = []
    paths.append([1 - prob])
    paths.append([prob**2, 0])
    paths.append([prob * (1 - prob), tau2 - t2])

    # Output
    KB = dipolarkernel(t, r, pathways=paths, bg=Bmodel, integralop=False)

    assert np.all(abs(KB - KBref) < 1e-3)
Exemple #25
0
def test_excbandwidth():
    #=======================================================================
    """Check kernel with limited excitation bandwidth is numerically correct"""

    r = 2.5  # nm
    excitewidth = 15  # MHz
    t = np.linspace(0, 2, 501)  # µs

    # Kernel using numerical integrals and approx. bandwidth treatment
    K = dipolarkernel(t, r, excbandwidth=excitewidth, method='grid')

    # Manual calculation using numerical powder average (reference)
    nKnots = 5001
    costheta = np.linspace(0, 1, nKnots)
    wdd = 2 * pi * 52.04 / r**3  # Mrad/s
    q = 1 - 3 * costheta**2
    D_ = 0
    for orientation in q:
        w = wdd * orientation
        D_ = D_ + np.cos(w * abs(t)) * np.exp(-w**2 / excitewidth**2)
    K0 = D_ / nKnots
    K0 = K0.reshape((len(t), 1))

    assert np.max(K0 - K) < 1e-4
Exemple #26
0
    "Check that the model has correct parameter names"

    model = dipolarmodel(t,r,dd_gauss,bg_hom3d,npathways=1)
    parameters = ['mean','width','conc','mod','reftime','scale']
    
    for param in parameters:
        assert hasattr(model,param)
# ======================================================================


t = np.linspace(-0.5,5,100)
r = np.linspace(2,5,50)
Bfcn = lambda t,lam: bg_hom3d(t,50,lam)
Bfcn_pheno = lambda t,_: bg_exp(t,0.1)
Pr = dd_gauss(r,3,0.2)
V1path = 1e5*dipolarkernel(t,r,mod=0.3,bg=Bfcn)@Pr
V1path_noB = 1e5*dipolarkernel(t,r,mod=0.3)@Pr
V1path_phenoB = 1e5*dipolarkernel(t,r,mod=0.3,bg=Bfcn_pheno)@Pr
V2path = 1e5*dipolarkernel(t,r,pathways=[[0.6],[0.3,0],[0.1,2]],bg=Bfcn)@Pr
V3path = 1e5*dipolarkernel(t,r,pathways=[[0.5],[0.3,0],[0.1,2],[0.1,5]],bg=Bfcn)@Pr


# ======================================================================
def test_call_positional(): 
    "Check that the model called via positional arguments responds correctly"

    Vmodel = dipolarmodel(t,r,dd_gauss,bg_hom3d,npathways=1)
    
    Vsim = Vmodel(0.3,0.0,50,3,0.2,1e5)

    assert np.allclose(Vsim,V1path)
Exemple #27
0
    model = dipolarmodel(t, r, dd_gauss, bg_hom3d, npathways=1)
    parameters = ['mean', 'width', 'conc', 'mod', 'reftime', 'scale']

    for param in parameters:
        assert hasattr(model, param)


# ======================================================================

t = np.linspace(-0.5, 5, 100)
r = np.linspace(2, 5, 50)
Bfcn = lambda t, lam: bg_hom3d(t, 50, lam)
Bfcn_pheno = lambda t, _: bg_exp(t, 0.1)
Pr = dd_gauss(r, 3, 0.2)
V1path = 1e5 * dipolarkernel(t, r, mod=0.3, bg=Bfcn) @ Pr
V1path_noB = 1e5 * dipolarkernel(t, r, mod=0.3) @ Pr
V1path_phenoB = 1e5 * dipolarkernel(t, r, mod=0.3, bg=Bfcn_pheno) @ Pr
V2path = 1e5 * dipolarkernel(
    t, r, pathways=[[0.6], [0.3, 0], [0.1, 2]], bg=Bfcn) @ Pr
V3path = 1e5 * dipolarkernel(
    t, r, pathways=[[0.5], [0.3, 0], [0.1, 2], [0.1, 5]], bg=Bfcn) @ Pr


# ======================================================================
def test_call_positional():
    "Check that the model called via positional arguments responds correctly"

    Vmodel = dipolarmodel(t, r, dd_gauss, bg_hom3d, npathways=1)

    Vsim = Vmodel(0.3, 0.0, 50, 3, 0.2, 1e5)