예제 #1
0
def test_dimensionality_of_lineshape_kernel():
    kernel_dimensions = [
        cp.Dimension(type="linear", count=96, increment="208.33 Hz", complex_fft=True)
    ]

    inverse_dimension = [
        cp.Dimension(type="linear", count=25, increment="370 Hz"),
        cp.Dimension(type="linear", count=25, increment="370 m"),
    ]

    error = r"with quantity name `\['frequency', 'dimensionless'\]` is required for "
    with pytest.raises(ValueError, match=f".*{error}.*"):
        ShieldingPALineshape(
            anisotropic_dimension=kernel_dimensions,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )

    kernel_dimensions = cp.Dimension(
        type="linear", count=96, increment="208.33 ms", complex_fft=True
    )
    with pytest.raises(ValueError, match=f".*{error}.*"):
        ShieldingPALineshape(
            anisotropic_dimension=kernel_dimensions,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )
예제 #2
0
def test_zeta_eta_from_x_y():
    for dim in anisotropic_dims:
        ns_obj = ShieldingPALineshape(
            anisotropic_dimension=dim,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )

        x = np.arange(4) * 3000
        y = np.arange(4) * 3000
        factor_ = 4 / np.pi
        zeta_ = []
        eta_ = []
        for y_ in y:
            for x_ in x:
                z = np.sqrt(x_**2 + y_**2)
                if x_ < y_:
                    eta_.append(factor_ * np.arctan(x_ / y_))
                    zeta_.append(z)
                elif x_ > y_:
                    eta_.append(factor_ * np.arctan(y_ / x_))
                    zeta_.append(-z)
                else:
                    zeta_.append(z)
                    eta_.append(1.0)
        zeta, eta = ns_obj._get_zeta_eta(supersampling=1)

        assert np.allclose(zeta, np.asarray(zeta_))
        assert np.allclose(eta, np.asarray(eta_))
예제 #3
0
def test_MAF_lineshape_kernel():
    for dim in anisotropic_dims:
        ns_obj = ShieldingPALineshape(
            anisotropic_dimension=dim,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )
        zeta, eta = ns_obj._get_zeta_eta(supersampling=1)
        K = ns_obj.kernel(supersampling=1)
        sim_lineshape = generate_shielding_kernel(zeta, eta, np.pi / 2, 14000,
                                                  1).T
        assert np.allclose(K, sim_lineshape, rtol=1.0e-3, atol=1e-3)

        ns_obj = MAF(
            anisotropic_dimension=dim,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
        )
        zeta, eta = ns_obj._get_zeta_eta(supersampling=1)
        K = ns_obj.kernel(supersampling=1)
        sim_lineshape = generate_shielding_kernel(zeta, eta, np.pi / 2, 14000,
                                                  1).T

        assert np.allclose(K, sim_lineshape, rtol=1.0e-3, atol=1e-3)

        _ = TSVDCompression(K, s=np.arange(96))
        assert _.truncation_index == 15
예제 #4
0
def generate_kernel(n, data, count0, inc0, count1, inc1, channel, B0, theta,
                    n_su, d_range, k_typ):
    if data is None:
        raise PreventUpdate

    if d_range is None:
        d_range = [[0, -1], [0, -1]]

    data = cp.parse_dict(data)

    anisotropic_dimension = data.dimensions[0]
    inverse_dimensions = [
        cp.LinearDimension(count=count0, increment=f"{inc0} Hz", label="x"),
        cp.LinearDimension(count=count1, increment=f"{inc1} Hz", label="y"),
    ]

    vr = 0
    ns = 1

    if k_typ == "sideband-correlation":
        vr = anisotropic_dimension.increment.to("Hz")
        ns = anisotropic_dimension.count

    if k_typ == "MAF":
        vr = "1 GHz"
        ns = 1

    K = ShieldingPALineshape(
        anisotropic_dimension=anisotropic_dimension,
        inverse_dimension=inverse_dimensions,
        channel=channel,
        magnetic_flux_density=f"{B0} T",
        rotor_angle=f"{theta} °",
        rotor_frequency=f"{vr}",
        number_of_sidebands=ns,
    ).kernel(supersampling=int(n_su))

    ranges = slice(d_range[1][0], d_range[1][1], None)
    data_truncated = data[:, ranges]

    new_system = TSVDCompression(K, data_truncated)
    compressed_K = new_system.compressed_K
    compressed_s = new_system.compressed_s

    return {
        "kernel": compressed_K,
        "signal": compressed_s.dict(),
        "inverse_dimensions": [item.dict() for item in inverse_dimensions],
    }
