def setup_simulator():
    site = Site(
        isotope="23Na",
        isotropic_chemical_shift=32,
        shielding_symmetric={
            "zeta": -120,
            "eta": 0.1
        },
        quadrupolar={
            "Cq": 1e5,
            "eta": 0.31,
            "beta": 5.12
        },
    )
    sys = SpinSystem(sites=[site], abundance=0.123)
    sim = Simulator()
    sim.spin_systems.append(sys)
    sim.methods.append(
        BlochDecayCTSpectrum(channels=["2H"], rotor_frequency=1e3))
    sim.methods.append(
        BlochDecaySpectrum(channels=["2H"], rotor_frequency=12.5e3))
    sim.methods.append(ThreeQ_VAS(channels=["27Al"]))
    sim.methods.append(SSB2D(channels=["17O"], rotor_frequency=35500))
    return sim
        "eta": 0.1
    },
)
sn117 = Site(
    isotope="117Sn",
    isotropic_chemical_shift=0,
)
j_sn = Coupling(
    site_index=[0, 1],
    isotropic_j=8150.0,
)

sn117_abundance = 7.68  # in %
spin_systems = [
    # uncoupled spin system
    SpinSystem(sites=[sn119], abundance=100 - sn117_abundance),
    # coupled spin systems
    SpinSystem(sites=[sn119, sn117],
               couplings=[j_sn],
               abundance=sn117_abundance),
]

# %%
# **Method**

# Get the spectral dimension parameters from the experiment.
spectral_dims = get_spectral_dimensions(experiment)

MAS = BlochDecaySpectrum(
    channels=["119Sn"],
    magnetic_flux_density=9.395,  # in T
예제 #3
0
ax.plot(experiment, "k", alpha=0.5)
ax.set_xlim(100, -100)
plt.grid()
plt.tight_layout()
plt.show()

# %%
# Create a fitting model
# ----------------------
# **Spin System**
B11 = Site(
    isotope="11B",
    isotropic_chemical_shift=20.0,  # in ppm
    quadrupolar=SymmetricTensor(Cq=2.3e6, eta=0.03),  # Cq in Hz
)
spin_systems = [SpinSystem(sites=[B11])]

# %%
# **Method**

# Get the spectral dimension parameters from the experiment.
spectral_dims = get_spectral_dimensions(experiment)

MAS_CT = BlochDecayCTSpectrum(
    channels=["11B"],
    magnetic_flux_density=14.1,  # in T
    rotor_frequency=12500,  # in Hz
    spectral_dimensions=spectral_dims,
    experiment=experiment,  # add the measurement to the method.
)
예제 #4
0
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
    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 = Method2D(
            channels=[ist],
            magnetic_flux_density=B0,  # in T
            spectral_dimensions=[
                {
                    "count": 64,
                    "spectral_width": 8e4,  # in Hz
                    "label": "Anisotropic dimension",
                    "events": [{
                        "rotor_angle": 90 * 3.14159 / 180
                    }],
                },
                # 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",
                },
            ],
            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=6)
예제 #5
0
def test_MQMAS():
    site = Site(
        isotope="87Rb",
        isotropic_chemical_shift=-9,
        shielding_symmetric={
            "zeta": 100,
            "eta": 0
        },
        quadrupolar={
            "Cq": 3.5e6,
            "eta": 0.36,
            "beta": 70 / 180 * np.pi
        },
    )
    spin_system = SpinSystem(sites=[site])

    method = Method2D(
        channels=["87Rb"],
        magnetic_flux_density=9.4,
        spectral_dimensions=[
            {
                "count": 128,
                "spectral_width": 20000,
                "events": [{
                    "transition_query": [{
                        "P": [-3],
                        "D": [0]
                    }]
                }],
            },
            {
                "count": 128,
                "spectral_width": 20000,
                "events": [{
                    "transition_query": [{
                        "P": [-1],
                        "D": [0]
                    }]
                }],
            },
        ],
    )

    sim = Simulator()
    sim.spin_systems = [spin_system]
    sim.methods = [method]
    sim.config.integration_volume = "hemisphere"
    sim.run()

    # process
    k = 21 / 27  # shear factor
    processor = sp.SignalProcessor(operations=[
        sp.IFFT(dim_index=1),
        aft.Shear(factor=-k, dim_index=1, parallel=0),
        aft.Scale(factor=1 + k, dim_index=1),
        sp.FFT(dim_index=1),
    ])
    processed_data = processor.apply_operations(
        data=sim.methods[0].simulation).real

    # Since there is a single site, after the shear and scaling transformations, there
    # should be a single perak along the isotropic dimension at index 70.
    # The isotropic coordinate of this peak is given by
    # w_iso = (17.8)*iso_shift + 1e6/8 * (vq/v0)^2 * (eta^2 / 3 + 1)
    # ref: D. Massiot et al. / Solid State Nuclear Magnetic Resonance 6 (1996) 73-83
    iso_slice = processed_data[40, :]
    assert np.argmax(iso_slice.y[0].components[0]) == 70

    # calculate the isotropic coordinate
    spin = method.channels[0].spin
    w0 = method.channels[0].gyromagnetic_ratio * 9.4 * 1e6
    wq = 3 * 3.5e6 / (2 * spin * (2 * spin - 1))
    w_iso = -9 * 17 / 8 + 1e6 / 8 * (wq / w0)**2 * ((0.36**2) / 3 + 1)

    # the coordinate from spectrum
    w_iso_spectrum = processed_data.x[1].coordinates[70].value
    np.testing.assert_almost_equal(w_iso, w_iso_spectrum, decimal=2)

    # The projection onto the  MAS dimension should be the 1D block decay central
    # transition spectrum
    mas_slice = processed_data.sum(axis=1).y[0].components[0]

    # MAS spectrum
    method = BlochDecayCTSpectrum(
        channels=["87Rb"],
        magnetic_flux_density=9.4,
        rotor_frequency=1e9,
        spectral_dimensions=[{
            "count": 128,
            "spectral_width": 20000
        }],
    )

    sim = Simulator()
    sim.spin_systems = [spin_system]
    sim.methods = [method]
    sim.config.integration_volume = "hemisphere"
    sim.run()

    data = sim.methods[0].simulation.y[0].components[0]
    np.testing.assert_almost_equal(data / data.max(),
                                   mas_slice / mas_slice.max(),
                                   decimal=2,
                                   err_msg="not equal")
