def test_sites_to_pandas_df(): isotopes = ["29Si"] * 3 + ["17O"] shifts = [-89.0, -89.5, -87.8, 15.0] zeta = [59.8, 52.1, 69.4, 12.4] eta_n = [0.62, 0.68, 0.6, 0.5] Cq = [None, None, None, 5.3e6] eta_q = [None, None, None, 0.34] spin_systems = single_site_system_generator( isotope=isotopes, isotropic_chemical_shift=shifts, shielding_symmetric={"zeta": zeta, "eta": eta_n}, quadrupolar={"Cq": Cq, "eta": eta_q}, abundance=1, ) sim = Simulator() sim.spin_systems = spin_systems pd_o = sim.sites().to_pd() assert list(pd_o["isotope"]) == isotopes assert list(pd_o["isotropic_chemical_shift"]) == [ f"{i} ppm" if i is not None else None for i in shifts ] assert list(pd_o["shielding_symmetric.zeta"]) == [ f"{i} ppm" if i is not None else None for i in zeta ] assert list(pd_o["shielding_symmetric.eta"]) == [ i if i is not None else None for i in eta_n ] assert list(pd_o["quadrupolar.Cq"]) == [ f"{i} Hz" if i is not None else None for i in Cq ]
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 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 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 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 generate_simulator(spin_systems, method, integration_volume="octant", number_of_sidebands=64): sim = Simulator() sim.spin_systems = spin_systems sim.methods = [method] sim.config.integration_volume = integration_volume sim.config.number_of_sidebands = number_of_sidebands return sim
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 test_simulator_assignments(): a = Simulator() assert a.spin_systems == [] error = "value is not a valid list" with pytest.raises(Exception, match=f".*{error}.*"): a.spin_systems = "" with pytest.raises(Exception, match=f".*{error}.*"): a.methods = ""
def test_sim_coesite(): # coesite O17_1 = Site( isotope="17O", isotropic_chemical_shift=29, quadrupolar=dict(Cq=6.05e6, eta=0.000), ) O17_2 = Site( isotope="17O", isotropic_chemical_shift=41, quadrupolar=dict(Cq=5.43e6, eta=0.166), ) O17_3 = Site( isotope="17O", isotropic_chemical_shift=57, quadrupolar=dict(Cq=5.45e6, eta=0.168), ) O17_4 = Site( isotope="17O", isotropic_chemical_shift=53, quadrupolar=dict(Cq=5.52e6, eta=0.169), ) O17_5 = Site( isotope="17O", isotropic_chemical_shift=58, quadrupolar=dict(Cq=5.16e6, eta=0.292), ) sites = [O17_1, O17_2, O17_3, O17_4, O17_5] abundance = [0.83, 1.05, 2.16, 2.05, 1.90] # abundance of each spin system spin_systems = [ SpinSystem(sites=[s], abundance=a) for s, a in zip(sites, abundance) ] method = BlochDecayCTSpectrum( channels=["17O"], rotor_frequency=14000, spectral_dimensions=[{ "count": 2048, "spectral_width": 50000 }], ) sim_coesite = Simulator() sim_coesite.spin_systems += spin_systems sim_coesite.methods += [method] sim_coesite.save("sample.mrsim") sim_load = Simulator.load("sample.mrsim") assert sim_coesite == sim_load os.remove("sample.mrsim")
def test_sites(): iso = [1.02, 2.12, 13.2, 5.2, 2.1, 1.2] zeta = [1.02, 2.12, 13.2, 5.2, 2.1, 1.2] eta = [0.1, 0.4, 0.3, 0.6, 0.9, 1.0] sites = [ Site( isotope="13C", isotropic_chemical_shift=i, shielding_symmetric={ "zeta": z, "eta": e }, ) for i, z, e in zip(iso, zeta, eta) ] sim = Simulator() sim.spin_systems = [SpinSystem(sites=[s]) for s in sites] r_sites = sim.sites() for i, site in enumerate(sites): assert r_sites[i] == site # test sites to pd sites_table = sim.sites().to_pd() assert list(sites_table["isotope"]) == ["13C"] * len(iso) assert list(sites_table["isotropic_chemical_shift"]) == [ f"{i} ppm" if i is not None else None for i in iso ] assert list(sites_table["shielding_symmetric.zeta"]) == [ f"{i} ppm" if i is not None else None for i in zeta ] assert list(sites_table["shielding_symmetric.eta"]) == [ i if i is not None else None for i in eta ] # test Sites Class a = Sites([]) site = Site(isotope="1H") a.append(site) assert a[0] == site site2 = Site(isotope="17O") a[0] = site2 assert a[0] == site2 site_dict = {"isotope": "13C"} a[0] = site_dict assert a[0] == Site(**site_dict) with pytest.raises(ValueError, match="Only object of type Site is allowed."): a[0] = ""
def pre_setup(): site_1 = Site(isotope="13C", shielding_symmetric={"zeta": 50, "eta": 0.5}) spin_system = SpinSystem(sites=[site_1]) method = BlochDecaySpectrum(channels=["13C"], spectral_dimensions=[{ "count": 1024, "spectral_width": 25000 }]) sim = Simulator() sim.spin_systems.append(spin_system) sim.methods = [method] return sim
def c_setup(data_object, data_source): # mrsimulator spectrum = Spectrum.parse_json_with_units(data_object["spectrum"]) isotopomer = [ Isotopomer.parse_json_with_units(isotopomer) for isotopomer in data_object["isotopomers"] ] s1 = Simulator(isotopomer, spectrum) freq, data_mrsimulator = s1.one_d_spectrum( geodesic_polyhedron_frequency=120) data_mrsimulator /= data_mrsimulator.max() return data_mrsimulator, data_source
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_raise_messages(): e = "Expecting a `Simulator` object, found" with pytest.raises(ValueError, match=f".*{e}.*"): sf.make_LMFIT_params(12, 21) e = "Expecting a list of `SignalProcessor` objects." with pytest.raises(ValueError, match=f".*{e}.*"): sf.make_LMFIT_params(Simulator(spin_systems=[SpinSystem()]), 21)
def get_simulator(): isotopes = ["19F", "31P", "2H", "6Li", "14N", "27Al", "25Mg", "45Sc", "87Sr"] sites = [] for isotope in isotopes: for _ in range(randint(1, 3)): sites.append(Site(isotope=isotope)) sim = Simulator() sim.spin_systems.append(SpinSystem(sites=sites)) return sim
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 test_allowed_isotopes(): assert set(Simulator.allowed_isotopes()) == { "19F", "31P", "129Xe", "1H", "57Fe", "13C", "15N", "29Si", }
def test_equality(): a = Simulator() b = Simulator() assert a == b assert a != {} c = Simulator(spin_systems=[SpinSystem()], label="test") assert a != c result = { "label": "test", "spin_systems": [{}], "config": { "decompose_spectrum": "none", "integration_density": 70, "integration_volume": "octant", "number_of_sidebands": 64, }, } assert c.json() == result assert c.json(units=False) == { "label": "test", "spin_systems": [{}], "config": { "number_of_sidebands": 64, "integration_volume": "octant", "integration_density": 70, "decompose_spectrum": "none", }, }
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 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 one_time_simulation(): mrsim_data = ctx.inputs["local-mrsim-data.data"] # n_sys = 1 if "spin_systems" not in mrsim_data else len(mrsim_data["spin_systems"]) if mrsim_data is None: raise PreventUpdate if len(mrsim_data["methods"]) == 0: mrsim_data["timestamp"] = datetime.datetime.now() return [no_update, no_update, mrsim_data] try: sim = Simulator.parse_dict_with_units(mrsim_data) decompose = sim.config.decompose_spectrum[:] sim.config.decompose_spectrum = "spin_system" sim.run() sim.config.decompose_spectrum = decompose except Exception as e: return [f"SimulationError: {e}", True, no_update] process_data = mrsim_data["signal_processors"] for proc, mth in zip(process_data, sim.methods): processor = SignalProcessor.parse_dict_with_units(proc) mth.simulation = processor.apply_operations(data=mth.simulation).real if decompose == "none": for mth in sim.methods: mth.simulation = add_csdm_dvs(mth.simulation) serialize = sim.json(include_methods=True, include_version=True) serialize["signal_processors"] = process_data # add parameters to serialization if present if "params" in mrsim_data: serialize["params"] = mrsim_data["params"] # layout = ctx.states["graph-view-layout.data"] # for _ in range(len(sim.methods)-len(layout)): # layout.append(None) # for i, mth in enumerate(sim.methods): # if layout[i] is None: # if len(mth.simulation.x) == 1: # x = mth.simulation.x[0].coordinates.value # y = mth.simulation.y[0].components[0].real # layout[i] = { # 'xaxis': {"range": [x.max(), x.min()]}, # 'yaxis': {"range": [y.min(), y.max()]} # } return ["", False, serialize]
def test_7(): site = Site(isotope="23Na") sys = SpinSystem(sites=[site], abundance=50) sim = Simulator() sim.spin_systems = [sys, sys] sim.methods = [BlochDecayCTSpectrum(channels=["23Na"])] sim.methods[0].experiment = cp.as_csdm(np.zeros(1024)) processor = sp.SignalProcessor(operations=[ sp.IFFT(dim_index=0), sp.apodization.Gaussian(FWHM="0.2 kHz", dim_index=0), sp.FFT(dim_index=0), ]) def test_array(): sim.run() dataset = processor.apply_operations(sim.methods[0].simulation) data_sum = 0 for dv in dataset.y: data_sum += dv.components[0] params = sf.make_LMFIT_params(sim, processor) a = sf.LMFIT_min_function(params, sim, processor) np.testing.assert_almost_equal(-a, data_sum, decimal=8) dat = sf.add_csdm_dvs(dataset.real) fits = sf.bestfit(sim, processor) assert sf.add_csdm_dvs(fits[0]) == dat res = sf.residuals(sim, processor) assert res[0] == -dat test_array() sim.config.decompose_spectrum = "spin_system" test_array()
def add_site(doctest_namespace): doctest_namespace["np"] = np doctest_namespace["plt"] = plt doctest_namespace["SpinSystem"] = SpinSystem doctest_namespace["Simulator"] = Simulator doctest_namespace["Site"] = Site doctest_namespace["Coupling"] = Coupling doctest_namespace["SymmetricTensor"] = SymmetricTensor doctest_namespace["st"] = SymmetricTensor doctest_namespace["pprint"] = pprint doctest_namespace["Isotope"] = Isotope doctest_namespace["sp"] = sp doctest_namespace["Method2D"] = Method2D site1 = Site( isotope="13C", isotropic_chemical_shift=20, shielding_symmetric=SymmetricTensor(zeta=10, eta=0.5), ) site2 = Site( isotope="1H", isotropic_chemical_shift=-4, shielding_symmetric=SymmetricTensor(zeta=2.1, eta=0.1), ) site3 = Site( isotope="27Al", isotropic_chemical_shift=120, shielding_symmetric=SymmetricTensor(zeta=2.1, eta=0.1), quadrupolar=SymmetricTensor(Cq=5.1e6, eta=0.5), ) doctest_namespace["spin_system_1H_13C"] = SpinSystem(sites=[site1, site2]) doctest_namespace["spin_systems"] = SpinSystem(sites=[site1, site2, site3]) spin_systems = [SpinSystem(sites=[site]) for site in [site1, site2, site3]] sim = Simulator() sim.spin_systems += spin_systems doctest_namespace["sim"] = sim # Transitions t1 = Transition(initial=[0.5, 0.5], final=[0.5, -0.5]) doctest_namespace["t1"] = t1 t2 = Transition(initial=[0.5, 0.5], final=[-0.5, 0.5]) doctest_namespace["t2"] = t2 path = TransitionPathway([t1, t2]) doctest_namespace["path"] = path
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 simulator_setup( data_object, integration_volume="octant", integration_density=120, number_of_sidebands=90, ): methods = [Method.parse_dict_with_units(_) for _ in data_object["methods"]] spin_systems = [ SpinSystem.parse_dict_with_units(item) for item in data_object["spin_systems"] ] s1 = Simulator(spin_systems=spin_systems, methods=methods) s1.config.decompose_spectrum = "spin_system" s1.spin_systems[0].name = "test name" s1.spin_systems[0].description = "test description" s1.config.integration_density = integration_density s1.config.number_of_sidebands = number_of_sidebands s1.config.integration_volume = integration_volume return s1
def test_6_coupled(): sim = Simulator() spin_system = {"sites": [H, C], "couplings": [CH], "abundance": "100%"} system_object = SpinSystem.parse_dict_with_units(spin_system) sim.spin_systems += [system_object] post_sim = sp.SignalProcessor(operations=op_list) params = sf.make_LMFIT_params(sim, post_sim) valuesdict_system = { "sys_0_site_0_isotropic_chemical_shift": 10, "sys_0_site_0_shielding_symmetric_zeta": 5, "sys_0_site_0_shielding_symmetric_eta": 0.1, "sys_0_site_0_shielding_symmetric_alpha": 3.12, "sys_0_site_0_shielding_symmetric_gamma": 0.341, "sys_0_site_1_isotropic_chemical_shift": -10, "sys_0_site_1_shielding_symmetric_zeta": 15, "sys_0_site_1_shielding_symmetric_eta": 0.2, "sys_0_site_1_shielding_symmetric_beta": 4.12, "sys_0_coupling_0_isotropic_j": 10, "sys_0_coupling_0_j_symmetric_zeta": 60, "sys_0_coupling_0_j_symmetric_eta": 0.4, "sys_0_abundance": 100, } valuedict_proc = { "SP_0_operation_1_Exponential_FWHM": 100, "SP_0_operation_3_Scale_factor": 10, } assert params.valuesdict() == { **valuesdict_system, **valuedict_proc, }, "Parameter creation failed" params = sf.make_LMFIT_params(sim) assert params.valuesdict( ) == valuesdict_system, "Parameter creation failed" # alias params = sf.make_LMFIT_parameters(sim) assert params.valuesdict( ) == valuesdict_system, "Parameter creation failed"
def test_6_coupled(): sim = Simulator() spin_system = {"sites": [H, C], "couplings": [CH], "abundance": "100%"} system_object = SpinSystem.parse_dict_with_units(spin_system) sim.spin_systems += [system_object] post_sim = sp.SignalProcessor(operations=op_list) params = sf.make_LMFIT_params(sim, post_sim) valuesdict_system = { "sys_0_site_0_isotropic_chemical_shift": 10, "sys_0_site_0_shielding_symmetric_zeta": 5, "sys_0_site_0_shielding_symmetric_eta": 0.1, "sys_0_site_0_shielding_symmetric_alpha": 3.12, "sys_0_site_0_shielding_symmetric_gamma": 0.341, "sys_0_site_1_isotropic_chemical_shift": -10, "sys_0_site_1_shielding_symmetric_zeta": 15, "sys_0_site_1_shielding_symmetric_eta": 0.2, "sys_0_site_1_shielding_symmetric_beta": 4.12, "sys_0_coupling_0_isotropic_j": 10, "sys_0_coupling_0_j_symmetric_zeta": 60, "sys_0_coupling_0_j_symmetric_eta": 0.4, "sys_0_abundance": 100, } compare_result(params, valuesdict_system, sim)
def test_5_multi_spin_systems(): sim = Simulator() spin_system1 = {"sites": [H], "abundance": "100%"} system_object1 = SpinSystem.parse_dict_with_units(spin_system1) spin_system2 = {"sites": [C], "abundance": "60%"} system_object2 = SpinSystem.parse_dict_with_units(spin_system2) sim.spin_systems += [system_object1, system_object2] post_sim = sp.SignalProcessor(operations=op_list) params = sf.make_LMFIT_params(sim, post_sim) valuesdict_system = { "sys_0_site_0_isotropic_chemical_shift": 10, "sys_0_site_0_shielding_symmetric_zeta": 5, "sys_0_site_0_shielding_symmetric_eta": 0.1, "sys_0_site_0_shielding_symmetric_alpha": 3.12, "sys_0_site_0_shielding_symmetric_gamma": 0.341, "sys_0_abundance": 62.5, "sys_1_site_0_isotropic_chemical_shift": -10, "sys_1_site_0_shielding_symmetric_zeta": 15, "sys_1_site_0_shielding_symmetric_eta": 0.2, "sys_1_site_0_shielding_symmetric_beta": 4.12, "sys_1_abundance": 37.5, } compare_result(params, valuesdict_system, sim)
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
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