예제 #5
0
                       label="y"),  # the `y`-dimension.
]

# %%
# Generating the kernel
# '''''''''''''''''''''
#
# For MAF datasets, the line-shape kernel corresponds to the pure nuclear shielding
# anisotropy line-shapes. Use the
# :class:`~mrinversion.kernel.nmr.ShieldingPALineshape` class to generate a
# shielding line-shape kernel.
lineshape = ShieldingPALineshape(
    anisotropic_dimension=anisotropic_dimension,
    inverse_dimension=inverse_dimensions,
    channel="29Si",
    magnetic_flux_density="9.4 T",
    rotor_angle="90°",
    rotor_frequency="12 kHz",
    number_of_sidebands=4,
)

# %%
# Here, ``lineshape`` is an instance of the
# :class:`~mrinversion.kernel.nmr.ShieldingPALineshape` class. The required
# arguments of this class are the `anisotropic_dimension`, `inverse_dimension`, and
# `channel`. We have already defined the first two arguments in the previous
# sub-section. The value of the `channel` argument is the nucleus observed in the MAF
# experiment. In this example, this value is '29Si'.
# The remaining arguments, such as the `magnetic_flux_density`, `rotor_angle`,
# and `rotor_frequency`, are set to match the conditions under which the 2D MAF
# spectrum was acquired. The value of the `number_of_sidebands` argument is the number
예제 #6
0
                       label="y"),  # the `y`-dimension.
]

# %%
# Generating the kernel
# '''''''''''''''''''''
#
# For MAF/PASS datasets, the kernel corresponds to the pure nuclear shielding anisotropy
# sideband spectra. Use the
# :class:`~mrinversion.kernel.nmr.ShieldingPALineshape` class to generate a
# shielding spinning sidebands kernel.
sidebands = ShieldingPALineshape(
    anisotropic_dimension=anisotropic_dimension,
    inverse_dimension=inverse_dimensions,
    channel="29Si",
    magnetic_flux_density="9.4 T",
    rotor_angle="54.735°",
    rotor_frequency="790 Hz",
    number_of_sidebands=anisotropic_dimension.count,
)

