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, )
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_))
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
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], }
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
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
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
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, )
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