def test_5Q_VAS_general(): """5Q-VAS method test""" mth = FiveQ_VAS( channels=["17O"], spectral_dimensions=[SpectralDimension(), SpectralDimension()] ) assert mth.name == "FiveQ_VAS" assert mth.description == "Simulate a 5Q variable-angle spinning spectrum." assert mth.spectral_dimensions[0].events[0].transition_queries == [ TransitionQuery(ch1={"P": [-5], "D": [0]}) ] assert mth.spectral_dimensions[1].events[0].transition_queries == [ TransitionQuery(ch1={"P": [-1], "D": [0]}) ] assert FiveQ_VAS.parse_dict_with_units(mth.json()) == mth assert np.allclose( mth.affine_matrix, [0.3243243243243243, 0.6756756756756757, 0.0, 1.0] ) serialize = mth.json() _ = serialize.pop("affine_matrix") assert serialize == { "channels": ["17O"], "description": "Simulate a 5Q variable-angle spinning spectrum.", "name": "FiveQ_VAS", **sample_test_output(-5), }
def check_event_objects_for_compatibility(cls, default_dim, obj_dim, method_dict): """Checks Events for compatibility and sets global method attributes Args: default_dim (dict): Dict representation of SpectralDimension in base method obj_dim (SpectralDimension): User-passed SpectralDimension object to check method_dict (dict): Dict representation of passed method """ required = ["magnetic_flux_density", "rotor_frequency", "rotor_angle"] check_dim = SpectralDimension(**default_dim) for i, (ev_check, ev_obj) in enumerate(zip(check_dim.events, obj_dim.events)): default_obj = SpectralDimension(events=[{}]).events[0] obj_keys = ev_obj.dict(exclude={"property_units"}).keys() check_keys = default_dim["events"][i].keys() for k in obj_keys: # iterate over event attributes fail = False if k in check_keys: obj_attr, default_attr, check_attr = (getattr( _, k) for _ in [ev_obj, default_obj, ev_check]) fail_1 = obj_attr != default_attr # not default (user passed value) fail_2 = obj_attr != check_attr # passed attr does not match base fail_3 = default_attr is not None fail = fail_1 and fail_2 and fail_3 setattr(ev_obj, k, check_attr) elif k in required and k in method_dict: # True if passed attr does not match global attr defined by method fail = getattr(ev_obj, k) != method_dict[k] # Set event attr to global method attr setattr(ev_obj, k, method_dict[k]) if fail: raise ImmutableEventError(cls.__name__)
def assertion(csdm, res, test_ref=""): assert get_spectral_dimensions(csdm)[0] == res, f"failed ref {test_ref}" csdm_coordinates = csdm.x[0].coordinates.to("Hz").value if csdm.x[0].increment < 0: csdm_coordinates = csdm_coordinates[::-1] spectral_dimension = SpectralDimension(**res) mrsim_coordinates = spectral_dimension.coordinates_Hz() assert np.allclose(csdm_coordinates, mrsim_coordinates), f"failed ref {test_ref}"
def test_BaseNamedMethod1D_spectral_dimension_count(): e = "Method requires exactly 1 spectral dimensions, given 2." # test for SpectralDimension passed as dictionary with pytest.raises(ValueError, match=f".*{e}.*"): BaseNamedMethod1D(spectral_dimensions=[{}, {}]) # test for SpectralDimension passed as object with pytest.raises(ValueError, match=f".*{e}.*"): BaseNamedMethod1D(spectral_dimensions=[ SpectralDimension(), SpectralDimension(), ])
def csa_1D_projection(): csa_only = Method( channels=["87Rb"], magnetic_flux_density=9.4, # in T rotor_angle=70.12 * np.pi / 180, # in rads rotor_frequency=np.inf, spectral_dimensions=[ SpectralDimension( count=512, spectral_width=4e4, reference_offset=-8e3, events=[ SpectralEvent( freq_contrib=[ "Quad2_0", "Shielding1_0", "Shielding1_2" ], transition_queries=[{ "ch1": { "P": [3], "D": [0] } }], ), ], ) ], ) return process_spectrum(csa_only)
def test_BaseNamedMethod2D_spectral_dimension_count(): e = "Method requires exactly 2 spectral dimensions, given 1." # test for SpectralDimension passed as dictionary with pytest.raises(ValueError, match=f".*{e}.*"): BaseNamedMethod2D(channels=["1H"], spectral_dimensions=[{}]) # test for SpectralDimension passed as object with pytest.raises(ValueError, match=f".*{e}.*"): BaseNamedMethod2D(channels=["1H"], spectral_dimensions=[SpectralDimension()])
def coaster_simulation(): coaster = Method( name="COASTER", channels=["87Rb"], magnetic_flux_density=9.4, # in T rotor_angle=70.12 * np.pi / 180, # in rads rotor_frequency=np.inf, spectral_dimensions=[ SpectralDimension( count=512, spectral_width=4e4, # in Hz reference_offset=-8e3, # in Hz label="$\\omega_1$ (CSA)", events=[ SpectralEvent(transition_queries=[{ "ch1": { "P": [3], "D": [0] } }]), MixingEvent(query={"ch1": { "angle": np.pi * 109.5 / 180 }}), ], ), SpectralDimension( count=512, spectral_width=8e3, # in Hz reference_offset=-4e3, # in Hz label="$\\omega_2$ (Q)", events=[ SpectralEvent(transition_queries=[{ "ch1": { "P": [-1], "D": [0] } }]) ], ), ], affine_matrix=[[1, 0], [1 / 4, 3 / 4]], ) return process_spectrum(coaster)
def check_event_objects_for_compatibility(cls, py, obj, obj_dict): required = ["magnetic_flux_density", "rotor_frequency", "rotor_angle"] py_obj = SpectralDimension(**py) for i, (ev_py, ev_obj) in enumerate(zip(py_obj.events, obj.events)): default_obj = SpectralDimension(events=[{}]).events[0] obj_keys = ev_obj.dict(exclude={"property_units"}).keys() py_keys = py["events"][i].keys() for k in obj_keys: a = False if k in py_keys: a1, a2, a3 = [getattr(_, k) for _ in [ev_obj, default_obj, ev_py]] a = a1 != a2 and a1 != a3 and a2 is not None setattr(ev_obj, k, a3) elif k in required and k in obj_dict: a = getattr(ev_obj, k) != obj_dict[k] setattr(ev_obj, k, obj_dict[k]) if a: raise ImmutableEventError(cls.__name__)
def contrib_method(contrib): return Method( channels=["1H"], magnetic_flux_density=9.4, # in T spectral_dimensions=[ SpectralDimension( count=512, spectral_width=2e4, events=[ SpectralEvent(freq_contrib=contrib, transition_queries=negative_sq_tq) ], ) ], )
def test_empty_spec_dims(): # Empty list empty_method = Method(channels=["1H"], spectral_dimensions=[]) error = ( r".*Method has empty spectral_dimensions. At least one SpectralDimension " r"is needed with at least one Event..*") with pytest.raises(AttributeError, match=error): empty_method.summary() # No events empty_method.spectral_dimensions = [SpectralDimension(events=[])] error = (r".*Method has no Events. At least one SpectralDimension " r"is needed with at least one Event..*") with pytest.raises(AttributeError, match=error): empty_method.summary()
def test_rotor_frequency(): """Ensures only 1 non-zero finite spinning speed in method""" # Good method, should not throw error Method( channels=["1H"], spectral_dimensions=[ SpectralDimension(events=[ SpectralEvent(fraction=0.5, rotor_frequency=123), SpectralEvent(fraction=0.5, rotor_frequency=0), ]), SpectralDimension(events=[SpectralEvent(rotor_frequency=np.inf)]), ], ) # Bad method, should throw error for multiple finite speeds for cls in [Method]: with pytest.raises(NotImplementedError): cls( channels=["1H"], spectral_dimensions=[ SpectralDimension(events=[ SpectralEvent(fraction=0.5, rotor_frequency=123), SpectralEvent(fraction=0.5, rotor_frequency=456), ]) ], ) with pytest.raises(NotImplementedError): Method( channels=["1H"], spectral_dimensions=[ SpectralDimension(events=[ SpectralEvent(fraction=0.5, rotor_frequency=123), SpectralEvent(fraction=0.5, rotor_frequency=np.inf), ]), SpectralDimension(events=[ SpectralEvent(fraction=0.5, rotor_frequency=0), SpectralEvent(fraction=0.5, rotor_frequency=456), ]), ], ) with pytest.raises(NotImplementedError): # Both events should take 10000 Hz rotor_frequency Method( channels=["27Al"], rotor_frequency=10000, spectral_dimensions=[ SpectralDimension(events=[ SpectralEvent(fraction=0.5), SpectralEvent(fraction=0.5) ]) ], )
def quad_1D_projection(): quad_only = Method( channels=["87Rb"], magnetic_flux_density=9.4, # in T rotor_angle=70.12 * np.pi / 180, # in rads rotor_frequency=np.inf, spectral_dimensions=[ SpectralDimension( count=512, spectral_width=8e3, reference_offset=-4e3, events=[ SpectralEvent( fraction=1 / 4, freq_contrib=["Quad2_0"], transition_queries=[{ "ch1": { "P": [3], "D": [0] } }], ), MixingEvent(query={ "ch1": { "angle": np.pi * 109.5 / 180, "phase": 0 } }), SpectralEvent( fraction=3 / 4, freq_contrib=["Quad2_0", "Quad2_2"], transition_queries=[{ "ch1": { "P": [-1], "D": [0] } }], ), ], ) ], ) return process_spectrum(quad_only)
def hahn_method(): return Method( channels=["1H"], magnetic_flux_density=9.4, # in T rotor_angle=0, # in rads spectral_dimensions=[ SpectralDimension( count=512, spectral_width=2e4, # in Hz events=[ SpectralEvent(fraction=0.5, transition_queries=positive_sq_tq), MixingEvent(query={"ch1": { "angle": np.pi, "phase": 0 }}), SpectralEvent(fraction=0.5, transition_queries=negative_sq_tq), ], ) ], )
def check_when_arg_is_object(cls, method_dict): default_method = cls.update(**method_dict) default_sp = default_method["spectral_dimensions"] obj_sp = method_dict["spectral_dimensions"] for i, (dflt_dim, obj_dim) in enumerate(zip(default_sp, obj_sp)): if len(dflt_dim["events"]) != len( obj_dim.events) and obj_dim.events != []: raise ImmutableEventError(cls.__name__) if obj_dim.events == []: obj_sp[i] = obj_dim.json(units=False) if "events" not in obj_sp[i]: obj_sp[i]["events"] = dflt_dim["events"] obj_sp[i] = SpectralDimension(**obj_sp[i]) cls.check_event_objects_for_compatibility(dflt_dim, obj_dim, method_dict) for k, v in default_method.items(): if k not in method_dict: method_dict[k] = v
def test_mixing_query_connect_map(): MX1 = MixingEvent(mixing_query={"ch1": {"tip_angle": 0.12}}) MX2 = MixingEvent(mixing_query={"ch2": {"tip_angle": 1.12}}) spectral_dimmensions = [ SpectralDimension(events=[ { "fraction": 0.5 }, # 0 MX1, { "duration": 0.5 }, # 1 { "fraction": 0.5 }, # 2 MX2, { "duration": 0.5 }, # 3 ]), SpectralDimension(events=[ MX1, MX2, { "duration": 0.5 }, # 4 MX2, { "duration": 0.5 }, # 5 { "fraction": 1 }, # 2 ]), ] res = mixing_query_connect_map(spectral_dimmensions) assert res == [ { "mixing_query": MX1.mixing_query, "near_index": [0, 1] }, { "mixing_query": MX2.mixing_query, "near_index": [2, 3] }, { "mixing_query": MX1.mixing_query, "near_index": [3, 4] }, { "mixing_query": MX2.mixing_query, "near_index": [3, 4] }, { "mixing_query": MX2.mixing_query, "near_index": [4, 5] }, ] error = "SpectralDimension requires at least one SpectralEvent" with pytest.raises(MissingSpectralEventError, match=f".*{error}.*"): SpectralDimension( events=[MX1, MX2, { "duration": 0.5 }, MX2, { "duration": 0.5 }])
def basic_method_tests(the_method): assert the_method != "r" assert the_method.name == "test-1-d" the_method.name = "test worked" assert the_method.name == "test worked" assert the_method.description == "Test-1" the_method.description = "test worked again" assert the_method.description == "test worked again" # spectral width test assert the_method.channels == [Isotope(symbol="29Si")] the_method.channels = ["1H", "17O"] assert the_method.channels == [Isotope(symbol="1H"), Isotope(symbol="17O")] with pytest.raises(ValidationError, match=".*value is not a valid list.*"): the_method.channels = "6Li" dimension = SpectralDimension.parse_dict_with_units(dimension_dictionary) assert the_method.spectral_dimensions[0] == dimension the_method2 = deepcopy(the_method) the_method2.affine_matrix = [1] assert the_method2 != the_method # json() evt = [{"fraction": 0.5, "transition_query": [{"ch1": {"P": [-1]}}]}] * 2 serialize = { "name": "test worked", "description": "test worked again", "channels": ["1H", "17O"], "magnetic_flux_density": "9.6 T", "rotor_frequency": "1000.0 Hz", "rotor_angle": "0.9553059660790962 rad", "spectral_dimensions": [{ "count": 1024, "spectral_width": "100.0 Hz", "events": evt, }], } assert the_method.json() == serialize # json(units=False) assert the_method.json(units=False) == { "name": "test worked", "description": "test worked again", "channels": ["1H", "17O"], "magnetic_flux_density": 9.6, "rotor_frequency": 1000.0, "rotor_angle": 0.9553059660790962, "spectral_dimensions": [{ "count": 1024, "spectral_width": 100.0, "events": evt, }], }
channels=["17O"], magnetic_flux_density=11.744, # in T spectral_dimensions=[ SpectralDimension( **spectral_dims[0], events=[ SpectralEvent( fraction=0.5, rotor_angle=37.38 * 3.14159 / 180, transition_query=[{ "ch1": { "P": [-1], "D": [0] } }], ), SpectralEvent( fraction=0.5, rotor_angle=79.19 * 3.14159 / 180, transition_query=[{ "ch1": { "P": [-1], "D": [0] } }], ), ], ), # The last spectral dimension block is the direct-dimension SpectralDimension( **spectral_dims[1],
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)
) for beta in beta_orientation ] # %% # Next, we create methods to simulate the sideband manifolds for the above spin # systems at four spinning rates: 3 kHz, 5 kHz, 8 kHz, 12 kHz. spin_rates = [3e3, 5e3, 8e3, 12e3] # in Hz # The variable `methods` is a list of four BlochDecaySpectrum methods. methods = [ BlochDecaySpectrum( channels=["13C"], magnetic_flux_density=9.4, # in T rotor_frequency=vr, # in Hz spectral_dimensions=[SpectralDimension(count=2048, spectral_width=8.0e4)], ) for vr in spin_rates ] # %% # Create the Simulator object and add the method and the spin system objects. sim = Simulator(spin_systems=spin_systems, methods=methods) sim.config.integration_volume = "hemisphere" # set averaging to hemisphere # config to decompose spectrum to individual spin systems. sim.config.decompose_spectrum = "spin_system" # %% # The run command will simulate twelve spectra corresponding to the three spin systems # evaluated at four different methods (spinning speeds). sim.run()
# 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 label="3Q dimension", events=[ SpectralEvent(transition_query=[{ "ch1": { "P": [3], "D": [0] } }]) ], ), # The last spectral dimension block is the direct-dimension SpectralDimension( count=256, spectral_width=2e4, # in Hz reference_offset=-3e3, # in Hz label="70.12 dimension", events=[ SpectralEvent(transition_query=[{ "ch1": {
quadrupolar=SymmetricTensor(Cq=1.72e6, eta=0.5), # Cq is in Hz ) sites = [Rb87_1, Rb87_2, Rb87_3] # all sites spin_systems = [SpinSystem(sites=[s]) for s in sites] # %% # Select a Triple Quantum variable-angle spinning method. You may optionally # provide a `rotor_angle` to the method. The default `rotor_angle` is the magic-angle. method = ThreeQ_VAS( channels=["87Rb"], magnetic_flux_density=9.4, # in T spectral_dimensions=[ SpectralDimension( count=128, spectral_width=7e3, # in Hz reference_offset=-7e3, # in Hz label="Isotropic dimension", ), SpectralDimension( count=256, spectral_width=1e4, # in Hz reference_offset=-4e3, # in Hz label="MAS dimension", ), ], ) # A graphical representation of the method object. plt.figure(figsize=(5, 2.5)) method.plot() plt.show()
hahn_echo = Method1D( channels=["1H"], magnetic_flux_density=9.4, # in T spectral_dimensions=[ SpectralDimension( count=512, spectral_width=2e4, # in Hz events=[ SpectralEvent(fraction=0.5, transition_query=[{ "ch1": { "P": [1] } }]), MixingEvent( mixing_query={"ch1": { "tip_angle": np.pi, "phase": 0 }}), SpectralEvent(fraction=0.5, transition_query=[{ "ch1": { "P": [-1] } }]), ], ) ], ) # %%
# method parameters, as shown below. Note, the Method2D method simulates an infinite # spinning speed spectrum. das = Method2D( name="Dynamic Angle Spinning", channels=["17O"], magnetic_flux_density=11.74, # in T spectral_dimensions=[ SpectralDimension( count=256, spectral_width=5e3, # in Hz reference_offset=0, # in Hz label="DAS isotropic dimension", events=[ SpectralEvent( fraction=0.5, rotor_angle=37.38 * 3.14159 / 180, transition_query=[{"ch1": {"P": [-1], "D": [0]}}], ), SpectralEvent( fraction=0.5, rotor_angle=79.19 * 3.14159 / 180, transition_query=[{"ch1": {"P": [-1], "D": [0]}}], ), ], ), # The last spectral dimension block is the direct-dimension SpectralDimension( count=256, spectral_width=2e4, # in Hz reference_offset=0, # in Hz label="MAS dimension", events=[
# transitions to the central transition. Note, STMAS measurements are highly suspectable # to rotor angle mismatch. In the following, we show two methods, the first at the # magic angle and second deliberately miss-sets by approximately 0.0059 degrees. angles = [54.7359, 54.73] method = [] for angle in angles: method.append( ST1_VAS( channels=["87Rb"], magnetic_flux_density=7, # in T rotor_angle=angle * 3.14159 / 180, # in rad (magic angle) spectral_dimensions=[ SpectralDimension( count=256, spectral_width=3e3, # in Hz reference_offset=-2.4e3, # in Hz label="Isotropic dimension", ), SpectralDimension( count=512, spectral_width=5e3, # in Hz reference_offset=-4e3, # in Hz label="MAS dimension", ), ], )) # A graphical representation of the method object. plt.figure(figsize=(5, 2.5)) method[0].plot() plt.show()
isotope="29Si", isotropic_chemical_shift=iso, shielding_symmetric={"zeta": zeta, "eta": eta}, abundance=pdf, ) # %% # **Method:** # # Let's also create a Bloch decay spectrum method. method = BlochDecaySpectrum( channels=["29Si"], rotor_frequency=0, # in Hz rotor_angle=0, # in rads spectral_dimensions=[ SpectralDimension(spectral_width=25000, reference_offset=-7000) # values in Hz ], ) # %% # The above method simulates a static :math:`^{29}\text{Si}` spectrum at 9.4 T field # (default value). # # **Simulator:** # # Now that we have the spin systems and the method, create the simulator object and # add the respective objects. sim = Simulator(spin_systems=spin_systems, methods=[method]) # %% # Static spectrum
"Cq": Cq * 1e6, "eta": eta }, # Cq in Hz abundance=pdf, ) # %% # Static spectrum # --------------- # Observe the static :math:`^{27}\text{Al}` NMR spectrum simulation. First, # create a central transition selective Bloch decay spectrum method. static_method = BlochDecayCTSpectrum( channels=["27Al"], rotor_frequency=0, # in Hz rotor_angle=0, # in rads spectral_dimensions=[SpectralDimension(spectral_width=80000)], ) # %% # Create the simulator object and add the spin systems and method. sim = Simulator(spin_systems=spin_systems, methods=[static_method]) sim.run() # %% # The plot of the corresponding spectrum. plt.figure(figsize=(4.25, 3.0)) ax = plt.subplot(projection="csdm") ax.plot(sim.methods[0].simulation.real, color="black", linewidth=1) ax.invert_xaxis() plt.tight_layout() plt.show()
rotor_frequency=np.inf, spectral_dimensions=[ SpectralDimension( **spectral_dims[0], events=[ SpectralEvent( fraction=0.5, rotor_angle=37.38 * np.pi / 180, # in rads transition_queries=[{ "ch1": { "P": [-1], "D": [0] } }], ), MixingEvent(query="NoMixing"), SpectralEvent( fraction=0.5, rotor_angle=79.19 * np.pi / 180, # in rads transition_queries=[{ "ch1": { "P": [-1], "D": [0] } }], ), MixingEvent(query="NoMixing"), ], ), # The last spectral dimension block is the direct-dimension SpectralDimension(
def test_mixing_query_connect_map(): MX1 = MixingEvent(query={"ch1": {"angle": 0.12}}) MX2 = MixingEvent(query={"ch2": {"angle": 1.12}}) TOTAL_MX = MixingEvent(query="TotalMixing") # Use MixingEvents with non-enum queries spectral_dimensions = [ SpectralDimension(events=[ { "fraction": 0.5 }, # 0 MX1, { "duration": 0.5 }, # 1 { "fraction": 0.5 }, # 2 MX2, { "duration": 0.5 }, # 3 ]), SpectralDimension(events=[ MX1, MX2, { "duration": 0.5 }, # 4 MX2, { "duration": 0.5 }, # 5 { "fraction": 1 }, # 6 ]), ] res = mixing_query_connect_map(spectral_dimensions) assert res == [ { "mixing_query_list": [MX1.query], "near_index": [0, 1] }, { "mixing_query_list": [MX2.query], "near_index": [2, 3] }, { "mixing_query_list": [MX1.query, MX2.query], "near_index": [3, 4] }, { "mixing_query_list": [MX2.query], "near_index": [4, 5] }, ] # Combination of MixingEvents with dict queries and enum queries (total mixing) spectral_dimensions = [ SpectralDimension(events=[ # Connect all, should return no list { "fraction": 0.5 }, # 0 TOTAL_MX, { "duration": 0.5 }, # 1 # Just MX1 { "fraction": 0.5 }, # 2 TOTAL_MX, MX1, { "duration": 0.5 }, # 3 ]), SpectralDimension(events=[ # MX1 and MX2 { "fraction": 0.5 }, # 4 MX1, TOTAL_MX, MX2, { "duration": 0.5 }, # 5 # MX1, MX2, MX1 { "fraction": 0.5 }, # 6 MX1, TOTAL_MX, MX2, MX1, TOTAL_MX, { "duration": 0.5 }, # 7 ]), ] res = mixing_query_connect_map(spectral_dimensions) assert res == [ { "mixing_query_list": [MX1.query], "near_index": [2, 3] }, { "mixing_query_list": [MX1.query, MX2.query], "near_index": [4, 5] }, { "mixing_query_list": [MX1.query, MX2.query, MX1.query], "near_index": [6, 7] }, ] error = "SpectralDimension requires at least one SpectralEvent" with pytest.raises(MissingSpectralEventError, match=f".*{error}.*"): SpectralDimension( events=[MX1, MX2, { "duration": 0.5 }, MX2, { "duration": 0.5 }])
# SpectralEvent. A no mixing query is equivalent to a rotation query where each # channel has a zero phase and angle. Since all spin systems in this example have a # single site, defining no mixing between the two spectral events is superfluous. # We include it such that the method is applicable with multi-site spin systems. maf = Method( name="Magic Angle Flipping", channels=["29Si"], magnetic_flux_density=14.1, # in T rotor_frequency=np.inf, spectral_dimensions=[ SpectralDimension( count=128, spectral_width=2e4, # in Hz label="Anisotropic dimension", events=[ SpectralEvent( rotor_angle=90 * np.pi / 180, # in rads transition_queries=[{"ch1": {"P": [-1], "D": [0]}}], ), MixingEvent(query="NoMixing"), ], ), SpectralDimension( count=128, spectral_width=3e3, # in Hz reference_offset=-1.05e4, # in Hz label="Isotropic dimension", events=[ SpectralEvent( rotor_angle=54.735 * np.pi / 180, # in rads transition_queries=[{"ch1": {"P": [-1], "D": [0]}}], )
# Use the generic 2D method, `Method2D`, to simulate a Magic-Angle Flipping (MAF) # spectrum by customizing the method parameters, as shown below. Note, the Method2D # method simulates an infinite spinning speed spectrum. maf = Method2D( name="Magic Angle Flipping", channels=["29Si"], magnetic_flux_density=14.1, # in T spectral_dimensions=[ SpectralDimension( count=128, spectral_width=2e4, # in Hz label="Anisotropic dimension", events=[ SpectralEvent( rotor_angle=90 * 3.14159 / 180, transition_query=[{ "ch1": { "P": [-1], "D": [0] } }], ) ], ), SpectralDimension( count=128, spectral_width=3e3, # in Hz reference_offset=-1.05e4, # in Hz label="Isotropic dimension", events=[ SpectralEvent( rotor_angle=54.735 * 3.14159 / 180,