def pre_setup(isotope, shift, reference_offset): spin_system = SpinSystem( sites=[Site(isotope=isotope, isotropic_chemical_shift=shift)]) method = Method.parse_dict_with_units( dict( channels=[isotope], spectral_dimensions=[{ "count": 2048, "spectral_width": "25 kHz", "reference_offset": f"{reference_offset} Hz", "events": [{ "magnetic_flux_density": "9.4 T", "transition_queries": [{ "ch1": { "P": [-1] } }], }], }], )) sim = Simulator() sim.spin_systems.append(spin_system) sim.methods = [method] sim.run() x, y = sim.methods[0].simulation.to_list() return x[np.argmax(y)], abs(x[1] - x[0])
def test_method_exp_sim(): 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 ) ]) data = cp.as_csdm(np.random.rand(1024, 512)) 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 }, ], experiment=data, ) sim = Simulator() sim.spin_systems = [spin_system] sim.methods = [method] sim.run()
def setup_test(spin_system, volume="octant", sw=25000, n_gamma=500): mth_kwargs = { "channels": [spin_system.sites[0].isotope.symbol], "spectral_dimensions": [{ "count": 1024, "spectral_width": sw }], } data = [] for angle in [0, 54.735, 90]: method = BlochDecaySpectrum(rotor_angle=angle * np.pi / 180, rotor_frequency=0, **mth_kwargs) sim = Simulator(spin_systems=[spin_system], methods=[method]) sim.config.integration_volume = volume sim.config.number_of_gamma_angles = 1 if angle == 0 else n_gamma sim.run(auto_switch=False) res = sim.methods[0].simulation.y[0].components[0] res /= res.max() data.append(res) # plt.plot(data[0]) # plt.plot(data[1], "--") # plt.plot(data[2], "-.") # plt.show() np.testing.assert_almost_equal(data[0], data[1], decimal=2) np.testing.assert_almost_equal(data[0], data[2], decimal=1.6)
def setup(): site = Site(isotope="1H", shielding_symmetric={"zeta": -100, "eta": 0.3}) spin_sys = SpinSystem(sites=[site, site], abundance=45) method = BlochDecaySpectrum(channels=["1H"]) sim = Simulator(spin_systems=[spin_sys, spin_sys], methods=[method, method]) sim.run(method_index=0) sim.methods[0].simulation._timestamp = None processor = sp.SignalProcessor(operations=[ sp.IFFT(), sp.apodization.Exponential(FWHM="2500 Hz"), sp.FFT(), sp.Scale(factor=20), ]) processors = [processor] * 2 application = { "com.github.DeepanshS.mrsimulator": { "foo": "This is some metadata" }, "com.github.DeepanshS.mrsimulator-app": { "params": "The JSON string of params" }, } return sim, processors, application
def test_empty_spin_sys_simulator(): sim = Simulator() sim.methods = [ BlochDecaySpectrum(channels=["1H"], spectral_dimensions=[{"count": 10}]) ] sim.config.decompose_spectrum = "spin_system" sim.run() assert np.allclose(sim.methods[0].simulation.y[0].components[0], 0)
def process_spectrum(method): spin_system = setup_spin_system() sim = Simulator(spin_systems=[spin_system], methods=[method]) sim.config.integration_volume = "hemisphere" sim.run() data = sim.methods[0].simulation.y[0].components[0] data /= data.max() return data
def bestfit(sim: Simulator, processors: list = None): """Return a list of best fit spectrum ordered relative to the methods in the simulator object. Args: Simulator sim: The simulator object. list processors: List of SignalProcessor objects ordered according to the methods in the simulator object. """ processors = processors if isinstance(processors, list) else [processors] sim.run() return [ proc.apply_operations(data=mth.simulation).real for mth, proc in zip(sim.methods, processors) ]
def test_read_write_methods(): for item in methods: kwargs = { "channels": ["93Nb"], "spectral_dimensions": [{ "count": 1024, "spectral_width": 100 } for _ in range(item.ndim)], } if item.__name__ == "SSB2D": kwargs["rotor_frequency"] = 1e3 fn1 = item(**kwargs) # Parse against self assert_parsing(item, fn1) # Parse against Method class assert_parsing(Method, fn1) # Parse against Method1D/Method2D classes mth_d = Method1D if item.ndim == 1 else Method2D assert_parsing(mth_d, fn1) # save test sim = Simulator(spin_systems=[sys], methods=[fn1]) # save/load with units sim.run() sim.save("test.mrsim") sim2 = Simulator.load("test.mrsim") check_sim_save(sim, sim2, "with units") # save/load with out units sim.run() sim.save("test.mrsim", with_units=False) sim2 = Simulator.load("test.mrsim", parse_units=False) check_sim_save(sim, sim2, "without units") # save/load methods sim.run() sim.export_methods("test.mrmtd") sim2 = sim.copy() sim2.load_methods("test.mrmtd") check_methods_save_load(sim, sim2) # save/load spin systems sim.run() sim.export_spin_systems("test.mrsys") sim2 = sim.copy() sim2.load_spin_systems("test.mrsys") assert sim.spin_systems == sim2.spin_systems os.remove("test.mrsim") os.remove("test.mrsys") os.remove("test.mrmtd")
def test_two_site_no_coupling_test(): site1 = Site( isotope="29Si", isotropic_chemical_shift=10, shielding_symmetric={ "zeta": 5, "eta": 0 }, ) site2 = Site( isotope="29Si", isotropic_chemical_shift=-10, shielding_symmetric={ "zeta": -5, "eta": 0 }, ) iso_two_site = [SpinSystem(sites=[site1, site2])] iso_single_sites = [SpinSystem(sites=[site1]), SpinSystem(sites=[site2])] sim1 = Simulator() sim1.spin_systems += iso_two_site sim1.methods += [ BlochDecaySpectrum( channels=["29Si"], spectral_dimensions=[dict(count=2048, spectral_width=25000)], ) ] sim1.run() sim2 = Simulator() sim2.spin_systems += iso_single_sites sim2.methods += [ BlochDecaySpectrum( channels=["29Si"], spectral_dimensions=[dict(count=2048, spectral_width=25000)], ) ] sim2.run() data1 = (sim1.methods[0].simulation / 2).y[0].components data2 = sim2.methods[0].simulation.y[0].components assert np.allclose(data1, data2)
def setup(): site = Site(isotope="1H", shielding_symmetric={"zeta": -100, "eta": 0.3}) spin_sys = SpinSystem(sites=[site, site], abundance=45) method = BlochDecaySpectrum(channels=["1H"]) sim = Simulator(spin_systems=[spin_sys, spin_sys], methods=[method, method]) sim.run(method_index=0) processor = sp.SignalProcessor(operations=[ sp.IFFT(), sp.apodization.Exponential(FWHM="2500 Hz"), sp.FFT(), sp.Scale(factor=20), ]) processors = [processor] * 2 return sim, processors
def generate_shielding_kernel(zeta_, eta_, angle, freq, n_sidebands, to_ppm=True): method = BlochDecaySpectrum( channels=["29Si"], magnetic_flux_density=9.4, spectral_dimensions=[ dict(count=96, spectral_width=208.33 * 96, reference_offset=0) ], rotor_angle=angle, rotor_frequency=freq, ) if to_ppm: larmor_frequency = -method.channels[ 0].gyromagnetic_ratio * 9.4 # in MHz zeta_ /= larmor_frequency spin_systems = [ SpinSystem(sites=[ Site(isotope="29Si", shielding_symmetric={ "zeta": z, "eta": e }) ]) for z, e in zip(zeta_, eta_) ] sim = Simulator() sim.spin_systems = spin_systems sim.methods = [method] sim.config.decompose_spectrum = "spin_system" sim.config.number_of_sidebands = n_sidebands sim.run(pack_as_csdm=False) sim_lineshape = sim.methods[0].simulation.real sim_lineshape = np.asarray(sim_lineshape).reshape(4, 4, 96) sim_lineshape = sim_lineshape / sim_lineshape[0, 0].sum() sim_lineshape[0, :, :] /= 2.0 sim_lineshape[:, 0, :] /= 2.0 sim_lineshape.shape = (16, 96) return sim_lineshape
def test_simulator_2(): sim = Simulator() sim.spin_systems = [ SpinSystem( sites=[Site(isotope="1H"), Site(isotope="23Na")], couplings=[Coupling(site_index=[0, 1], isotropic_j=15)], ) ] sim.methods = [ BlochDecaySpectrum( channels=["1H"], spectral_dimensions=[{ "count": 10 }], experiment=cp.as_csdm(np.arange(10)), ) ] sim.name = "test" sim.label = "test0" sim.description = "testing-testing 1.2.3" sim.run() # save sim.save("test_sim_save.temp") sim_load = Simulator.load("test_sim_save.temp") sim_load_data = sim_load.methods[0].simulation sim_data = sim.methods[0].simulation sim_load_data._timestamp = "" assert sim_load_data.dict() == sim_data.dict() sim_load.methods[0].simulation = None sim.methods[0].simulation = None assert sim_load.spin_systems == sim.spin_systems assert sim_load.methods == sim.methods assert sim_load.name == sim.name assert sim_load.description == sim.description os.remove("test_sim_save.temp")
def LMFIT_min_function(params: Parameters, sim: Simulator, processors: list = None, sigma: list = None): """The simulation routine to calculate the vector difference between simulation and experiment based on the parameters update. Args: params: Parameters object containing parameters for OLS minimization. sim: Simulator object. processors: A list of PostSimulator objects corresponding to the methods in the Simulator object. sigma: A list of standard deviations corresponding to the experiments in the Simulator.methods attribute Returns: Array of the differences between the simulation and the experimental data. """ processors = processors if isinstance(processors, list) else [processors] sigma = [1.0 for _ in sim.methods] if sigma is None else sigma sigma = sigma if isinstance(sigma, list) else [sigma] update_mrsim_obj_from_params(params, sim, processors) sim.run() processed_data = [ item.apply_operations(data=data.simulation) for item, data in zip(processors, sim.methods) ] diff = np.asarray([]) for processed_datum, mth, sigma_ in zip(processed_data, sim.methods, sigma): datum = 0 for decomposed_datum in processed_datum.y: datum += decomposed_datum.components[0].real exp_data = get_correct_data_order(mth) diff = np.append(diff, (exp_data - datum) / sigma_) return diff
def kernel(self, supersampling=1): """ Return the NMR nuclear shielding anisotropic line-shape kernel. Args: supersampling: An integer. Each cell is supersampled by the factor `supersampling` along every dimension. Returns: A numpy array containing the line-shape kernel. """ args_ = deepcopy(self.method_args) method = BlochDecaySpectrum.parse_dict_with_units(args_) isotope = args_["channels"][0] zeta, eta = self._get_zeta_eta(supersampling) x_csdm = self.inverse_kernel_dimension[0] if x_csdm.coordinates.unit.physical_type == "frequency": # convert zeta to ppm if given in frequency units. zeta /= self.larmor_frequency # zeta in ppm for dim_i in self.inverse_kernel_dimension: if dim_i.origin_offset.value == 0: dim_i.origin_offset = f"{abs(self.larmor_frequency)} MHz" spin_systems = [ SpinSystem(sites=[ dict(isotope=isotope, shielding_symmetric=dict(zeta=z, eta=e)) ]) for z, e in zip(zeta, eta) ] sim = Simulator() sim.config.number_of_sidebands = self.number_of_sidebands sim.config.decompose_spectrum = "spin_system" sim.spin_systems = spin_systems sim.methods = [method] sim.run(pack_as_csdm=False) amp = sim.methods[0].simulation.real return self._averaged_kernel(amp, supersampling)
spectral_dimensions=spectral_dims, experiment=experiment, # add the measurement to the method. ) # Optimize the script by pre-setting the transition pathways for each spin system from # the method. for sys in spin_systems: sys.transition_pathways = MAS_CT.get_transition_pathways(sys) # %% # **Guess Model Spectrum** # Simulation # ---------- sim = Simulator(spin_systems=spin_systems, methods=[MAS_CT]) sim.run() # Post Simulation Processing # -------------------------- processor = sp.SignalProcessor(operations=[ sp.IFFT(), sp.apodization.Exponential(FWHM="100 Hz"), sp.FFT(), sp.Scale(factor=200), ]) processed_dataset = processor.apply_operations( dataset=sim.methods[0].simulation).real # Plot of the guess Spectrum # -------------------------- plt.figure(figsize=(4.25, 3.0))
dimension = { "magnetic_flux_density": "9.4 T", "rotor_frequency": "0 kHz", "rotor_angle": "54.735 deg", "number_of_points": 2048, "spectral_width": "25 kHz", "reference_offset": "0 Hz", "isotope": "1H", } sim = Simulator() sim.isotopomers = [Isotopomer.parse_dict_with_units(item) for item in isotopomers] sim.dimensions = [Dimension.parse_dict_with_units(dimension)] freq1, amp1 = sim.run(one_d_spectrum) # spinning sideband simulation # set the rotor frequency to 1000 Hz sim.dimensions[0].rotor_frequency = 1000 freq2, amp2 = sim.run(one_d_spectrum) 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") ax[1].plot(freq2, amp2, linewidth=1.0, color="k") ax[1].set_xlabel(f"frequency ratio / {freq2.unit}") ax[1].grid(color="gray", linestyle="--", linewidth=0.5, alpha=0.5) ax[1].set_title("MAS")
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)
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())
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")
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())
def simulator(method, j_coup, dipole): system = coupled_spin_system(j_coup, dipole) sim = Simulator(spin_systems=[system], methods=[method]) sim.run() return sim.methods[0].simulation.real.y[0].components[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)
def test_DAS(): B0 = 11.7 das = Method2D( channels=["17O"], magnetic_flux_density=B0, # in T spectral_dimensions=[ { "count": 912, "spectral_width": 5e3, # in Hz "reference_offset": 0, # in Hz "label": "DAS isotropic dimension", "events": [ { "fraction": 0.5, "rotor_angle": 37.38 * 3.14159 / 180 }, { "fraction": 0.5, "rotor_angle": 79.19 * 3.14159 / 180 }, ], }, # The last spectral dimension block is the direct-dimension { "count": 2048, "spectral_width": 2e4, # in Hz "reference_offset": 0, # in Hz "label": "MAS dimension", "events": [{ "rotor_angle": 54.735 * 3.14159 / 180 }], }, ], ) sim = Simulator() sim.spin_systems = spin_systems # add spin systems sim.methods = [das] # add the method. sim.config.decompose_spectrum = "spin_system" sim.run(pack_as_csdm=False) data_das = sim.methods[0].simulation data_das_coords_ppm = das.spectral_dimensions[0].coordinates_ppm() # Bloch decay central transition method bloch = BlochDecayCentralTransitionSpectrum( channels=["17O"], magnetic_flux_density=B0, # in T rotor_frequency=1e9, # in Hz rotor_angle=54.735 * 3.14159 / 180, spectral_dimensions=[ { "count": 2048, "spectral_width": 2e4, # in Hz "reference_offset": 0, # in Hz "label": "MAS dimension", }, ], ) sim = Simulator() sim.spin_systems = spin_systems sim.methods = [bloch] sim.config.decompose_spectrum = "spin_system" sim.run(pack_as_csdm=False) data_bloch = sim.methods[0].simulation larmor_freq = das.channels[0].gyromagnetic_ratio * B0 * 1e6 spin = das.channels[0].spin for i, sys in enumerate(spin_systems): for site in sys.sites: Cq = site.quadrupolar.Cq eta = site.quadrupolar.eta iso = site.isotropic_chemical_shift factor1 = -(3 / 40) * (Cq / larmor_freq)**2 factor2 = (spin * (spin + 1) - 3 / 4) / (spin**2 * (2 * spin - 1)**2) factor3 = 1 + (eta**2) / 3 iso_obs = factor1 * factor2 * factor3 * 1e6 + iso # get the index where there is a signal id1 = data_das[i] / data_das[i].max() index = np.where(id1 == id1.max())[0] iso_spectrum = data_das_coords_ppm[ index[0]] # x[1].coords[index[0]] # test for the position of isotropic peaks. np.testing.assert_almost_equal(iso_obs, iso_spectrum, decimal=1) # test for the spectrum across the isotropic peaks. data_bloch_i = data_bloch[i] / data_bloch[i].max() assert np.allclose(id1[index[0]], data_bloch_i)
"count": 256, "spectral_width": 5e3, # in Hz "reference_offset": -2.5e3, # in Hz "label": "Isotropic dimension", }, # The last spectral dimension block is the direct-dimension { "count": 256, "spectral_width": 2e4, # in Hz "reference_offset": 0, # in Hz "label": "MAS dimension", }, ], ) sim.methods = [method] # add the method. sim.run() # Run the simulation # %% # The plot of the simulation. data = sim.methods[0].simulation ax = plt.subplot(projection="csdm") cb = ax.imshow(data / data.max(), aspect="auto", cmap="gist_ncar_r") plt.colorbar(cb) ax.invert_xaxis() ax.invert_yaxis() plt.tight_layout() plt.show() # %% # Add post-simulation signal processing. processor = sp.SignalProcessor(
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] if method not in [Method, Method1D, Method2D]: with pytest.raises(ImmutableEventError, match=f".*{event_error}.*"): method.parse_dict_with_units(serialize) with pytest.raises(ImmutableEventError, match=f".*{event_error}.*"): method(**serialize) with pytest.raises(ImmutableEventError, match=f".*{event_error}.*"): ent.append({"transition_query": [{"ch1": {"P": [-100]}}]}) method.parse_dict_with_units(serialize) def check_sim_save(sim1, sim2, message): for mth in sim2.methods: mth.simulation._timestamp = "" _ = [ item.to("ppm", "nmr_frequency_ratio") for item in mth.simulation.x ] data1 = sim.methods[0].simulation.copy() sim.methods[0].simulation = None data2 = sim2.methods[0].simulation.copy() sim2.methods[0].simulation = None assert data1 == data2, f"data saved and loaded is not equal: type {message}." assert sim == sim2, f".mrsim saved and loaded is not equal: type {message}." for item in methods: kwargs = { "channels": ["93Nb"], "spectral_dimensions": [{ "count": 1024, "spectral_width": 100 } for _ in range(item.ndim)], } if item.__name__ == "SSB2D": kwargs["rotor_frequency"] = 1e3 fn1 = item(**kwargs) # Parse against self assert_parsing(item, fn1) # Parse against Method class assert_parsing(Method, fn1) # Parse against Method1D/Method2D classes mth_d = Method1D if item.ndim == 1 else Method2D assert_parsing(mth_d, fn1) # save test sim = Simulator(spin_systems=[sys], methods=[fn1]) # save/load with units sim.run() sim.save("test.mrsim") sim2 = Simulator.load("test.mrsim") check_sim_save(sim, sim2, "with units") # save/load with out units sim.run() sim.save("test.mrsim", with_units=False) sim2 = Simulator.load("test.mrsim", parse_units=False) check_sim_save(sim, sim2, "without units") os.remove("test.mrsim")
def setup_simulation(site, affine_matrix, class_id=0): isotope = site.isotope.symbol spin_system = [SpinSystem(sites=[site])] method_C = method_class[class_id] method = method_C( channels=[isotope], magnetic_flux_density=7, # in T rotor_angle=54.735 * np.pi / 180, spectral_dimensions=[ { "count": 512, "spectral_width": 4e4, # in Hz "reference_offset": -3e3, # in Hz }, { "count": 1024, "spectral_width": 1e4, # in Hz "reference_offset": -4e3, # in Hz }, ], affine_matrix=affine_matrix, ) method_1 = Method( channels=[isotope], magnetic_flux_density=7, # in T rotor_angle=54.735 * np.pi / 180, rotor_frequency=np.inf, spectral_dimensions=[ { "count": 1024, "spectral_width": 1e4, # in Hz "reference_offset": -4e3, # in Hz "events": [ { "fraction": 27 / 17, "freq_contrib": ["Quad2_0"], "transition_queries": [{"ch1": {"P": [-1], "D": [0]}}], }, { "fraction": 1, "freq_contrib": ["Quad2_4"], "transition_queries": [{"ch1": {"P": [-1], "D": [0]}}], }, ], } ], ) sim = Simulator() sim.spin_systems = spin_system # add the spin-system sim.methods = [method, method_1] # add the method # run the simulation sim.config.number_of_sidebands = 1 sim.run() csdm_data1 = sim.methods[0].simulation.real.sum(axis=1) csdm_data2 = sim.methods[1].simulation.real csdm_data1 /= csdm_data1.max() csdm_data2 /= csdm_data2.max() np.testing.assert_almost_equal( csdm_data1.y[0].components, csdm_data2.y[0].components, decimal=3 )