# %%
# Here, ``sidebands`` is an instance of the
# :class:`~mrinversion.kernel.nmr.ShieldingPALineshape` class. The required
# arguments of this class are the `anisotropic_dimension`, `inverse_dimension`, and
# `channel`. We have already defined the first two arguments in the previous
# sub-section. The value of the `channel` argument is the nucleus observed in the
# MAT/PASS experiment. In this example, this value is '29Si'.
# The remaining arguments, such as the `magnetic_flux_density`, `rotor_angle`,
# and `rotor_frequency`, are set to match the conditions under which the 2D MAT/PASS
# spectrum was acquired, which in this case corresponds to acquisition at
예제 #7
0
def test_01():
    domain = "https://sandbox.zenodo.org/record/1065347/files"
    filename = f"{domain}/8lnwmg0dr7y6egk40c2orpkmmugh9j7c.csdf"
    data_object = cp.load(filename)
    data_object = data_object.real
    _ = [item.to("ppm", "nmr_frequency_ratio") for item in data_object.dimensions]

    data_object = data_object.T
    data_object_truncated = data_object[:, 155:180]

    anisotropic_dimension = data_object_truncated.dimensions[0]
    inverse_dimensions = [
        cp.LinearDimension(count=25, increment="400 Hz", label="x"),
        cp.LinearDimension(count=25, increment="400 Hz", label="y"),
    ]

    lineshape = ShieldingPALineshape(
        anisotropic_dimension=anisotropic_dimension,
        inverse_dimension=inverse_dimensions,
        channel="29Si",
        magnetic_flux_density="9.4 T",
        rotor_angle="87.14°",
        rotor_frequency="14 kHz",
        number_of_sidebands=4,
    )
    K = lineshape.kernel(supersampling=2)

    new_system = TSVDCompression(K, data_object_truncated)
    compressed_K = new_system.compressed_K
    compressed_s = new_system.compressed_s

    assert new_system.truncation_index == 87

    s_lasso = SmoothLasso(
        alpha=2.07e-7, lambda1=7.85e-6, inverse_dimension=inverse_dimensions
    )
    s_lasso.fit(K=compressed_K, s=compressed_s)
    f_sol = s_lasso.f

    residuals = s_lasso.residuals(K=K, s=data_object_truncated)

    # assert np.allclose(residuals.mean().value, 0.00048751)
    np.testing.assert_almost_equal(residuals.std().value, 0.00336372, decimal=2)

    f_sol /= f_sol.max()
    [item.to("ppm", "nmr_frequency_ratio") for item in f_sol.dimensions]

    Q4_region = f_sol[0:8, 0:8, 3:18]
    Q4_region.description = "Q4 region"

    Q3_region = f_sol[0:8, 11:22, 8:20]
    Q3_region.description = "Q3 region"

    # Analysis
    int_Q4 = stats.integral(Q4_region)  # volume of the Q4 distribution
    mean_Q4 = stats.mean(Q4_region)  # mean of the Q4 distribution
    std_Q4 = stats.std(Q4_region)  # standard deviation of the Q4 distribution

    int_Q3 = stats.integral(Q3_region)  # volume of the Q3 distribution
    mean_Q3 = stats.mean(Q3_region)  # mean of the Q3 distribution
    std_Q3 = stats.std(Q3_region)  # standard deviation of the Q3 distribution

    np.testing.assert_almost_equal(
        (100 * int_Q4 / (int_Q4 + int_Q3)).value, 60.45388973909665, decimal=1
    )

    np.testing.assert_almost_equal(
        np.asarray([mean_Q4[0].value, mean_Q4[1].value, mean_Q4[2].value]),
        np.asarray([8.604842824865958, 9.05845796147297, -103.6976331077773]),
        decimal=0,
    )

    np.testing.assert_almost_equal(
        np.asarray([mean_Q3[0].value, mean_Q3[1].value, mean_Q3[2].value]),
        np.asarray([10.35036818411856, 79.02481579085152, -90.58326773441284]),
        decimal=0,
    )

    np.testing.assert_almost_equal(
        np.asarray([std_Q4[0].value, std_Q4[1].value, std_Q4[2].value]),
        np.asarray([4.525457744683861, 4.686253809896416, 5.369228151035292]),
        decimal=0,
    )

    np.testing.assert_almost_equal(
        np.asarray([std_Q3[0].value, std_Q3[1].value, std_Q3[2].value]),
        np.asarray([6.138761032132587, 7.837190479891721, 4.210912435356488]),
        decimal=0,
    )
    cp.LinearDimension(count=25, increment="370 Hz",
                       label="y"),  # the `y`-dimension.
]

# %%
# Generating the kernel
# '''''''''''''''''''''
#
# For MAF datasets, the line-shape kernel corresponds to the pure nuclear shielding
# anisotropy line-shapes. Use the
# :class:`~mrinversion.kernel.nmr.ShieldingPALineshape` class to generate a
# shielding line-shape kernel.
lineshape = ShieldingPALineshape(
    anisotropic_dimension=anisotropic_dimension,
    inverse_dimension=inverse_dimension,
    channel="29Si",
    magnetic_flux_density="9.4 T",
    rotor_angle="90 deg",
    rotor_frequency="14 kHz",
)
K = lineshape.kernel(supersampling=1)