예제 #6
0
# %%
# Generate the site and spin system objects.
sites = [
    Site(
        isotope="87Rb",
        isotropic_chemical_shift=16,  # in ppm
        quadrupolar=SymmetricTensor(Cq=5.3e6, eta=0.1),  # Cq in Hz
    ),
    Site(
        isotope="87Rb",
        isotropic_chemical_shift=40,  # in ppm
        quadrupolar=SymmetricTensor(Cq=2.6e6, eta=1.0),  # Cq in Hz
    ),
]
spin_systems = [SpinSystem(sites=[s]) for s in sites]

# %%
# Use the ``SSB2D`` method to simulate a PASS, MAT, QPASS, QMAT, or any equivalent
# sideband separation spectrum. Here, we use the method to generate a QMAT spectrum.
# The QMAT method is created from the ``SSB2D`` method in the same as a PASS or MAT
# method. The difference is that the observed channel is a half-integer quadrupolar
# spin instead of a spin I=1/2.
qmat = SSB2D(
    channels=["87Rb"],
    magnetic_flux_density=9.4,
    rotor_frequency=2604,
    spectral_dimensions=[
        dict(
            count=32 * 4,
            spectral_width=2604 * 32,  # in Hz
예제 #7
0
def test_2D():
    site_Ni = Site(
        isotope="2H",
        isotropic_chemical_shift=-97,  # in ppm
        shielding_symmetric=dict(
            zeta=-551,
            eta=0.12,
            alpha=62 * np.pi / 180,
            beta=114 * np.pi / 180,
            gamma=171 * np.pi / 180,
        ),
        quadrupolar=dict(Cq=77.2e3, eta=0.9),  # Cq in Hz
    )
    spin_system = SpinSystem(sites=[site_Ni])

    data = []
    for angle, n_gamma in zip([0, np.pi / 4], [1, 500]):
        shifting_d = Method(
            name="Shifting-d",
            channels=["2H"],
            magnetic_flux_density=9.395,  # in T
            rotor_frequency=0,  # in Hz
            rotor_angle=angle,  # 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"],
                        )
                    ],
                ),
            ],
        )

        sim = Simulator(spin_systems=[spin_system], methods=[shifting_d])
        sim.config.integration_volume = "hemisphere"
        sim.config.number_of_gamma_angles = n_gamma
        sim.run(auto_switch=False)

        res = sim.methods[0].simulation.y[0].components[0]
        data.append(res / res.max())

    # _, ax = plt.subplots(1, 2)
    # ax[0].imshow(data[0].real)
    # ax[1].imshow(data[1].real)
    # plt.show()

    np.testing.assert_almost_equal(data[0], data[1], decimal=1.8)
예제 #8
0
    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)
# Create a fitting model
# ----------------------
# **Guess model**
#
# Create a guess list of spin systems. For fitting the sideband profile at an isotropic
# chemical shift cross-section from PASS/MAT datasets, set the isotropic_chemical_shift
# parameter of the site object as zero.
site = Site(
    isotope="13C",
    isotropic_chemical_shift=0,  #
    shielding_symmetric={
        "zeta": -70,
        "eta": 0.8
    },
)
spin_systems = [SpinSystem(sites=[site])]

# %%
# **Method**
#
# For the sideband-only cross-section, use the BlochDecaySpectrum method.

# Get the dimension information from the experiment.
spectral_dims = get_spectral_dimensions(pass_cross_section)

