def test_methods(): das = Method( name="DAS", channels=["87Rb"], magnetic_flux_density=4.2, # in T rotor_angle=54.735 * 3.14159 / 180, # in rads rotor_frequency=1000000000000, spectral_dimensions=[ { "count": 256, "spectral_width": 2e4, # in Hz "reference_offset": -5e3, # in Hz "label": "70.12 dimension", "events": [ { "fraction": 0.5, "rotor_angle": 70.12 * 3.14159 / 180, # in rads "transition_queries": [{ "ch1": { "P": [-1], "D": [0] } }], }, { "fraction": 0.5, "rotor_angle": 30.12 * 3.14159 / 180, # in rads "transition_queries": [{ "ch1": { "P": [-1], "D": [0] } }], }, ], }, # The last spectral dimension block is the direct-dimension { "count": 256, "spectral_width": 3e4, # in Hz "reference_offset": -7e3, # in Hz "label": "MAS dimension", "events": [{ "transition_queries": [{ "ch1": { "P": [-1], "D": [0] } }] }], }, ], ) assert das.affine_matrix is None assert das.json() == TESTDATA["DAS"] assert Method.parse_dict_with_units(das.json()) == das
def test_2D_method(): # Method2D replaced with generic Method object error = "The first element of the affine matrix cannot be zero." with pytest.raises(ValueError, match=f".*{error}.*"): Method(spectral_dimensions=[{}, {}], affine_matrix=[0, 1, 2, 3])
def test_BlochDecaySpectrum(): # test-1 m1 = BlochDecaySpectrum(channels=["1H"]) dimension_dictionary_ = { "count": 1024, "spectral_width": "25000.0 Hz", "events": [{ "transition_queries": [{ "ch1": { "P": [-1] } }] }], } should_be = { "name": "BlochDecaySpectrum", "channels": ["1H"], "magnetic_flux_density": "9.4 T", "rotor_frequency": "0.0 Hz", "rotor_angle": "0.9553166181245 rad", "spectral_dimensions": [dimension_dictionary_], } dict_ = m1.json() assert Method.parse_dict_with_units(dict_) == m1 dict_.pop("description") assert dict_ == should_be # test-2 m2_dict = { "channels": ["29Si"], "magnetic_flux_density": "11.7 T", "rotor_angle": "90 deg", "spectral_dimensions": [{}], } m2 = BlochDecaySpectrum.parse_dict_with_units(m2_dict) angle = 90 * np.pi / 180 dimension_dictionary_ = { "count": 1024, "spectral_width": "25000.0 Hz", "events": [{ "transition_queries": [{ "ch1": { "P": [-1] } }] }], } should_be = { "name": "BlochDecaySpectrum", "channels": ["29Si"], "magnetic_flux_density": "11.7 T", "rotor_frequency": "0.0 Hz", "rotor_angle": f"{angle} rad", "spectral_dimensions": [dimension_dictionary_], } dict_ = m2.json() assert Method.parse_dict_with_units(dict_) == m2 dict_.pop("description") assert dict_ == should_be
# -*- coding: utf-8 -*- import numpy as np from mrsimulator import SpinSystem from mrsimulator.method import Method from mrsimulator.methods import Method1D from mrsimulator.methods import Method2D from mrsimulator.transition import TransitionPathway __author__ = "Deepansh J. Srivastava" __email__ = "*****@*****.**" method1 = Method( channels=["13C"], spectral_dimensions=[{"events": [{"transition_query": [{"ch1": {"P": [-1]}}]}]}], ) method2 = Method( channels=["13C"], spectral_dimensions=[{"events": [{"transition_query": [{"ch1": {"P": [-2]}}]}]}], ) def check_transition_set(got, expected): assert len(got) == len(expected), "Inconsistent transition pathway count" for item in got: assert item in expected, f"Transition pathways not found: {item}" def test_00(): system = SpinSystem(sites=[{"isotope": "13C"}]) tr = method1.get_transition_pathways(system)
def SSB2D_setup(ist, vr, method_type): sites = [ Site( isotope=ist, isotropic_chemical_shift=29, shielding_symmetric={ "zeta": -70, "eta": 0.000 }, ), Site( isotope=ist, isotropic_chemical_shift=44, shielding_symmetric={ "zeta": -96, "eta": 0.166 }, ), Site( isotope=ist, isotropic_chemical_shift=57, shielding_symmetric={ "zeta": -120, "eta": 0.168 }, ), ] spin_systems = [SpinSystem(sites=[s]) for s in sites] B0 = 11.7 sq_tq = {"transition_queries": [{"ch1": {"P": [-1]}}]} if method_type == "PASS": method = SSB2D( channels=[ist], magnetic_flux_density=B0, # in T rotor_frequency=vr, spectral_dimensions=[ { "count": 32, "spectral_width": 32 * vr, # in Hz "label": "Anisotropic dimension", }, # The last spectral dimension block is the direct-dimension { "count": 2048, "spectral_width": 2e4, # in Hz "reference_offset": 5e3, # in Hz "label": "Fast MAS dimension", }, ], ) else: method = Method( channels=[ist], magnetic_flux_density=B0, # in T rotor_frequency=1e12, spectral_dimensions=[ { "count": 64, "spectral_width": 8e4, # in Hz "label": "Anisotropic dimension", "events": [{ "rotor_angle": 90 * 3.14159 / 180, **sq_tq }], }, # The last spectral dimension block is the direct-dimension { "count": 2048, "spectral_width": 2e4, # in Hz "reference_offset": 5e3, # in Hz "label": "Fast MAS dimension", "events": [sq_tq], }, ], affine_matrix=[[1, -1], [0, 1]], ) sim = Simulator() sim.spin_systems = spin_systems # add spin systems sim.methods = [method] # add the method. sim.run() data_ssb = sim.methods[0].simulation dim_ssb = data_ssb.x[0].coordinates.value if method_type == "PASS": bloch = BlochDecaySpectrum( channels=[ist], magnetic_flux_density=B0, # in T rotor_frequency=vr, # in Hz spectral_dimensions=[ { "count": 32, "spectral_width": 32 * vr, # in Hz "reference_offset": 0, # in Hz "label": "MAS dimension", }, ], ) else: bloch = BlochDecaySpectrum( channels=[ist], magnetic_flux_density=B0, # in T rotor_frequency=vr, # in Hz rotor_angle=90 * 3.14159 / 180, spectral_dimensions=[ { "count": 64, "spectral_width": 8e4, # in Hz "reference_offset": 0, # in Hz "label": "MAS dimension", }, ], ) for i in range(3): iso = spin_systems[i].sites[0].isotropic_chemical_shift sys = spin_systems[i].copy() sys.sites[0].isotropic_chemical_shift = 0 sim2 = Simulator() sim2.spin_systems = [sys] # add spin systems sim2.methods = [bloch] # add the method. sim2.run() index = np.where(dim_ssb < iso)[0][-1] one_d_section = data_ssb.y[0].components[0][:, index] one_d_section /= one_d_section.max() one_d_sim = sim2.methods[0].simulation.y[0].components[0] one_d_sim /= one_d_sim.max() np.testing.assert_almost_equal(one_d_section, one_d_sim, decimal=4)
def test_method_2D(): error = "The first element of the affine matrix cannot be zero." with pytest.raises(ValueError, match=f".*{error}.*"): Method2D(spectral_dimensions=[{}, {}], affine_matrix=[0, 1, 2, 3]) # parse dict with units test dict_1d = { "channels": ["87Rb"], "magnetic_flux_density": "7 T", # in T "rotor_angle": "54.735 deg", "spectral_dimensions": [ { "count": 1024, "spectral_width": "10 kHz", # in Hz "events": [ { "fraction": 27 / 17, "freq_contrib": ["Quad2_0"] }, { "fraction": 1, "freq_contrib": ["Quad2_4"] }, ], }, { "count": 1024, "spectral_width": "10 kHz", # in Hz "events": [ { "fraction": 27 / 17, "freq_contrib": ["Quad2_0"] }, { "fraction": 1, "freq_contrib": ["Quad2_4"] }, ], }, ], } method1a = Method2D.parse_dict_with_units(dict_1d) assert Method.parse_dict_with_units(method1a.json()) == method1a method1b = Method2D( channels=["87Rb"], magnetic_flux_density=7, # in T rotor_angle=54.735 * np.pi / 180, spectral_dimensions=[ { "count": 1024, "spectral_width": 1e4, # in Hz "events": [ { "fraction": 27 / 17, "freq_contrib": ["Quad2_0"] }, { "fraction": 1, "freq_contrib": ["Quad2_4"] }, ], }, { "count": 1024, "spectral_width": 1e4, # in Hz "events": [ { "fraction": 27 / 17, "freq_contrib": ["Quad2_0"] }, { "fraction": 1, "freq_contrib": ["Quad2_4"] }, ], }, ], ) assert method1a == method1b
def test_method_1D(): error = "Expecting a 1x1 affine matrix." with pytest.raises(ValueError, match=f".*{error}.*"): Method1D(spectral_dimensions=[{}], affine_matrix=[1, 2, 3, 4]) error = r"The method allows 1 spectral dimension\(s\), 2 given." with pytest.raises(ValueError, match=f".*{error}.*"): Method1D(spectral_dimensions=[{}, {}]) # parse dict with units test dict_1d = { "channels": ["87Rb"], "magnetic_flux_density": "7 T", # in T "rotor_angle": "54.735 deg", "rotor_frequency": "1e9 Hz", "spectral_dimensions": [{ "count": 1024, "spectral_width": "10 kHz", # in Hz "reference_offset": "-4 kHz", # in Hz "events": [ { "fraction": 27 / 17, "freq_contrib": ["Quad2_0"] }, { "fraction": 1, "freq_contrib": ["Quad2_4"] }, ], }], } method1a = Method1D.parse_dict_with_units(dict_1d) assert Method.parse_dict_with_units(method1a.json()) == method1a method1b = Method1D( channels=["87Rb"], magnetic_flux_density=7, # in T rotor_angle=54.735 * np.pi / 180, rotor_frequency=1e9, spectral_dimensions=[{ "count": 1024, "spectral_width": 1e4, # in Hz "reference_offset": -4e3, # in Hz "events": [ { "fraction": 27 / 17, "freq_contrib": ["Quad2_0"] }, { "fraction": 1, "freq_contrib": ["Quad2_4"] }, ], }], ) assert method1a == method1b
def parse_dict_with_units(cls, py_dict: dict): """Parse the physical quantity from a dictionary representation of the Simulator object, where the physical quantity is expressed as a string with a number and a unit. Args: dict py_dict: A required python dict object. Returns: A :ref:`simulator_api` object. Example ------- >>> sim_py_dict = { ... 'config': { ... 'decompose_spectrum': 'none', ... 'integration_density': 70, ... 'integration_volume': 'octant', ... 'number_of_sidebands': 64 ... }, ... 'spin_systems': [ ... { ... 'abundance': '100 %', ... 'sites': [{ ... 'isotope': '13C', ... 'isotropic_chemical_shift': '20.0 ppm', ... 'shielding_symmetric': {'eta': 0.5, 'zeta': '10.0 ppm'} ... }] ... }, ... { ... 'abundance': '100 %', ... 'sites': [{ ... 'isotope': '1H', ... 'isotropic_chemical_shift': '-4.0 ppm', ... 'shielding_symmetric': {'eta': 0.1, 'zeta': '2.1 ppm'} ... }] ... }, ... { ... 'abundance': '100 %', ... 'sites': [{ ... 'isotope': '27Al', ... 'isotropic_chemical_shift': '120.0 ppm', ... 'shielding_symmetric': {'eta': 0.1, 'zeta': '2.1 ppm'} ... }] ... } ... ] ... } >>> sim = Simulator.parse_dict_with_units(sim_py_dict) >>> len(sim.spin_systems) 3 """ py_copy_dict = deepcopy(py_dict) if "spin_systems" in py_copy_dict: spin_sys = py_copy_dict["spin_systems"] spin_sys = [SpinSystem.parse_dict_with_units(obj) for obj in spin_sys] py_copy_dict["spin_systems"] = spin_sys if "methods" in py_copy_dict: methods = py_copy_dict["methods"] methods = [Method.parse_dict_with_units(obj) for obj in methods] py_copy_dict["methods"] = methods return Simulator(**py_copy_dict)
sas = Method( channels=["87Rb"], magnetic_flux_density=4.2, # in T rotor_frequency=np.inf, spectral_dimensions=[ SpectralDimension( count=256, spectral_width=1.5e4, # in Hz reference_offset=-5e3, # in Hz label="70.12 dimension", events=[ SpectralEvent( rotor_angle=70.12 * np.pi / 180, # in radians transition_queries=[{ "ch1": { "P": [-1], "D": [0] } }], ) ], ), SpectralDimension( count=512, spectral_width=15e3, # in Hz reference_offset=-7e3, # in Hz label="MAS dimension", events=[ SpectralEvent( rotor_angle=54.74 * np.pi / 180, # in radians transition_queries=[{ "ch1": { "P": [-1], "D": [0] } }], ) ], ), ], )
def test_summary(): all_defined_no_constant_spec_dims = [ { "events": [ { "label": "Mix0", "mixing_query": { "ch1": { "tip_angle": np.pi / 4, "phase": np.pi / 2 } }, }, { "label": "Dur0", "duration": 1, "magnetic_flux_density": 1, "rotor_frequency": 0, # in kHz "rotor_angle": 0.1, "transition_query": [{ "ch1": { "P": [0], "D": [0] } }], }, { "label": "Spec0", "fraction": 1, "magnetic_flux_density": 2, "rotor_frequency": 20000, "rotor_angle": 0.2, "transition_query": [{ "ch1": { "P": [1], "D": [-2] } }], }, ] }, { "events": [ { "label": "Mix1", "mixing_query": { "ch1": { "tip_angle": np.pi / 2, "phase": np.pi } }, }, { "label": "Dur1", "duration": 2, "magnetic_flux_density": 3, "rotor_frequency": 0, "rotor_angle": 0.3, "transition_query": [{ "ch1": { "P": [3], "D": [-4] } }], }, { "label": "Spec1", "fraction": 1, "magnetic_flux_density": 4, "rotor_frequency": 0, "rotor_angle": 0.4, "transition_query": [{ "ch1": { "P": [4], "D": [-6] } }], }, ] }, ] const_mfd_rotor_ang_spec_dims = [ { "events": [ { "label": "Mix0", "mixing_query": { "ch1": { "tip_angle": np.pi / 2, "phase": np.pi } }, }, { "label": "Dur0", "duration": 1, "rotor_frequency": 0, "rotor_angle": 0.5, "transition_query": [{ "ch1": { "P": [0], "D": [0] } }], }, { "label": "Spec0", "fraction": 1, "rotor_frequency": 20000, "rotor_angle": 0.5, "transition_query": [{ "ch1": { "P": [1], "D": [0] } }], }, ] }, { "events": [ { "label": "Mix1", "mixing_query": { "ch1": { "tip_angle": np.pi / 2, "phase": np.pi } }, }, { "label": "Dur1", "duration": 2, "rotor_frequency": 0, "rotor_angle": 0.5, "transition_query": [{ "ch1": { "P": [3], "D": [0] } }], }, { "label": "Spec1", "fraction": 1, "rotor_frequency": 0, "rotor_angle": 0.5, "transition_query": [{ "ch1": { "P": [4], "D": [0] } }], }, ] }, ] method1 = Method( name="test-method-1", channels=["1H", "13C"], spectral_dimensions=all_defined_no_constant_spec_dims, ) # Constant 'magnetic_flux_density' and 'rotor_frequency' method2 = Method( name="test-method-2", channels=["1H", "13C"], spectral_dimensions=const_mfd_rotor_ang_spec_dims, ) assert method1.name == "test-method-1" assert len(method1.spectral_dimensions) == 2 basic_summary_tests(method1) assert method2.name == "test-method-2" assert len(method2.spectral_dimensions) == 2 args_summary_tests(method2) assert isinstance(method2.plot(), Figure)
def test_SSB_affine(): mth = SSB2D(channels=["13C"], rotor_frequency=1200) np.allclose(mth.affine_matrix, [1, -1, 0, 0]) assert Method.parse_dict_with_units(mth.json()) == mth
shifting_d = Method( name="Shifting-d", channels=["2H"], magnetic_flux_density=9.395, # in T rotor_frequency=0, # in Hz rotor_angle=0, # in Hz spectral_dimensions=[ SpectralDimension( count=512, spectral_width=2.5e5, # in Hz label="Quadrupolar frequency", events=[ SpectralEvent( transition_queries=[{"ch1": {"P": [-1]}}], freq_contrib=["Quad1_2"], ), MixingEvent(query="NoMixing"), ], ), SpectralDimension( count=256, spectral_width=2e5, # in Hz reference_offset=2e4, # in Hz label="Paramagnetic shift", events=[ SpectralEvent( transition_queries=[{"ch1": {"P": [-1]}}], freq_contrib=["Shielding1_0", "Shielding1_2"], ) ], ), ], )