# %%
# Data Compression
# ''''''''''''''''
#
# Data compression is optional but recommended. It may reduce the size of the
# inverse problem and, thus, further computation time.
new_system = TSVDCompression(K, data_object)
compressed_K = new_system.compressed_K
compressed_s = new_system.compressed_s
예제 #9
0
def test_number_of_dimensions_for_lineshape_kernel():
    kernel_dimensions = [
        cp.Dimension(type="linear", count=96, increment="208.33 Hz", complex_fft=True)
    ]

    inverse_dimension = [
        cp.Dimension(type="linear", count=25, increment="370 Hz"),
        cp.Dimension(type="linear", count=25, increment="370 Hz"),
    ]

    error = r"Exactly 2 inverse dimension\(s\) is/are required for the"
    with pytest.raises(ValueError, match=f".*{error}.*"):
        ShieldingPALineshape(
            anisotropic_dimension=kernel_dimensions,
            inverse_dimension=inverse_dimension[0],
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )

    with pytest.raises(ValueError, match=f".*{error}.*"):
        ShieldingPALineshape(
            anisotropic_dimension=kernel_dimensions,
            inverse_dimension=[inverse_dimension[0]],
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )

    error = r"Exactly 1 direct dimension\(s\) is/are required for the"
    with pytest.raises(ValueError, match=f".*{error}.*"):
        ShieldingPALineshape(
            anisotropic_dimension=inverse_dimension,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )

    kernel_dimension__ = {}
    error = r"The value of the `kernel_dimension` attribute must be one of "
    with pytest.raises(ValueError, match=f".*{error}.*"):
        ShieldingPALineshape(
            anisotropic_dimension=kernel_dimension__,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )

    inverse_dimension = ["", ""]
    error = "The element at index 0 of the `inverse_dimension` list must be an"
    with pytest.raises(ValueError, match=f".*{error}.*"):
        ShieldingPALineshape(
            anisotropic_dimension=kernel_dimensions,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )

    inverse_kernel_dimension__ = [
        {"type": "linear", "count": 10, "increment": "1 Hz"},
        "string",
    ]
    error = "The element at index 0 of the `inverse_dimension` list must be an"
    with pytest.raises(ValueError, match=f".*{error}.*"):
        ShieldingPALineshape(
            anisotropic_dimension=kernel_dimensions,
            inverse_dimension=inverse_kernel_dimension__,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="90 deg",
            rotor_frequency="14 kHz",
            number_of_sidebands=1,
        )
예제 #10
0
def test_spinning_sidebands_kernel():
    # 1
    for dim in anisotropic_dims:
        ns_obj = ShieldingPALineshape(
            anisotropic_dimension=dim,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="54.735 deg",
            rotor_frequency="100 Hz",
            number_of_sidebands=96,
        )
        zeta, eta = ns_obj._get_zeta_eta(supersampling=1)
        K = ns_obj.kernel(supersampling=1)
        sim_lineshape = generate_shielding_kernel(zeta, eta,
                                                  0.9553059660790962, 100,
                                                  96).T

        assert np.allclose(K, sim_lineshape, rtol=1.0e-3, atol=1e-3)

        # 2
        ns_obj = ShieldingPALineshape(
            anisotropic_dimension=dim,
            inverse_dimension=inverse_dimension_ppm,
            channel="29Si",
            magnetic_flux_density="9.4 T",
            rotor_angle="54.735 deg",
            rotor_frequency="100 Hz",
            number_of_sidebands=96,
        )
        zeta, eta = ns_obj._get_zeta_eta(supersampling=1)
        K = ns_obj.kernel(supersampling=1)
        sim_lineshape = generate_shielding_kernel(zeta,
                                                  eta,
                                                  0.9553059660790962,
                                                  100,
                                                  96,
                                                  to_ppm=False).T

        assert np.allclose(K, sim_lineshape, rtol=1.0e-3, atol=1e-3)

        # 3
        ns_obj = SpinningSidebands(
            anisotropic_dimension=dim,
            inverse_dimension=inverse_dimension,
            channel="29Si",
            magnetic_flux_density="9.4 T",
        )
        zeta, eta = ns_obj._get_zeta_eta(supersampling=1)
        K = ns_obj.kernel(supersampling=1)
        sim_lineshape = generate_shielding_kernel(zeta, eta,
                                                  0.9553059660790962, 208.33,
                                                  96).T

        assert np.allclose(K, sim_lineshape, rtol=1.0e-3, atol=1e-3)

        _ = TSVDCompression(K, s=np.arange(96))
        assert _.truncation_index == 15