PASS = BlochDecaySpectrum(
    channels=["13C"],
    magnetic_flux_density=9.395,  # in T
    rotor_frequency=1500,  # in Hz
    spectral_dimensions=spectral_dims,
    experiment=pass_cross_section,  # also add the measurement to the method.
예제 #10
0
Si29_2 = Site(
    isotope="29Si",
    isotropic_chemical_shift=-89.5,  # in ppm
    shielding_symmetric=SymmetricTensor(zeta=52.1, eta=0.68),  # zeta in ppm
)
Si29_3 = Site(
    isotope="29Si",
    isotropic_chemical_shift=-87.8,  # in ppm
    shielding_symmetric=SymmetricTensor(zeta=69.4, eta=0.60),  # zeta in ppm
)

# %%
# **Step 2:** Create the spin systems from these sites. Again, we create three
# single-site spin systems for better performance.
spin_systems = [
    SpinSystem(sites=[Si29_1]),
    SpinSystem(sites=[Si29_2]),
    SpinSystem(sites=[Si29_3]),
]

# %%
# **Step 3:** Create a Bloch decay spectrum method.
method = BlochDecaySpectrum(
    channels=["29Si"],
    magnetic_flux_density=14.1,  # in T
    rotor_frequency=1500,  # in Hz
    spectral_dimensions=[
        dict(
            count=2048,
            spectral_width=25000,  # in Hz
            reference_offset=-10000,  # in Hz
from mrsimulator import methods as NamedMethods
from mrsimulator import Simulator
from mrsimulator import SpinSystem
from mrsimulator.method import Method
from mrsimulator.methods import Method1D
from mrsimulator.methods import Method2D
from mrsimulator.utils.error import ImmutableEventError

__author__ = "Deepansh J. Srivastava"
__email__ = "*****@*****.**"

methods = [
    val for k, val in NamedMethods.__dict__.items() if isinstance(val, type)
]

sys = SpinSystem(sites=[{"isotope": "1H"}])


def test_read_write_methods():
    def assert_parsing(method, fn1):
        fn2 = method.parse_dict_with_units(fn1.json())
        assert fn1 == fn2, f"Error with {method} parse with units."

        fn3 = method(**fn1.json(units=False))
        assert fn1 == fn3, f"Error with {method} parse with units."

        event_error = "Event objects are immutable for"
        serialize = fn1.json()
        ent = serialize["spectral_dimensions"][0]["events"]
        ent[0]["transition_query"][0]["ch1"]["P"] = [-100]
예제 #12
0
def single_site_system_generator(
    isotope: Union[str, List[str]],
    isotropic_chemical_shift: Union[float, List[float], np.ndarray] = 0,
    shielding_symmetric: Dict = None,
    shielding_antisymmetric: Dict = None,
    quadrupolar: Dict = None,
    abundance: Union[float, List[float], np.ndarray] = None,
    site_name: Union[str, List[str]] = None,
    site_label: Union[str, List[str]] = None,
    site_description: Union[str, List[str]] = None,
    rtol: float = 1e-3,
) -> List[SpinSystem]:
    r"""Generate and return a list of single-site spin systems from the input parameters

    Args:
        isotope:
            A required string or a list of site isotopes.
        isotropic_chemical_shift:
            A float or a list/ndarray of isotropic chemical shifts per site per spin
            system. The default is 0.
        shielding_symmetric:
            A shielding symmetric dict object, where the keyword value can either
            be a float or a list/ndarray of floats. The default value is None. The
            allowed keywords are ``zeta``, ``eta``, ``alpha``, ``beta``, and ``gamma``.
        shielding_antisymmetric:
            A shielding antisymmetric dict object, where the keyword value can either
            be a float or a list/ndarray of floats. The default value is None. The
            allowed keywords are ``zeta``, ``alpha``, and ``beta``.
        quadrupolar:
            A quadrupolar dict object, where the keyword value can either be a float or
            a list/ndarray of floats. The default value is None. The allowed keywords
            are ``Cq``, ``eta``, ``alpha``, ``beta``, and ``gamma``.
        abundance:
            A float or a list/ndarray of floats describing the abundance of each spin
            system.
        site_name:
            A string or a list of strings with site names per site per spin system. The
            default is None.
        site_label:
            A string or a list of strings with site labels per site per spin system. The
            default is None.
        site_description:
            A string or a list of strings with site descriptions per site per spin
            system. The default is None.
        rtol:
            The relative tolerance used in determining the cutoff abundance, given as,
            :math:`\tt{abundance}_{\tt{cutoff}} = \tt{rtol} * \tt{max(abundance)}.`
            The spin systems with abundance below this threshold are ignored.

    Returns:
        List of :ref:`spin_sys_api` objects with a single :ref:`site_api`

    Example:
        **Single spin system:**

        >>> sys1 = single_site_system_generator(
        ...     isotope=["1H"],
        ...     isotropic_chemical_shift=10,
        ...     site_name="Single Proton",
        ... )
        >>> print(len(sys1))
        1

        **Multiple spin system:**

        >>> sys2 = single_site_system_generator(
        ...     isotope="1H",
        ...     isotropic_chemical_shift=[10] * 5,
        ...     site_name="5 Protons",
        ... )
        >>> print(len(sys2))
        5

        **Multiple spin system with dictionary arguments:**

        >>> Cq = [4.2e6] * 12
        >>> sys3 = single_site_system_generator(
        ...     isotope="17O",
        ...     isotropic_chemical_shift=60.0,  # in ppm,
        ...     quadrupolar={"Cq": Cq, "eta": 0.5},  # Cq in Hz
        ... )
        >>> print(len(sys3))
        12

    .. note::
        The parameter value can either be a float or a list/ndarray. If the parameter
        value is a float, the given value is assigned to the respective parameter in all
        the spin systems. If the parameter value is a list or ndarray, its `ith` value
        is assigned to the respective parameter of the `ith` spin system. When multiple
        parameter values are given as lists/ndarrays, the length of all the lists must
        be the same.
    """
    isotope = _flatten_item(isotope)
    isotropic_chemical_shift = _flatten_item(isotropic_chemical_shift)
    shielding_symmetric = _flatten_item(shielding_symmetric)
    shielding_antisymmetric = _flatten_item(shielding_antisymmetric)
    quadrupolar = _flatten_item(quadrupolar)
    site_name = _flatten_item(site_name)
    site_label = _flatten_item(site_label)
    site_description = _flatten_item(site_description)
    abundance = _flatten_item(abundance)
    args = [
        isotope,
        isotropic_chemical_shift,
        shielding_symmetric,
        shielding_antisymmetric,
        quadrupolar,
        site_name,
        site_label,
        site_description,
        abundance,
    ]

    n_sites = _check_lengths_of_args(*args)
    sites = _site_generator(n_sites, *args[:-1])  # Don't pass abundance

    if abundance is None:
        abundance = np.asarray([1 / n_sites] * n_sites)
    if isinstance(abundance, (int, float, np.floating)):
        abundance = np.asarray([abundance] * n_sites)

    keep_idxs = np.asarray(abundance > rtol * abundance.max()).nonzero()[0]

    return [
        SpinSystem(sites=[site], abundance=abd)
        for i, (site, abd) in enumerate(zip(sites, abundance))
        if i in keep_idxs
    ]
예제 #13
0
ax.set_xlim(600, -700)
plt.grid()
plt.tight_layout()
plt.show()

# %%
# Create a fitting model
# ----------------------
# **Spin System**
H_2 = Site(
    isotope="2H",
    isotropic_chemical_shift=-57.12,  # in ppm,
    quadrupolar=SymmetricTensor(Cq=3e4, eta=0.0),  # Cq in Hz
)

spin_systems = [SpinSystem(sites=[H_2])]

# %%
# **Method**

# Get the spectral dimension parameters from the experiment.
spectral_dims = get_spectral_dimensions(experiment)

MAS = BlochDecaySpectrum(
    channels=["2H"],
    magnetic_flux_density=9.395,  # in T
    rotor_frequency=4517.1,  # in Hz
    spectral_dimensions=spectral_dims,
    experiment=experiment,  # experimental dataset
)
예제 #14
0
def test_warnings():
    s = SpinSystem(sites=[Site(isotope="23Na")])
    m = Method(channels=["1H"], spectral_dimensions=[{}])
    assert m.get_transition_pathways(s) == []
# **Spin System**: The objective of a multi-data fitting is to optimize the spin
# system parameters using multiple datasets. In this example, we create two single-site
# spin systems, which are then shared by three method objects.
C1 = Site(
    isotope="13C",
    isotropic_chemical_shift=176.0,  # in ppm
    shielding_symmetric=SymmetricTensor(zeta=60, eta=0.6),  # zeta in Hz
)
C2 = Site(
    isotope="13C",
    isotropic_chemical_shift=43.0,  # in ppm
    shielding_symmetric=SymmetricTensor(zeta=30, eta=0.5),  # zeta in Hz
)

spin_systems = [
    SpinSystem(sites=[C1], name="C1"),
    SpinSystem(sites=[C2], name="C2")
]

# %%
# **Method**: Create the three MAS method objects with respective MAS spinning speeds.

# Get the spectral dimension parameters from the respective experiment and setup the
# corresponding method.

# Method for dataset 1
spectral_dims1 = get_spectral_dimensions(experiment1)
MAS1 = BlochDecaySpectrum(
    channels=["13C"],
    magnetic_flux_density=7.05,  # in T
    rotor_frequency=5000,  # in Hz
예제 #16
0
def test_bad_assignments():
    error = "value is not a valid list"
    with pytest.raises(ValidationError, match=f".*{error}.*"):
        SpinSystem(sites=Site())
예제 #17
0
        {"count": 2048, "spectral_width": "25 kHz", "reference_offset": "0 Hz",}
    ],
}
method2 = {
    "channels": ["1H"],
    "magnetic_flux_density": "9.4 T",
    "rotor_frequency": "1 kHz",
    "rotor_angle": "54.735 deg",
    "spectral_dimensions": [
        {"count": 2048, "spectral_width": "25 kHz", "reference_offset": "0 Hz",}
    ],
}


sim = Simulator()
sim.spin_systems = [SpinSystem.parse_dict_with_units(item) for item in spin_systems]
sim.methods = [
    BlochDecaySpectrum.parse_dict_with_units(method1),
    BlochDecaySpectrum.parse_dict_with_units(method2),
]

sim.run()

freq1, amp1 = sim.methods[0].simulation.to_list()
freq2, amp2 = sim.methods[1].simulation.to_list()

fig, ax = plt.subplots(1, 2, figsize=(6, 3))
ax[0].plot(freq1, amp1, linewidth=1.0, color="k")
ax[0].set_xlabel(f"frequency ratio / {freq2.unit}")
ax[0].grid(color="gray", linestyle="--", linewidth=0.5, alpha=0.5)
ax[0].set_title("Static")
# %%
# For demonstration, we will create two spin systems, one with a single site and other
# with two spin 1/2 sites.

S1 = Site(
    isotope="1H",
    isotropic_chemical_shift=10,  # in ppm
    shielding_symmetric=SymmetricTensor(zeta=-80, eta=0.25),  # zeta in ppm
)
S2 = Site(isotope="1H", isotropic_chemical_shift=-10)
S12 = Coupling(site_index=[0, 1],
               isotropic_j=100,
               dipolar=SymmetricTensor(D=2000, eta=0, alpha=0))

spin_system_1 = SpinSystem(sites=[S1], label="Uncoupled system")
spin_system_2 = SpinSystem(sites=[S1, S2],
                           couplings=[S12],
                           label="Coupled system")

# %%
# **Create a custom method**
#
# Writing a custom method is simply specifying an appropriate list of event objects per
# spectral dimension. In this example, we are interested in a one-dimensional Hahnecho
# method, and we use the generic `Method1D` class as a template. For a Hahnecho, we will
# use two types of Event objects---SpectralEvent and MixingEvent.
#
# A SpectralEvent object is where we sample the frequency contributions. The net
# frequency along a given spectral dimension is a weighted average of the frequencies
# from all SpectralEvent objects within a given SpectralDimension, i.e.,
예제 #19
0
def test_csa_01():
    site = Site(isotope="13C", shielding_symmetric={"zeta": 50, "eta": 0.5})
    spin_system = SpinSystem(sites=[site])
    setup_test(spin_system, volume="octant", sw=2.5e4)
예제 #20
0
import csdmpy as cp
import numpy as np
from mrsimulator import signal_processing as sp
from mrsimulator import Simulator
from mrsimulator import SpinSystem
from mrsimulator.methods import BlochDecaySpectrum

from .test_signal_processing import setup_read_write

__author__ = "Maxwell C. Venetos"
__email__ = "*****@*****.**"

sim = Simulator()
the_site = {"isotope": "1H", "isotropic_chemical_shift": "0 ppm"}
the_spin_system = {"name": "site A", "sites": [the_site], "abundance": "80%"}
spin_system_object = SpinSystem.parse_dict_with_units(the_spin_system)
sim.spin_systems += [
    spin_system_object, spin_system_object, spin_system_object
]
sim.config.decompose_spectrum = "spin_system"

sim.methods += [
    BlochDecaySpectrum(
        channels=["1H"],
        magnetic_flux_density=9.4,
        spectral_dimensions=[{
            "count": 65536,
            "spectral_width": 25000
        }],
    )
]
예제 #21
0
             isotropic_chemical_shift=58,
             quadrupolar={
                 "Cq": 5.16e6,
                 "eta": 0.292
             })

# all five sites.
sites = [O17_1, O17_2, O17_3, O17_4, O17_5]

# %%
# **Step 2:** Create the spin systems from these sites. For optimum performance, we
# create five single-site spin systems instead of a single five-site spin system. The
# abundance of each spin system is taken from above reference.
abundance = [0.83, 1.05, 2.16, 2.05, 1.90]
spin_systems = [
    SpinSystem(sites=[s], abundance=a) for s, a in zip(sites, abundance)
]

# %%
# **Step 3:** Create a central transition selective Bloch decay spectrum method.
method = BlochDecayCentralTransitionSpectrum(
    channels=["17O"],
    rotor_frequency=14000,  # in Hz
    spectral_dimensions=[{
        "count": 2048,
        "spectral_width": 50000,  # in Hz
        "label": r"$^{17}$O resonances",
    }],
)

# %%
예제 #22
0
ax.set_xlim(200, -200)
plt.grid()
plt.tight_layout()
plt.show()

# %%
# Create a fitting model
# ----------------------
# **Spin System**
P_31 = Site(
    isotope="31P",
    isotropic_chemical_shift=5.0,  # in ppm,
    shielding_symmetric=SymmetricTensor(zeta=-80, eta=0.5),  # zeta in Hz
)

spin_systems = [SpinSystem(sites=[P_31])]

# %%
# **Method**

# Get the spectral dimension parameters from the experiment.
spectral_dims = get_spectral_dimensions(experiment)

static1D = BlochDecaySpectrum(
    channels=["31P"],
    magnetic_flux_density=9.395,  # in T
    rotor_frequency=0,  # in Hz
    spectral_dimensions=spectral_dims,
    experiment=experiment,  # experimental dataset
)
예제 #23
0
def test_ThreeQ_VAS_spin_3halves():
    site = Site(
        isotope="87Rb",
        isotropic_chemical_shift=-9,
        shielding_symmetric={
            "zeta": 100,
            "eta": 0
        },
        quadrupolar={
            "Cq": 3.5e6,
            "eta": 0.36,
            "beta": 70 / 180 * np.pi
        },
    )
    spin_system = SpinSystem(sites=[site])

    method = ThreeQ_VAS(
        channels=["87Rb"],
        magnetic_flux_density=9.4,
        spectral_dimensions=[
            {
                "count": 1024,
                "spectral_width": 20000
            },
            {
                "count": 512,
                "spectral_width": 20000
            },
        ],
    )
    sim = Simulator()
    sim.spin_systems = [spin_system]
    sim.methods = [method]
    sim.config.integration_volume = "hemisphere"
    sim.run()

    data = sim.methods[0].simulation
    dat = data.y[0].components[0]
    index = np.where(dat == dat.max())[0]

    # The isotropic coordinate of this peak is given by
    # v_iso = (17/8)*iso_shift + 1e6/8 * (vq/v0)^2 * (eta^2 / 3 + 1)
    # ref: D. Massiot et al. / Solid State Nuclear Magnetic Resonance 6 (1996) 73-83
    spin = method.channels[0].spin
    v0 = method.channels[0].gyromagnetic_ratio * 9.4 * 1e6
    vq = (3 * 3.5e6) / (2 * spin * (2 * spin - 1))
    v_iso = -9 * 17 / 8 + 1e6 / 8 * ((vq / v0)**2) * ((0.36**2) / 3 + 1)

    # the coordinate from spectrum along the iso dimension must be equal to v_iso
    v_iso_spectrum = data.x[1].coordinates[index[0]].value
    np.testing.assert_almost_equal(v_iso, v_iso_spectrum, decimal=2)

    # The projection onto the  MAS dimension should be the 1D block decay central
    # transition spectrum
    mas_slice = data.sum(axis=1).y[0].components[0]

    # MAS spectrum
    method = BlochDecayCTSpectrum(
        channels=["87Rb"],
        magnetic_flux_density=9.4,
        rotor_frequency=1e9,
        spectral_dimensions=[{
            "count": 512,
            "spectral_width": 20000
        }],
    )

    sim = Simulator()
    sim.spin_systems = [spin_system]
    sim.methods = [method]
    sim.config.integration_volume = "hemisphere"
    sim.run()

    data = sim.methods[0].simulation.y[0].components[0]
    assert np.allclose(data / data.max(), mas_slice / mas_slice.max())
예제 #24
0
# investigation. For the current example, we know that Cuspidine is a crystalline silica
# polymorph with one crystallographic Si site. Therefore, our initial guess model is a
# single :math:`^{29}\text{Si}` site spin system. For non-linear fitting algorithms, as
# a general recommendation, the initial guess model parameters should be a good starting
# point for the algorithms to converge.

# the guess model comprising of a single site spin system
site = Site(
    isotope="29Si",
    isotropic_chemical_shift=-82.0,  # in ppm,
    shielding_symmetric=SymmetricTensor(zeta=-63, eta=0.4),  # zeta in ppm
)

spin_system = SpinSystem(
    name="Si Site",
    description="A 29Si site in cuspidine",
    sites=[site],  # from the above code
    abundance=100,
)

# %%
# **Step 2:** Create the method object.
#
# The method should be the same as the one used
# in the measurement. In this example, we use the `BlochDecaySpectrum` method. Note,
# when creating the method object, the value of the method parameters must match the
# respective values used in the experiment.
MAS = BlochDecaySpectrum(
    channels=["29Si"],
    magnetic_flux_density=7.1,  # in T
    rotor_frequency=780,  # in Hz
    spectral_dimensions=[
예제 #25
0
def test_MQMAS_spin_5halves():
    spin_system = SpinSystem(sites=[
        Site(
            isotope="27Al",
            isotropic_chemical_shift=64.5,  # in ppm
            quadrupolar={
                "Cq": 3.22e6,
                "eta": 0.66
            },  # Cq is in Hz
        )
    ])

    method = ThreeQ_VAS(
        channels=["27Al"],
        magnetic_flux_density=7,
        spectral_dimensions=[
            {
                "count": 1024,
                "spectral_width": 5000,
                "reference_offset": -3e3
            },
            {
                "count": 512,
                "spectral_width": 10000,
                "reference_offset": 4e3
            },
        ],
    )

    sim = Simulator()
    sim.spin_systems = [spin_system]
    sim.methods = [method]
    sim.run()

    data = sim.methods[0].simulation
    dat = data.y[0].components[0]
    index = np.where(dat == dat.max())[0]

    # The isotropic coordinate of this peak is given by
    # v_iso = -(17/31)*iso_shift + 8e6/93 * (vq/v0)^2 * (eta^2 / 3 + 1)
    # ref: D. Massiot et al. / Solid State Nuclear Magnetic Resonance 6 (1996) 73-83
    spin = method.channels[0].spin
    v0 = method.channels[0].gyromagnetic_ratio * 7 * 1e6
    vq = 3 * 3.22e6 / (2 * spin * (2 * spin - 1))
    v_iso = -(17 / 31) * 64.5 - (8e6 / 93) * (vq / v0)**2 * ((0.66**2) / 3 + 1)

    # the coordinate from spectrum along the iso dimension must be equal to v_iso
    v_iso_spectrum = data.x[1].coordinates[index[0]].value
    np.testing.assert_almost_equal(v_iso, v_iso_spectrum, decimal=2)

    # The projection onto the  MAS dimension should be the 1D block decay central
    # transition spectrum
    mas_slice = data.sum(axis=1).y[0].components[0]

    # MAS spectrum
    method = BlochDecayCTSpectrum(
        channels=["27Al"],
        magnetic_flux_density=7,
        rotor_frequency=1e9,
        spectral_dimensions=[{
            "count": 512,
            "spectral_width": 10000,
            "reference_offset": 4e3
        }],
    )

    sim = Simulator()
    sim.spin_systems = [spin_system]
    sim.methods = [method]
    sim.config.integration_volume = "hemisphere"
    sim.run()

    data = sim.methods[0].simulation.y[0].components[0]
    assert np.allclose(data / data.max(), mas_slice / mas_slice.max())
예제 #26
0
# %%
# Generate the site and spin system objects.
site = Site(
    isotope="87Rb",
    isotropic_chemical_shift=-9,  # in ppm
    shielding_symmetric=SymmetricTensor(zeta=110, eta=0),
    quadrupolar=SymmetricTensor(
        Cq=3.5e6,  # in Hz
        eta=0.36,
        alpha=0,  # in rads
        beta=70 * 3.14159 / 180,  # in rads
        gamma=0,  # in rads
    ),
)
spin_system = SpinSystem(sites=[site])

# %%
# Use the generic 2D method, `Method2D`, to simulate a COASTER spectrum by customizing
# the method parameters, as shown below. Note, the Method2D method simulates an infinite
# spinning speed spectrum.
coaster = Method2D(
    name="COASTER",
    channels=["87Rb"],
    magnetic_flux_density=9.4,  # in T
    rotor_angle=70.12 * 3.14159 / 180,  # in rads
    spectral_dimensions=[
        SpectralDimension(
            count=256,
            spectral_width=4e4,  # in Hz
            reference_offset=-8e3,  # in Hz
예제 #27
0
        "Cq": 4.2e6,
        "eta": 0.5
    },  # Cq in Hz
)

O2 = Site(
    isotope="17O",
    isotropic_chemical_shift=40.0,  # in ppm,
    quadrupolar={
        "Cq": 2.4e6,
        "eta": 0
    },  # Cq in Hz
)

spin_systems = [
    SpinSystem(sites=[O1], abundance=50, name="O1"),
    SpinSystem(sites=[O2], abundance=50, name="O2"),
]

# %%
# **Step 2:** Create the method object. Create an appropriate method object that closely
# resembles the technique used in acquiring the experimental data. The attribute values
# of this method must meet the experimental conditions, including the acquisition
# channels, the magnetic flux density, rotor angle, rotor frequency, and the
# spectral/spectroscopic dimension.
#
# In the following example, we set up a central transition selective Bloch decay
# spectrum method where the spectral/spectroscopic dimension information, i.e., count,
# spectral_width, and the reference_offset, is extracted from the CSDM dimension
# metadata using the :func:`~mrsimulator.utils.get_spectral_dimensions` utility
# function. The remaining attribute values are set to the experimental conditions.
예제 #28
0
def test_direct_init_spin_system():
    # test-1 # empty spin system
    the_spin_system = SpinSystem(sites=[],
                                 abundance=10,
                                 transition_pathways=None)

    assert the_spin_system.sites == []
    assert the_spin_system.abundance == 10.0
    assert the_spin_system.transition_pathways is None

    assert the_spin_system.json() == {"abundance": "10.0 %"}
    assert the_spin_system.json(units=False) == {
        "abundance": 10.0,
    }

    # test-2 # site
    test_site = Site(isotope="29Si", isotropic_chemical_shift=10)

    assert test_site.isotope.symbol == "29Si"
    assert test_site.isotropic_chemical_shift == 10.0
    assert test_site.property_units["isotropic_chemical_shift"] == "ppm"

    assert test_site.json() == {
        "isotope": "29Si",
        "isotropic_chemical_shift": "10.0 ppm",
    }
    assert test_site.json(units=False) == {
        "isotope": "29Si",
        "isotropic_chemical_shift": 10.0,
    }

    # test-3 # one site spin system
    the_spin_system = SpinSystem(sites=[test_site], abundance=10)
    assert isinstance(the_spin_system.sites[0], Site)
    assert the_spin_system.abundance == 10.0
    assert the_spin_system.json() == {
        "sites": [{
            "isotope": "29Si",
            "isotropic_chemical_shift": "10.0 ppm"
        }],
        "abundance": "10.0 %",
    }
    assert the_spin_system.json(units=False) == {
        "sites": [{
            "isotope": "29Si",
            "isotropic_chemical_shift": 10.0
        }],
        "abundance": 10,
    }

    # test-4 # two sites spin system
    the_spin_system = SpinSystem(sites=[test_site, test_site], abundance=10)
    assert isinstance(the_spin_system.sites[0], Site)
    assert isinstance(the_spin_system.sites[1], Site)
    assert id(the_spin_system.sites[0]) != id(the_spin_system.sites[1])
    assert the_spin_system.abundance == 10.0
    assert the_spin_system.json() == {
        "sites": [
            {
                "isotope": "29Si",
                "isotropic_chemical_shift": "10.0 ppm"
            },
            {
                "isotope": "29Si",
                "isotropic_chemical_shift": "10.0 ppm"
            },
        ],
        "abundance":
        "10.0 %",
    }
    assert the_spin_system.json(units=False) == {
        "sites": [
            {
                "isotope": "29Si",
                "isotropic_chemical_shift": 10.0
            },
            {
                "isotope": "29Si",
                "isotropic_chemical_shift": 10.0
            },
        ],
        "abundance":
        10,
    }

    # test-5 # coupling
    test_coupling = Coupling(site_index=[0, 1],
                             isotropic_j=10,
                             dipolar={"D": 100})

    assert test_coupling.site_index == [0, 1]
    assert test_coupling.isotropic_j == 10.0
    assert test_coupling.property_units["isotropic_j"] == "Hz"

    assert test_coupling.dipolar.D == 100.0
    assert test_coupling.dipolar.property_units["D"] == "Hz"

    assert test_coupling.json() == {
        "site_index": [0, 1],
        "isotropic_j": "10.0 Hz",
        "dipolar": {
            "D": "100.0 Hz"
        },
    }
    assert test_coupling.json(units=False) == {
        "site_index": [0, 1],
        "isotropic_j": 10.0,
        "dipolar": {
            "D": 100.0
        },
    }

    # test-6 #  two sites and one coupling spin system
    the_spin_system = SpinSystem(sites=[test_site, test_site],
                                 couplings=[test_coupling],
                                 abundance=10)
    assert isinstance(the_spin_system.sites[0], Site)
    assert isinstance(the_spin_system.sites[1], Site)
    assert isinstance(the_spin_system.couplings[0], Coupling)
    assert id(the_spin_system.sites[0]) != id(the_spin_system.sites[1])
    assert the_spin_system.abundance == 10.0
    assert the_spin_system.json() == {
        "sites": [
            {
                "isotope": "29Si",
                "isotropic_chemical_shift": "10.0 ppm"
            },
            {
                "isotope": "29Si",
                "isotropic_chemical_shift": "10.0 ppm"
            },
        ],
        "couplings": [{
            "site_index": [0, 1],
            "isotropic_j": "10.0 Hz",
            "dipolar": {
                "D": "100.0 Hz"
            },
        }],
        "abundance":
        "10.0 %",
    }
    assert the_spin_system.json(units=False) == {
        "sites": [
            {
                "isotope": "29Si",
                "isotropic_chemical_shift": 10.0
            },
            {
                "isotope": "29Si",
                "isotropic_chemical_shift": 10.0
            },
        ],
        "couplings": [{
            "site_index": [0, 1],
            "isotropic_j": 10.0,
            "dipolar": {
                "D": 100.0
            }
        }],
        "abundance":
        10,
    }

    # test-5
    the_spin_system = SpinSystem(
        name="Just a test",
        description="The same",
        sites=[
            {
                "isotope": "1H",
                "isotropic_chemical_shift": 0
            },
            {
                "isotope": "17O",
                "isotropic_chemical_shift": -10,
                "quadrupolar": {
                    "Cq": 5.1e6,
                    "eta": 0.5
                },
            },
        ],
        couplings=[{
            "site_index": [0, 1],
            "isotropic_j": 34
        }],
        abundance=4.23,
    )
    assert the_spin_system.name == "Just a test"
    assert the_spin_system.description == "The same"
    assert the_spin_system.sites[0].isotope.symbol == "1H"
    assert the_spin_system.sites[0].isotropic_chemical_shift == 0
    assert the_spin_system.sites[1].isotope.symbol == "17O"
    assert the_spin_system.sites[1].isotropic_chemical_shift == -10
    assert the_spin_system.sites[1].quadrupolar.Cq == 5.1e6
    assert the_spin_system.sites[1].quadrupolar.eta == 0.5
    assert the_spin_system.couplings[0].site_index == [0, 1]
    assert the_spin_system.couplings[0].isotropic_j == 34.0
    assert the_spin_system.abundance == 4.23

    serialize = the_spin_system.json()
    assert serialize == {
        "name":
        "Just a test",
        "description":
        "The same",
        "sites": [
            {
                "isotope": "1H",
                "isotropic_chemical_shift": "0.0 ppm"
            },
            {
                "isotope": "17O",
                "isotropic_chemical_shift": "-10.0 ppm",
                "quadrupolar": {
                    "Cq": "5100000.0 Hz",
                    "eta": 0.5
                },
            },
        ],
        "couplings": [{
            "site_index": [0, 1],
            "isotropic_j": "34.0 Hz"
        }],
        "abundance":
        "4.23 %",
    }
    assert the_spin_system == SpinSystem.parse_dict_with_units(serialize)

    json_no_unit = the_spin_system.json(units=False)
    assert json_no_unit == {
        "name":
        "Just a test",
        "description":
        "The same",
        "sites": [
            {
                "isotope": "1H",
                "isotropic_chemical_shift": 0
            },
            {
                "isotope": "17O",
                "isotropic_chemical_shift": -10.0,
                "quadrupolar": {
                    "Cq": 5100000,
                    "eta": 0.5
                },
            },
        ],
        "couplings": [{
            "site_index": [0, 1],
            "isotropic_j": 34.0
        }],
        "abundance":
        4.23,
    }
    assert the_spin_system == SpinSystem(**json_no_unit)
예제 #29
0
def test_warnings():
    s = SpinSystem(sites=[Site(isotope="23Na")])
    m = Method1D(channels=["1H"])
    assert m.get_transition_pathways(s) == []
예제 #30
0
def get_spin_system_list():
    isotopes = [
        "19F", "31P", "2H", "6Li", "14N", "27Al", "25Mg", "45Sc", "87Sr"
    ]
    return SpinSystem(sites=[Site(isotope=item) for item in isotopes])