def test_set_resonance_coupling_matrix(self): """(Aggregate) Testing setting the whole resonance coupling matrix """ agg = TestAggregate(name="dimer-2-env") mat = [[0.0, 1.0], [1.0, 0.0]] agg.set_resonance_coupling_matrix(mat) self.assertAlmostEqual(agg.resonance_coupling[1,0], 1.0) self.assertAlmostEqual(agg.resonance_coupling[0,1], 1.0) self.assertAlmostEqual(agg.resonance_coupling[0,0], 0.0) self.assertAlmostEqual(agg.resonance_coupling[1,1], 0.0) mat = ((0.0, 500.0), (500.0, 0.0)) with qr.energy_units("1/cm"): agg.set_resonance_coupling_matrix(mat) inint = qr.convert(500, "1/cm", "int") self.assertAlmostEqual(agg.resonance_coupling[1,0], inint) self.assertAlmostEqual(agg.resonance_coupling[0,1], inint) self.assertAlmostEqual(agg.resonance_coupling[0,0], 0.0) self.assertAlmostEqual(agg.resonance_coupling[1,1], 0.0)
def set_cor_func(for_agg, params, ax_len = 10000): ax_length = ax_len # Needs to have small step for the dynamics to converge t_ax_sd = qr.TimeAxis(0.0, ax_length, 1) db = SpectralDensityDB() # Parameters for spectral density. ODBO, Renger or Silbey params = params with qr.energy_units('1/cm'): sd_low_freq = qr.SpectralDensity(t_ax_sd, params) reorg = qr.convert(sd_low_freq.measure_reorganization_energy(), "int", "1/cm") print("spectral density reorg -", reorg) # Adding the high freq modes sd_high_freq = db.get_SpectralDensity(t_ax_sd, "Wendling_JPCB_104_2000_5825") ax = sd_low_freq.axis sd_high_freq.axis = ax sd_tot = sd_low_freq + sd_high_freq cf = sd_tot.get_CorrelationFunction(temperature=params['T'], ta=t_ax_sd) # Assigning the correlation function to the list of molecules for mol in for_agg: mol.set_transition_environment((0,1),cf)
def test_set_resonance_coupling(self): """(Aggregate) Testing resonance coupling setting with different units """ agg = TestAggregate(name="dimer-2-env") agg.init_coupling_matrix() agg.set_resonance_coupling(0, 1, 1.0) self.assertAlmostEqual(1.0, agg.resonance_coupling[0,1]) self.assertAlmostEqual(1.0, agg.resonance_coupling[1,0]) with qr.energy_units("1/cm"): agg.set_resonance_coupling(0, 1, 100.0) self.assertAlmostEqual(qr.convert(100.0, "1/cm", "int"), agg.resonance_coupling[0,1]) self.assertAlmostEqual(qr.convert(100.0, "1/cm", "int"), agg.resonance_coupling[1,0])
def test_set_resonance_coupling(self): """(Aggregate) Testing resonance coupling setting with different units """ agg = TestAggregate(name="dimer-2-env") agg.init_coupling_matrix() agg.set_resonance_coupling(0, 1, 1.0) self.assertAlmostEqual(1.0, agg.resonance_coupling[0, 1]) self.assertAlmostEqual(1.0, agg.resonance_coupling[1, 0]) with qr.energy_units("1/cm"): agg.set_resonance_coupling(0, 1, 100.0) self.assertAlmostEqual(qr.convert(100.0, "1/cm", "int"), agg.resonance_coupling[0, 1]) self.assertAlmostEqual(qr.convert(100.0, "1/cm", "int"), agg.resonance_coupling[1, 0])
def test_dipole_dipole_coupling(self): """(Aggregate) Testing dipole-dipole coupling calculation """ agg = TestAggregate(name="dimer-2-env") coup1 = agg.dipole_dipole_coupling(0, 1) coup2 = agg.dipole_dipole_coupling(0, 1, epsr=2.0) self.assertAlmostEqual(coup1, coup2 * 2.0) with qr.energy_units("1/cm"): coup = agg.dipole_dipole_coupling(0, 1) self.assertAlmostEqual(qr.convert(coup1, "int", "1/cm"), coup)
def test_get_resonance_coupling(self): """(Aggregate) Testing resonance coupling retrieval in different units """ agg = TestAggregate(name="dimer-2-env") agg.init_coupling_matrix() agg.set_resonance_coupling(0, 1, 1.0) coup = agg.get_resonance_coupling(1,0) self.assertAlmostEqual(coup, 1.0) with qr.energy_units("1/cm"): coup = agg.get_resonance_coupling(1,0) self.assertAlmostEqual(coup, qr.convert(1.0, "int", "1/cm")) with qr.energy_units("eV"): coup = agg.get_resonance_coupling(1,0) self.assertAlmostEqual(coup, qr.convert(1.0, "int", "eV")) with qr.energy_units("THz"): coup = agg.get_resonance_coupling(1,0) self.assertAlmostEqual(coup, qr.convert(1.0, "int", "THz"))
def test_dipole_dipole_coupling(self): """(Aggregate) Testing dipole-dipole coupling calculation """ agg = TestAggregate(name="dimer-2-env") coup1 = agg.dipole_dipole_coupling(0,1) coup2 = agg.dipole_dipole_coupling(0,1, epsr=2.0) self.assertAlmostEqual(coup1, coup2*2.0) with qr.energy_units("1/cm"): coup = agg.dipole_dipole_coupling(0,1) self.assertAlmostEqual(qr.convert(coup1,"int","1/cm"), coup)
def test_get_resonance_coupling(self): """(Aggregate) Testing resonance coupling retrieval in different units """ agg = TestAggregate(name="dimer-2-env") agg.init_coupling_matrix() agg.set_resonance_coupling(0, 1, 1.0) coup = agg.get_resonance_coupling(1, 0) self.assertAlmostEqual(coup, 1.0) with qr.energy_units("1/cm"): coup = agg.get_resonance_coupling(1, 0) self.assertAlmostEqual(coup, qr.convert(1.0, "int", "1/cm")) with qr.energy_units("eV"): coup = agg.get_resonance_coupling(1, 0) self.assertAlmostEqual(coup, qr.convert(1.0, "int", "eV")) with qr.energy_units("THz"): coup = agg.get_resonance_coupling(1, 0) self.assertAlmostEqual(coup, qr.convert(1.0, "int", "THz"))
def test_set_resonance_coupling_matrix(self): """(Aggregate) Testing setting the whole resonance coupling matrix """ agg = TestAggregate(name="dimer-2-env") mat = [[0.0, 1.0], [1.0, 0.0]] agg.set_resonance_coupling_matrix(mat) self.assertAlmostEqual(agg.resonance_coupling[1, 0], 1.0) self.assertAlmostEqual(agg.resonance_coupling[0, 1], 1.0) self.assertAlmostEqual(agg.resonance_coupling[0, 0], 0.0) self.assertAlmostEqual(agg.resonance_coupling[1, 1], 0.0) mat = ((0.0, 500.0), (500.0, 0.0)) with qr.energy_units("1/cm"): agg.set_resonance_coupling_matrix(mat) inint = qr.convert(500, "1/cm", "int") self.assertAlmostEqual(agg.resonance_coupling[1, 0], inint) self.assertAlmostEqual(agg.resonance_coupling[0, 1], inint) self.assertAlmostEqual(agg.resonance_coupling[0, 0], 0.0) self.assertAlmostEqual(agg.resonance_coupling[1, 1], 0.0)
def run(omega, HR, dE, JJ, rate, E0, vib_loc="up", use_vib=True, detailed_balance=False, temperature=77.0, stype=qr.signal_REPH, save_eUt=False, t2_save_pathways=[], dname=None, trimer=None, disE=None): """Runs a complete set of simulations for a single set of parameters If disE is not None it tries to run averaging over Gaussian energetic disorder. """ if dname is None: dname = "sim_" + vib_loc use_trimer = trimer["useit"] rate_sp = trimer["rate"] # # PARAMETERS FROM INPUT FILE # dip1 = INP.dip1 # [1.5, 0.0, 0.0] dip2 = INP.dip2 # [-1.0, -1.0, 0.0] width = INP.feature_width # 100.0 width2 = INP.feature_width2 normalize_maps_to_maximu = False trim_maps = False units = "1/cm" with qr.energy_units(units): data_descr = "_dO="+str(dE)+"_omega="+str(omega)+ \ "_HR="+str(HR)+"_J="+str(JJ) if use_vib: sys_char = "_vib" else: sys_char = "_ele" data_ext = sys_char + ".png" obj_ext = sys_char + ".qrp" # parameters of the SP if use_trimer: E2 = trimer["E2"] epsa = (E0 + E2) / 2.0 DE = trimer["DE"] J2 = 0.5 * numpy.sqrt(((E0 - E2)**2) - (DE**2)) ESP2 = epsa + DE / 2.0 ESP1 = epsa - DE / 2.0 # # Model system is a dimer of molecules # with qr.energy_units("1/cm"): if not use_trimer: if disE is not None: mol1 = qr.Molecule([0.0, E0 + disE[0]]) mol2 = qr.Molecule([0.0, E0 + dE + disE[1]]) print("Monomer 1 energy:", E0 + disE[0], "1/cm") print("Monomer 2 energy:", E0 + dE + disE[1], "1/cm") else: mol1 = qr.Molecule([0.0, E0]) mol2 = qr.Molecule([0.0, E0 + dE]) print("Monomer 1 energy:", E0, "1/cm") print("Monomer 2 energy:", E0 + dE, "1/cm") else: if disE is not None: mol1 = qr.Molecule([0.0, ESP2 + disE[0]]) mol2 = qr.Molecule([0.0, E0 + dE + disE[1]]) print("Monomer 1 (SP_high) energy:", ESP2 + disE[0], "1/cm") print("Monomer 2 (B) energy:", E0 + dE + disE[1], "1/cm") else: mol1 = qr.Molecule([0.0, ESP2]) mol2 = qr.Molecule([0.0, E0 + dE]) print("Monomer 1 (SP_high) energy:", ESP2, "1/cm") print("Monomer 2 (B) energy:", E0 + dE, "1/cm") if disE is not None: mol3 = qr.Molecule([0.0, ESP1 + disE[2]]) print("Monomer 3 (SP_low) energy:", ESP1 + disE[2], "1/cm") else: mol3 = qr.Molecule([0.0, ESP1]) print("Monomer 3 (SP_low) energy:", ESP1, "1/cm") mol3.set_transition_width((0, 1), width2) mol3.set_dipole(0, 1, trimer["dipsp"]) mol1.set_transition_width((0, 1), width2) mol1.set_dipole(0, 1, dip1) mol2.set_transition_width((0, 1), width) mol2.set_dipole(0, 1, dip2) if use_trimer: agg = qr.Aggregate([mol1, mol2, mol3]) else: agg = qr.Aggregate([mol1, mol2]) if use_trimer: with qr.energy_units("1/cm"): agg.set_resonance_coupling(0, 1, JJ) print("B - SP_high coupling:", JJ, "1/cm") agg.set_resonance_coupling(0, 2, J2) print("SP coupling:", J2, "1/cm") else: with qr.energy_units("1/cm"): agg.set_resonance_coupling(0, 1, JJ) # # Electronic only aggregate # agg_el = agg.deepcopy() # # if nuclear vibrations are to be added, do it here # if use_vib: with qr.energy_units("1/cm"): mod1 = qr.Mode(omega) mod2 = qr.Mode(omega) if vib_loc == "down": set_vib = [True, False] elif vib_loc == "up": set_vib = [False, True] elif vib_loc == "both": set_vib = [True, True] else: raise Exception("Unknown location of the vibrations") if set_vib[0]: print("Vibrations set for SP_high molecule") mol1.add_Mode(mod1) mod1.set_nmax(0, INP.vibmode["no_g_vib"]) mod1.set_nmax(1, INP.vibmode["no_e_vib"]) mod1.set_HR(1, HR) if set_vib[1]: print("Vibrations set for B molecule") mol2.add_Mode(mod2) mod2.set_nmax(0, INP.vibmode["no_g_vib"]) mod2.set_nmax(1, INP.vibmode["no_e_vib"]) mod2.set_HR(1, HR) # # Before we build the aggregate, we make its copy to have an unbuilt version # agg3 = agg.deepcopy() aggA = agg.deepcopy() # # here we build the complete aggregate and its electronic only version # agg.build(mult=1) agg_el.build(mult=1) aggA.build(mult=1) # total Hamiltonian HH = agg.get_Hamiltonian() # electronic Hamiltonian He = agg_el.get_Hamiltonian() # # Laboratory setup # lab = qr.LabSetup() lab.set_polarizations(pulse_polarizations=[X, X, X], detection_polarization=X) # # Time axis for the calculation of excited state evolution # t2_N_steps = INP.t2_N_steps t2_time_step = INP.t2_time_step time2 = qr.TimeAxis(0.0, t2_N_steps, t2_time_step) # # Containers for 2D maps with positive and negative frequencies # cont_p = qr.TwoDResponseContainer(t2axis=time2) cont_m = qr.TwoDResponseContainer(t2axis=time2) cont_tot = qr.TwoDResponseContainer(t2axis=time2) # # spectra will be indexed by the times in the time axis `time2` # cont_p.use_indexing_type(time2) cont_m.use_indexing_type(time2) cont_tot.use_indexing_type(time2) # # We define two-time axes, which will be FFTed and will define # the omega_1 and omega_3 axes of the 2D spectrum # t1_N_steps = INP.t1_N_steps t1_time_step = INP.t1_time_step t3_N_steps = INP.t3_N_steps t3_time_step = INP.t3_time_step t1axis = qr.TimeAxis(0.0, t1_N_steps, t1_time_step) t3axis = qr.TimeAxis(0.0, t3_N_steps, t3_time_step) # # This calculator calculated 2D spectra from the effective width # msc = qr.MockTwoDResponseCalculator(t1axis, time2, t3axis) with qr.energy_units("1/cm"): msc.bootstrap(rwa=E0, shape="Gaussian") # # System-bath interaction including vibrational states # operators = [] rates = [] print("Relaxation rates: ", rate, rate_sp, "1/fs") with qr.eigenbasis_of(He): if use_trimer: if He.data[3, 3] < He.data[2, 2]: Exception("Electronic states not orderred!") operators.append(qr.qm.ProjectionOperator(2, 3, dim=He.dim)) with qr.energy_units("1/cm"): print("2 <- 3 : energies = ", He.data[2, 2], He.data[3, 3], "1/cm") rates.append(rate) print("Transfer time 2 <- 3:", 1.0 / rate, "fs") if He.data[2, 2] < He.data[1, 1]: Exception("Electronic states not orderred!") operators.append(qr.qm.ProjectionOperator(1, 2, dim=He.dim)) with qr.energy_units("1/cm"): print("1 <- 2 : energies = ", He.data[1, 1], He.data[2, 2], "1/cm") rates.append(rate_sp) print("Transfer time 1 <- 2", 1.0 / rate_sp, "fs") else: if He.data[2, 2] < He.data[1, 1]: Exception("Electronic states not orderred!") operators.append(qr.qm.ProjectionOperator(1, 2, dim=He.dim)) with qr.energy_units("1/cm"): print("1 <- 2 : energies = ", He.data[1, 1], He.data[2, 2], "1/cm") rates.append(rate_sp) print("Transfer time 1 <- 2", 1.0 / rate, "fs") # include detailed balace if detailed_balance: if use_trimer: with qr.eigenbasis_of(He): T = temperature #77.0 Den = (He.data[3, 3] - He.data[2, 2]) / (kB_int * T) operators.append(qr.qm.ProjectionOperator(3, 2, dim=He.dim)) thermal_fac = numpy.exp(-Den) rates.append(rate * thermal_fac) Den = (He.data[2, 2] - He.data[1, 1]) / (kB_int * T) operators.append(qr.qm.ProjectionOperator(2, 1, dim=He.dim)) thermal_fac = numpy.exp(-Den) rates.append(rate_sp * thermal_fac) else: with qr.eigenbasis_of(He): T = temperature #77.0 Den = (He.data[2, 2] - He.data[1, 1]) / (kB_int * T) operators.append(qr.qm.ProjectionOperator(2, 1, dim=He.dim)) thermal_fac = numpy.exp(-Den) rates.append(rate * thermal_fac) sbi = qr.qm.SystemBathInteraction(sys_operators=operators, rates=rates) sbi.set_system(agg) # # Lindblad form for relaxation # LF = qr.qm.ElectronicLindbladForm(HH, sbi, as_operators=True) # # Pure dephasing # p_deph = qr.qm.ElectronicPureDephasing(agg, dtype="Gaussian") # we simplify calculations by converting dephasing to # corresponding Lorentzian form p_deph.convert_to("Lorentzian") eUt = qr.qm.EvolutionSuperOperator(time2, HH, relt=LF, pdeph=p_deph, mode="all") eUt.set_dense_dt(INP.fine_splitting) print("---") # # We calculate evolution superoperator # eUt.calculate(show_progress=False) # save the evolution operator if save_eUt: eut_name = os.path.join( dname, "eUt" + "_omega2=" + str(omega) + data_descr + obj_ext) eUt.save(eut_name) # # Prepare aggregate with all states (including 2-EX band) # agg3.build(mult=2) agg3.diagonalize() agg_el.diagonalize() print("") print("Square of the transition dipoles") print(agg_el.D2) print("") print("---") # # calculation of absorption spectrum # time1 = qr.TimeAxis(0.0, 1000, 5.0) absc = qr.MockAbsSpectrumCalculator(time1, system=aggA) with qr.energy_units("1/cm"): absc.bootstrap(rwa=E0) spctrm = absc.calculate() spctrm.normalize2() with qr.energy_units("1/cm"): spctrm.plot(show=False, axis=[10500.0, 13500.0, 0.0, 1.1]) spctrm.savefig(os.path.join(dname, "abs.png")) spctrm.save_data(os.path.join(dname, "abs.dat")) pways = dict() olow_cm = omega - INP.omega_uncertainty / 2.0 ohigh_cm = omega + INP.omega_uncertainty / 2.0 olow = qr.convert(olow_cm, "1/cm", "int") ohigh = qr.convert(ohigh_cm, "1/cm", "int") for t2 in time2.data: # this could save some memory of pathways become too big pways = dict() print("T2 =", t2, "fs (of T2_max =", time2.max, "fs)") twod = msc.calculate_one_system(t2, agg3, eUt, lab, pways=pways, dtol=1.0e-12, selection=[["omega2", [olow, ohigh]]]) pws = pways[str(t2)] npa = len(pws) has_R = False has_NR = False for pw in pws: if pw.pathway_type == "NR": has_NR = True elif pw.pathway_type == "R": has_R = True if t2 in t2_save_pathways: pws_name = os.path.join( dname, "pws_t2=" + str(t2) + "_omega2=" + str(omega) + data_descr + obj_ext) qr.save_parcel(pways[str(t2)], pws_name) cont_p.set_spectrum(twod) twod = msc.calculate_one_system(t2, agg3, eUt, lab, pways=pways, dtol=1.0e-12, selection=[["omega2", [-ohigh, -olow]]]) pws = pways[str(t2)] npa = len(pws) #print(" m:", npa) has_R = False has_NR = False for pw in pws: if pw.pathway_type == "NR": has_NR = True elif pw.pathway_type == "R": has_R = True #print(" R:", has_R, ", NR:", has_NR) if t2 in t2_save_pathways: pws_name = os.path.join( dname, "pws_t2=" + str(t2) + "_omega2=" + str(-omega) + data_descr + obj_ext) qr.save_parcel(pways[str(t2)], pws_name) cont_m.set_spectrum(twod) # calculation without pre-selecting pathways twod = msc.calculate_one_system(t2, agg3, eUt, lab, pways=pways, dtol=1.0e-12) cont_tot.set_spectrum(twod) # saving total spectrum to a directory for further analysis try: saveit = INP.total_spectrum["save_it"] except: saveit = False if saveit: try: dform = INP.total_spectrum["data_format"] except: dform = "dat" try: stp = INP.total_spectrum["spectra_type"] if stp == "TOTL": stype = qr.signal_TOTL elif stp == "REPH": stype = qr.signal_REPH elif stp == "NONR": stype = qr.signal_NONR else: raise Exception("Wrong signal type") except: stype = qr.signal_REPH save_spectra(cont_tot, ext=dform, dir=dname, stype=stype) # # Save aggregate when a single calculation is done # if save_eUt: fname = os.path.join(dname, "aggregate.qrp") agg3.save(fname) # # Window function for subsequenty FFT # window = func.Tukey(time2, r=INP.tukey_window_r, sym=False) # # FFT with the window function # # Specify REPH, NONR or `total` to get different types of spectra # print("Calculating FFT of the 2D maps") #fcont = cont.fft(window=window, dtype=stype) #, dpart="real", offset=0.0) fcont_p_re = cont_p.fft(window=window, dtype=qr.signal_REPH) fcont_p_nr = cont_p.fft(window=window, dtype=qr.signal_NONR) fcont_p_to = cont_p.fft(window=window, dtype=qr.signal_TOTL) if normalize_maps_to_maximu: fcont_p_re.normalize2(dpart=qr.part_ABS) fcont_p_nr.normalize2(dpart=qr.part_ABS) fcont_p_to.normalize2(dpart=qr.part_ABS) fcont_m_re = cont_m.fft(window=window, dtype=qr.signal_REPH) fcont_m_nr = cont_m.fft(window=window, dtype=qr.signal_NONR) fcont_m_to = cont_m.fft(window=window, dtype=qr.signal_TOTL) if normalize_maps_to_maximu: fcont_m_re.normalize2(dpart=qr.part_ABS) fcont_m_nr.normalize2(dpart=qr.part_ABS) fcont_m_to.normalize2(dpart=qr.part_ABS) if trim_maps: twin = INP.trim_maps_to with qr.energy_units("1/cm"): fcont_p_re.trimall_to(window=twin) fcont_p_nr.trimall_to(window=twin) fcont_p_to.trimall_to(window=twin) show_omega = omega with qr.frequency_units("1/cm"): sp1_p_re, show_Npoint1 = fcont_p_re.get_nearest(show_omega) sp2_p_re, show_Npoint2 = fcont_p_re.get_nearest(-show_omega) sp1_p_nr, show_Npoint1 = fcont_p_nr.get_nearest(show_omega) sp2_p_nr, show_Npoint2 = fcont_p_nr.get_nearest(-show_omega) sp1_p_to, show_Npoint1 = fcont_p_to.get_nearest(show_omega) sp2_p_to, show_Npoint2 = fcont_p_to.get_nearest(-show_omega) sp1_m_re, show_Npoint1 = fcont_m_re.get_nearest(show_omega) sp2_m_re, show_Npoint2 = fcont_m_re.get_nearest(-show_omega) sp1_m_nr, show_Npoint1 = fcont_m_nr.get_nearest(show_omega) sp2_m_nr, show_Npoint2 = fcont_m_nr.get_nearest(-show_omega) sp1_m_to, show_Npoint1 = fcont_m_to.get_nearest(show_omega) sp2_m_to, show_Npoint2 = fcont_m_to.get_nearest(-show_omega) sstm = platform.system() #print(sstm) if sstm != "Windows": import resource memo = resource.getrusage( resource.RUSAGE_SELF).ru_maxrss / (1024 * 1024) print("Memory usage: ", memo, "in MB") return (sp1_p_re, sp1_p_nr, sp2_m_re, sp2_m_nr)
# Aggregate with vibrational states, Hamiltonian generated up to single # exciton states in a Two-particle approximation # This object is used for calculation of dynamics # agg.build(mult=1, vibgen_approx="TPA") # # agg2 object will be used for calculation of 2D spectra # so it needs to know how to represent the spectra (what width it should have). # It also has to be built with # two-exciton states (in two-particle approximation) # for mol_name in transition_widths: width = qr.convert(transition_widths[mol_name], "1/cm", "int") mol = agg2.get_Molecule_by_name(mol_name) mol.set_transition_width((0,1), width) print("Aggregate has ", agg2.nmono, "single excited electronic states") agg2.build(mult=2, vibgen_approx="TPA") print("and ", agg2.Ntot, " (electro-vibrational) states in total") print("Number of single exciton states :", agg2.Nb[0]+agg2.Nb[1]) qr.save_parcel(agg2, os.path.join(pre_out,"agg2_built.qrp")) # # Electronic aggregate is built with single exciton states only
import numpy import quantarhei as qr qr.Manager().gen_conf.legacy_relaxation = True print("Preparing a model system:") with qr.energy_units("1/cm"): mol1 = qr.Molecule([0.0, 12010]) mol2 = qr.Molecule([0.0, 12000]) mol3 = qr.Molecule([0.0, 12100]) mol4 = qr.Molecule([0.0, 12110]) agg = qr.Aggregate([mol1, mol2, mol3, mol4]) agg.set_resonance_coupling(2, 3, qr.convert(100.0, "1/cm", "int")) agg.set_resonance_coupling(1, 3, qr.convert(100.0, "1/cm", "int")) agg.set_resonance_coupling(1, 2, qr.convert(0.0, "1/cm", "int")) qr.save_parcel(agg, "agg.qrp") agg2 = qr.load_parcel("agg.qrp") agg2.build() H = agg2.get_Hamiltonian() print("...done") print("Setting up Lindblad form relaxation:") Ndim = 5 with qr.eigenbasis_of(H): K12 = qr.qm.ProjectionOperator(1, 2, dim=Ndim)
def test_LindbladWithVibrations_dynamics_comp(self): """Compares Lindblad dynamics of a system with vibrations calculated from propagator and superoperator """ # Aggregate import quantarhei as qr time = qr.TimeAxis(0.0, 1000, 1.0) # create a model with qr.energy_units("1/cm"): me1 = qr.Molecule([0.0, 12100.0]) me2 = qr.Molecule([0.0, 12000.0]) me3 = qr.Molecule([0.0, 12900.0]) agg_el = qr.Aggregate([me1, me2, me3]) agg_el.set_resonance_coupling(0, 1, qr.convert(150, "1/cm", to="int")) agg_el.set_resonance_coupling(1, 2, qr.convert(50, "1/cm", to="int")) m1 = qr.Molecule([0.0, 12100.0]) m2 = qr.Molecule([0.0, 12000.0]) m3 = qr.Molecule([0.0, 12900.0]) mod1 = qr.Mode(frequency=qr.convert(100, "1/cm", "int")) m1.add_Mode(mod1) mod1.set_HR(1, 0.01) agg = qr.Aggregate([m1, m2, m3]) agg.set_resonance_coupling(0, 1, qr.convert(150, "1/cm", to="int")) agg.set_resonance_coupling(1, 2, qr.convert(50, "1/cm", to="int")) agg_el.build() agg.build() hame = agg_el.get_Hamiltonian() ham = agg.get_Hamiltonian() # calculate relaxation tensor with qr.eigenbasis_of(hame): # # Operator describing relaxation # K = qr.qm.ProjectionOperator(1, 2, dim=hame.dim) # # System bath interaction with prescribed rate # from quantarhei.qm import SystemBathInteraction sbi = SystemBathInteraction(sys_operators=[K], rates=(1.0 / 100.0, )) sbi.set_system(agg) #agg.set_SystemBathInteraction(sbi) with qr.eigenbasis_of(ham): # # Corresponding Lindblad form # from quantarhei.qm import ElectronicLindbladForm LF = ElectronicLindbladForm(ham, sbi, as_operators=True) # # Evolution of reduced density matrix # prop = qr.ReducedDensityMatrixPropagator(time, ham, LF) # # Evolution by superoperator # eSO = qr.qm.EvolutionSuperOperator(time, ham, LF) eSO.set_dense_dt(5) eSO.calculate() # compare the two propagations pairs = [(5, 4), (5, 5), (6, 5), (7, 5)] for p in pairs: rho_i1 = qr.ReducedDensityMatrix(dim=ham.dim) rho_i1.data[p[0], p[1]] = 1.0 rho_t1 = prop.propagate(rho_i1) exp_rho_t2 = eSO.data[:, :, :, p[0], p[1]] #import matplotlib.pyplot as plt #plt.plot(rho_t1.TimeAxis.data, numpy.real(rho_t1.data[:,p[0],p[1]]), "-r") #plt.plot(rho_t1.TimeAxis.data, numpy.real(exp_rho_t2[:,p[0],p[1]]), "--g") #plt.show() #for kk in range(rho_t1.TimeAxis.length): # print(kk, numpy.real(rho_t1.data[kk,p[0],p[1]]),numpy.real(exp_rho_t2[kk,p[0],p[1]])) #numpy.testing.assert_allclose(RRT.data, rtd) numpy.testing.assert_allclose(numpy.real(rho_t1.data[:, :, :]), numpy.real(exp_rho_t2[:, :, :]), rtol=5.0e-2, atol=1.0e-3)
# Create an aggregate # agg = qr.Aggregate(molecules=[mol]) agg.build() # # Time axes and the calculator # t1axis = qr.TimeAxis(0.0, 1000, 10.0) t3axis = qr.TimeAxis(0.0, 1000, 10.0) t2axis = qr.TimeAxis(0.0, Nt2, dt2) # FIXME: TwoDResponseCalculator msc = qr.MockTwoDResponseCalculator(t1axis, t2axis, t3axis) msc.bootstrap(rwa=qr.convert(E1,"1/cm","int"), all_positive=False, shape="Gaussian") # # Laboratory setup # lab = LabSetup() lab.set_polarizations(pulse_polarizations=[X,X,X], detection_polarization=X) # # Hamiltonian is required # H = agg.get_Hamiltonian() #
with qr.energy_units("1/cm"): agg.set_resonance_coupling_matrix(J_Matrix[0:3, 0:3]) #agg.save("RC_Model_40_4_adjusted_CT_no_environment_unbuilt.hdf5") qr.save_parcel( agg, os.path.join(pre_out, "RC_Model_40_4_adjusted_CT_no_environment_unbuilt.qrp")) # In[3]: # check that units were set correctly rc = agg.resonance_coupling[1, 0] with qr.energy_units("1/cm"): print(qr.convert(rc, "int")) with qr.energy_units("1/cm"): print(agg.get_resonance_coupling(1, 0)) # In[4]: # Bath correlation function time = qr.TimeAxis(0.0, 1000, 1.0) cfA_params = dict(ftype="OverdampedBrownian", reorg=190, cortime=80, T=77, matsubara=100) cfH_params = dict(ftype="OverdampedBrownian",
# # In[37]: frac_electronic.report_on_expansion(3, N=4) # # State 3 is a clear anti-symmetric mixture of P(+) and B # # In[38]: N1 = frac_electronic.Nbe[1] print("Energies in 1/cm:") print([ qr.convert(frac_electronic.HH[i, i], "int", "1/cm") for i in range(1, N1 + 1) ]) # In[39]: # # Transition dipoles square # print("Transition dipoles square:") print(frac_electronic.D2[1:N1 + 1, 0]) # In[40]: #frac.save("fraction_45_2_vibrations_CT_built.hdf5") qr.save_parcel(frac,
def run(omega, HR, dE, JJ, rate, vib_loc="up", use_vib=True, stype=qr.signal_REPH, make_movie=False): """Runs a complete set of simulations for a single set of parameters """ # # FIXED PARAMETERS # E0 = 10000.0 dip1 = [1.5, 0.0, 0.0] dip2 = [-1.0, -1.0, 0.0] width = 100.0 #rate = 1.0/50.0 normalize_maps_to_maximu = False trim_maps = False units = "1/cm" with qr.energy_units(units): data_descr = "_dO="+str(dE-omega)+"_HR="+str(HR)+"_J="+str(JJ) if use_vib: sys_char = "_vib" else: sys_char = "_ele" data_ext = sys_char+".png" obj_ext = sys_char+".qrp" # # Model system is a dimer of molecules # with qr.energy_units("1/cm"): mol1 = qr.Molecule([0.0, E0]) mol2 = qr.Molecule([0.0, E0+dE]) mod1 = qr.Mode(omega) mod2 = qr.Mode(omega) mol1.set_transition_width((0,1), qr.convert(width, "1/cm", "int")) mol1.set_dipole(0,1, dip1) mol2.set_transition_width((0,1), qr.convert(width, "1/cm", "int")) mol2.set_dipole(0,1, dip2) agg = qr.Aggregate([mol1, mol2]) with qr.energy_units("1/cm"): agg.set_resonance_coupling(0,1,JJ) # # Electronic only aggregate # agg_el = agg.deepcopy() # # if nuclear vibrations are to be added, do it here # if use_vib: if vib_loc == "down": set_vib = [True, False] elif vib_loc == "up": set_vib = [False, True] elif vib_loc == "both": set_vib = [True, True] else: raise Exception("Unknown location of the vibrations") if set_vib[0]: mol1.add_Mode(mod1) mod1.set_nmax(0, 3) mod1.set_nmax(1, 3) mod1.set_HR(1, HR) if set_vib[1]: mol2.add_Mode(mod2) mod2.set_nmax(0, 3) mod2.set_nmax(1, 3) mod2.set_HR(1, HR) agg3 = agg.deepcopy() agg.build(mult=1) agg_el.build(mult=1) HH = agg.get_Hamiltonian() He = agg_el.get_Hamiltonian() with qr.energy_units("1/cm"): with qr.eigenbasis_of(He): Ep_l = He.data[1,1] Ep_u = He.data[2,2] Ep = numpy.zeros((4,2)) Ep[0,0] = Ep_l Ep[0,1] = Ep_l Ep[1,0] = Ep_l Ep[1,1] = Ep_u Ep[2,0] = Ep_u Ep[2,1] = Ep_l Ep[3,0] = Ep_u Ep[3,1] = Ep_u # # Laboratory setup # lab = qr.LabSetup() lab.set_polarizations(pulse_polarizations=[X,X,X], detection_polarization=X) time2 = qr.TimeAxis(0.0, 100, 10.0) cont_p = qr.TwoDResponseContainer(t2axis=time2) cont_m = qr.TwoDResponseContainer(t2axis=time2) # # spectra will be indexed by the times in the time axis `time2` # cont_p.use_indexing_type(time2) # # We define two-time axes, which will be FFTed and will define # the omega_1 and omega_3 axes of the 2D spectrum # t1_N_steps = 100 t1_time_step = 10.0 t3_N_steps = 100 t3_time_step = 10.0 t1axis = qr.TimeAxis(0.0, t1_N_steps, t1_time_step) t3axis = qr.TimeAxis(0.0, t3_N_steps, t3_time_step) # # This calculator calculated 2D spectra from the effective width # msc = qr.MockTwoDResponseCalculator(t1axis, time2, t3axis) with qr.energy_units("1/cm"): msc.bootstrap(rwa=E0, shape="Gaussian") # # System-bath interaction including vibrational states # operators = [] rates = [] with qr.eigenbasis_of(He): operators.append(qr.qm.ProjectionOperator(1, 2, dim=He.dim)) rates.append(rate) sbi = qr.qm.SystemBathInteraction(sys_operators=operators, rates=rates) sbi.set_system(agg) # # Liouville form for relaxation # LF = qr.qm.ElectronicLindbladForm(HH, sbi, as_operators=True) # # Pure dephasing # p_deph = qr.qm.ElectronicPureDephasing(agg, dtype="Gaussian") eUt = qr.qm.EvolutionSuperOperator(time2, HH, relt=LF, pdeph=p_deph, mode="all") eUt.set_dense_dt(10) # # We calculate evolution superoperator # eUt.calculate(show_progress=False) # # Prepare aggregate with all states (including 2-EX band) # agg3.build(mult=2) agg3.diagonalize() pways = dict() t2_save_pathways = [300.0] olow = qr.convert(omega-30.0, "1/cm", "int") ohigh = qr.convert(omega+30.0, "1/cm", "int") for t2 in time2.data: # this could save some memory of pathways become too big pways = dict() print("t2 =", t2) twod = msc.calculate_one_system(t2, agg3, eUt, lab, pways=pways, selection=[["omega2",[olow, ohigh]]]) print("Number of pathways used for omega2 =",omega,":", len(pways[str(t2)])) if t2 in t2_save_pathways: pws_name = os.path.join("sim_"+vib_loc, "pws_t2="+str(t2)+ "_omega2="+str(omega)+data_descr+data_ext) qr.save_parcel(pways[str(t2)], pws_name) cont_p.set_spectrum(twod) twod = msc.calculate_one_system(t2, agg3, eUt, lab, pways=pways, selection=[["omega2",[-ohigh, -olow]]]) print("Number of pathways used for omega2 =",-omega,":", len(pways[str(t2)])) if t2 in t2_save_pathways: pws_name = os.path.join("sim_"+vib_loc, "pws_t2="+str(t2)+ "_omega2="+str(-omega)+data_descr+data_ext) qr.save_parcel(pways[str(t2)], pws_name) cont_m.set_spectrum(twod) if make_movie: with qr.energy_units("1/cm"): cont_p.make_movie("mov.mp4") fname = os.path.join("sim_"+vib_loc, "pways.qrp") qr.save_parcel(pways, fname) fname = os.path.join("sim_"+vib_loc, "aggregate.qrp") agg3.save(fname) # # Window function for subsequenty FFT # window = func.Tukey(time2, r=0.3, sym=False) # # FFT with the window function # # Specify REPH, NONR or `total` to get different types of spectra # print("\nCalculating FFT of the 2D maps") #fcont = cont.fft(window=window, dtype=stype) #, dpart="real", offset=0.0) fcont_p_re = cont_p.fft(window=window, dtype=qr.signal_REPH) fcont_p_nr = cont_p.fft(window=window, dtype=qr.signal_NONR) fcont_p_to = cont_p.fft(window=window, dtype=qr.signal_TOTL) if normalize_maps_to_maximu: fcont_p_re.normalize2(dpart=qr.part_ABS) fcont_p_nr.normalize2(dpart=qr.part_ABS) fcont_p_to.normalize2(dpart=qr.part_ABS) fcont_m_re = cont_m.fft(window=window, dtype=qr.signal_REPH) fcont_m_nr = cont_m.fft(window=window, dtype=qr.signal_NONR) fcont_m_to = cont_m.fft(window=window, dtype=qr.signal_TOTL) if normalize_maps_to_maximu: fcont_m_re.normalize2(dpart=qr.part_ABS) fcont_m_nr.normalize2(dpart=qr.part_ABS) fcont_m_to.normalize2(dpart=qr.part_ABS) if trim_maps: twin = [9500, 11000, 9500, 11000] with qr.energy_units("1/cm"): fcont_p_re.trimall_to(window=twin) fcont_p_nr.trimall_to(window=twin) fcont_p_to.trimall_to(window=twin) show_omega = omega # # Have a look which frequencies we actually have # # Ndat = len(fcont_re.axis.data) # print("\nNumber of frequency points:", Ndat) # print("In 1/cm they are:") # with qr.energy_units("1/cm"): # for k_i in range(Ndat): # print(k_i, fcont_re.axis.data[k_i]) with qr.frequency_units("1/cm"): sp1_p_re, show_Npoint1 = fcont_p_re.get_nearest(show_omega) sp2_p_re, show_Npoint2 = fcont_p_re.get_nearest(-show_omega) sp1_p_nr, show_Npoint1 = fcont_p_nr.get_nearest(show_omega) sp2_p_nr, show_Npoint2 = fcont_p_nr.get_nearest(-show_omega) sp1_p_to, show_Npoint1 = fcont_p_to.get_nearest(show_omega) sp2_p_to, show_Npoint2 = fcont_p_to.get_nearest(-show_omega) sp1_m_re, show_Npoint1 = fcont_m_re.get_nearest(show_omega) sp2_m_re, show_Npoint2 = fcont_m_re.get_nearest(-show_omega) sp1_m_nr, show_Npoint1 = fcont_m_nr.get_nearest(show_omega) sp2_m_nr, show_Npoint2 = fcont_m_nr.get_nearest(-show_omega) sp1_m_to, show_Npoint1 = fcont_m_to.get_nearest(show_omega) sp2_m_to, show_Npoint2 = fcont_m_to.get_nearest(-show_omega) # units = "1/cm" # with qr.energy_units(units): # # data_descr = "_dO="+str(dE-omega)+"_HR="+str(HR)+"_J="+str(JJ) # # if use_vib: # sys_char = "_vib" # else: # sys_char = "_ele" # data_ext = sys_char+".png" # obj_ext = sys_char+".qrp" with qr.energy_units(units): print("\nPlotting and saving spectrum at frequency:", fcont_p_re.axis.data[show_Npoint1], units) fftf_1 = os.path.join("sim_"+vib_loc, "twod_fft"+data_descr+ "_stype=REPH"+"_omega="+str(omega)+data_ext) sp1_p_re.plot(Npos_contours=10, spart=qr.part_ABS, label="Rephasing\n $\omega="+str(omega)+ "$ cm$^{-1}$", text_loc=[0.05,0.1], show_states=[Ep_l, Ep_u, Ep_u+numpy.abs(omega)], show_diagonal="-k") sp1_p_re.savefig(fftf_1) print("... saved into: ", fftf_1) fftf_2 = os.path.join("sim_"+vib_loc, "twod_fft"+data_descr+ "_stype=NONR"+"_omega="+str(omega)+data_ext) sp1_p_nr.plot(Npos_contours=10, spart=qr.part_ABS, label="Non-rephasing\n $\omega="+str(omega)+ "$ cm$^{-1}$", text_loc=[0.05,0.1], show_states=[Ep_l, Ep_u, Ep_u+numpy.abs(omega)], show_diagonal="-k") sp1_p_nr.savefig(fftf_2) print("... saved into: ", fftf_2) fftf_3 = os.path.join("sim_"+vib_loc, "twod_fft"+data_descr+ "_stype=tot"+"_omega="+str(omega)+data_ext) sp1_p_to.plot(Npos_contours=10, spart=qr.part_ABS, label="Total\n $\omega="+str(omega)+ "$ cm$^{-1}$", text_loc=[0.05,0.1], show_states=[Ep_l, Ep_u, Ep_u+numpy.abs(omega)], show_diagonal="-k") sp1_p_to.savefig(fftf_3) print("... saved into: ", fftf_3) # # Point evolutions at the expected peak positions # if show_plots: for ii in range(4): points = fcont_p_re.get_point_evolution(Ep[ii,0], Ep[ii,1], fcont_p_re.axis) points.apply_to_data(numpy.abs) if ii >= 3: points.plot(show=True) else: points.plot(show=False) print("\nPlotting and saving spectrum at frequency:", fcont_m_re.axis.data[show_Npoint2], units) fftf_4 = os.path.join("sim_"+vib_loc, "twod_fft"+data_descr+ "_stype=REPH"+"_omega="+str(-omega)+data_ext) sp2_m_re.plot(Npos_contours=10, spart=qr.part_ABS, label="Rephasing\n $\omega="+str(-omega)+ "$ cm$^{-1}$", text_loc=[0.05,0.1], show_states=[Ep_l, Ep_u, Ep_u+numpy.abs(omega)], show_diagonal="-k") sp2_m_re.savefig(fftf_4) print("... saved into: ", fftf_4) fftf_5 = os.path.join("sim_"+vib_loc, "twod_fft"+data_descr+ "_stype=NONR"+"_omega="+str(-omega)+data_ext) sp2_m_nr.plot(Npos_contours=10, spart=qr.part_ABS, label="Non-rephasing\n $\omega="+str(-omega)+ "$ cm$^{-1}$", text_loc=[0.05,0.1], show_states=[Ep_l, Ep_u, Ep_u+numpy.abs(omega)], show_diagonal="-k") sp2_m_nr.savefig(fftf_5) print("... saved into: ", fftf_5) fftf_6 = os.path.join("sim_"+vib_loc, "twod_fft"+data_descr+ "_stype=tot"+"_omega="+str(-omega)+data_ext) sp2_m_to.plot(Npos_contours=10, spart=qr.part_ABS, label="Total\n $\omega="+str(-omega)+ "$ cm$^{-1}$", text_loc=[0.05,0.1], show_states=[Ep_l, Ep_u, Ep_u+numpy.abs(omega)], show_diagonal="-k") sp2_m_to.savefig(fftf_6) print("... saved into: ", fftf_6) if show_plots: # # Point evolutions at the expected peak positions # for ii in range(4): points = fcont_p_re.get_point_evolution(Ep[ii,0], Ep[ii,1], fcont_m_re.axis) points.apply_to_data(numpy.abs) if ii >= 3: points.plot(show=True) else: points.plot(show=False) #points.apply_to_data(numpy.abs) #points.plot() # saving containers # fname = os.path.join("sim_"+vib_loc,"fcont_re"+data_descr+obj_ext) # print("Saving container into: "+fname) # fcont_p_re.save(fname) # fname = os.path.join("sim_"+vib_loc,"fcont_nr"+data_descr+obj_ext) # print("Saving container into: "+fname) # fcont_p_nr.save(fname) # fname = os.path.join("sim_"+vib_loc,"fcont_to"+data_descr+obj_ext) # print("Saving container into: "+fname) # fcont_p_to.save(fname) fname = os.path.join("sim_"+vib_loc,"cont_p"+data_descr+obj_ext) print("Saving container into: "+fname) cont_p.save(fname) fname = os.path.join("sim_"+vib_loc,"cont_m"+data_descr+obj_ext) print("Saving container into: "+fname) cont_m.save(fname) return (sp1_p_re, sp1_p_nr, sp2_m_re, sp2_m_nr)
with qr.energy_units("1/cm"): agg.set_resonance_coupling_matrix(J_Matrix[0:3,0:3]) #agg.save("RC_Model_40_4_adjusted_CT_no_environment_unbuilt.hdf5") qr.save_parcel(agg, os.path.join(pre_out, "RC_Model_40_4_adjusted_CT_no_environment_unbuilt.qrp")) # In[3]: # check that units were set correctly rc = agg.resonance_coupling[1,0] with qr.energy_units("1/cm"): print(qr.convert(rc, "int")) with qr.energy_units("1/cm"): print(agg.get_resonance_coupling(1,0)) # In[4]: # Bath correlation function time = qr.TimeAxis(0.0, 1000, 1.0) cfA_params = dict(ftype="OverdampedBrownian", reorg=190, cortime=80, T=77, matsubara=100) cfH_params = dict(ftype="OverdampedBrownian", reorg=200, cortime=100, T=77, matsubara=100)
# # Set the correlation function to the transitions on the molecules # m1.set_transition_environment((0, 1), cf) m2.set_transition_environment((0, 1), cf) # # Build the aggregate # agg.build() # # Calculate absorption spectrum # asc = qr.AbsSpectrumCalculator(time, system=agg) asc.bootstrap(rwa=qr.convert(10050, "1/cm", "int"), lab=lab) abs1 = asc.calculate(raw=False) abs1.normalize2() # # Plot the absorption spectrum # with qr.energy_units("1/cm"): abs1.plot(axis=[9000, 12000, 0.0, 1.01], color="b", show=False) ############################################################################### # # Calculation using effective Gaussian lineshape # ###############################################################################
import quantarhei as qr qr.Manager().gen_conf.legacy_relaxation = True print("Preparing a model system:") with qr.energy_units("1/cm"): mol1 = qr.Molecule([0.0, 12000]) mol2 = qr.Molecule([0.0, 12000]) mol3 = qr.Molecule([0.0, 12100]) mol4 = qr.Molecule([0.0, 12100]) agg = qr.Aggregate([mol1, mol2, mol3, mol4]) agg.set_resonance_coupling(2,3,qr.convert(100.0,"1/cm","int")) agg.set_resonance_coupling(1,3,qr.convert(100.0,"1/cm","int")) with tempfile.TemporaryDirectory() as tdir: path = os.path.join(tdir,"agg.qrp") qr.save_parcel(agg,path) agg2 = qr.load_parcel(path) agg2.build() H = agg2.get_Hamiltonian() print("...done") print("Setting up Lindblad form relaxation:") Ndim = 5
with qr.energy_units('1/cm'): sd_low_freq = qr.SpectralDensity(t_ax_sd, params) # Adding the high freq modes sd_high_freq = db.get_SpectralDensity(t_ax_sd, "Wendling_JPCB_104_2000_5825") ax = sd_low_freq.axis sd_high_freq.axis = ax sd_tot = sd_low_freq + sd_high_freq cf = sd_tot.get_CorrelationFunction(temperature=temperature, ta=t_ax_sd) # Assigning the correlation function to the list of molecules for mol in for_agg: mol.set_transition_environment((0, 1), cf) if _test_: reorg = qr.convert(sd_low_freq.get_reorganization_energy(), "int", "1/cm") print("input_reorg - ", reorg) with qr.energy_units("1/cm"): sd_tot.plot(show=True, axis=[0, 2000, 0.0, np.max(sd_tot.data)]) cf.plot(show=True) ####################################################################### # Dynamics ####################################################################### # Test the setup by calculating the dynamics at same and diff energies if _test_: energies1 = [energy] * num_mol energies2 = [energy - (100 * num_mol / 2)\ + i * 100 for i in range(num_mol)]
print("Fitted population decay time (exciton basis): ", 1.0 / popt_p_e[1]) print("Fitted population decay time (site basis): ", 1.0 / popt_p_s[1]) else: popt_p_e = [0.0, 10000.0] popt_p_s = [0.0, 10000.0] if J == 0.0: rat = 0.0 balance = 0.0 else: rat = popt_p_e[1] kBT = qr.core.units.kB_int * Temperature print("kBT = ", qr.convert(kBT, "int", "1/cm"), "cm^-1") with qr.eigenbasis_of(ham): balance = rat * numpy.exp( -(ham.data[2, 2] - ham.data[1, 1]) / kBT) print("Uphill decay time from canonical detailed balance: ", 1.0 / balance) rate_predicted = 0.5 * balance + 0.5 * rat print( "Prediction for the decoherence time" + " based on population transfer:", 1.0 / rate_predicted) # # Exponential fitting of opt_coh and ext_coh #
# # Integration over disorder # for e1 in es1: for e2 in es2: e_shift = e1 - Ecalc DE = e2 - e1 # get the spectrum with DE and shift it by e_shift (N_DE, err) = des.locate(DE) #print(DE, N_DE, weight(e1, E1, width_dis[0])* # weight(e2, E2, width_dis[1])) twod_a = spects[N_DE].deepcopy() twod_a.shift_energy(qr.convert(e_shift,"1/cm","int")) data[:,:] += weight(e1, E1, width_dis[0])* \ weight(e2, E2, width_dis[1])*twod_a.data[:,:] twod_a.data[:,:] = data[:,:]/(N1_1*N1_2) with qr.energy_units("1/cm"): twod_a.plot(spart=qr.part_ABS) if INP.save_fig: twod_a.savefig(INP.fig_file) if INP.save_spectrum: twod_a.save(INP.spectrum_file)
# set bath correlation functions to the molecules for i_m in range(N_molecules): mols[i_m].set_transition_environment((0, 1), cf) # aggregate of molecules agg = qr.Aggregate(mols) agg.set_coupling_by_dipole_dipole() # Building the aggregate qr.log_report("Building aggregate") agg.build() qr.log_report("...done") qr.log_detail("Resonance coupling matrix: ") qr.log_detail(qr.convert(agg.resonance_coupling, "int", "1/cm"), use_indent=False) # Dimension of the problem HH = agg.get_Hamiltonian() Nr = HH.dim qr.log_detail("Hamiltonian has a rank:", Nr) benchmark_report["Dimension"] = Nr qr.log_report("Calculating Relaxation tensor:") t1 = time.time() (RT, ham) = agg.get_RelaxationTensor(timea, relaxation_theory="standard_Redfield", as_operators=True) t2 = time.time()
def test_LindbladWithVibrations_dynamics_comp(self): """Compares Lindblad dynamics of a system with vibrations calculated from propagator and superoperator """ # Aggregate import quantarhei as qr time = qr.TimeAxis(0.0, 1000, 1.0) # create a model with qr.energy_units("1/cm"): me1 = qr.Molecule([0.0, 12100.0]) me2 = qr.Molecule([0.0, 12000.0]) me3 = qr.Molecule([0.0, 12900.0]) agg_el = qr.Aggregate([me1, me2, me3]) agg_el.set_resonance_coupling(0, 1, qr.convert(150, "1/cm", to="int")) agg_el.set_resonance_coupling(1, 2, qr.convert(50, "1/cm", to="int")) m1 = qr.Molecule([0.0, 12100.0]) m2 = qr.Molecule([0.0, 12000.0]) m3 = qr.Molecule([0.0, 12900.0]) mod1 = qr.Mode(frequency=qr.convert(100, "1/cm", "int")) m1.add_Mode(mod1) mod1.set_HR(1, 0.01) agg = qr.Aggregate([m1, m2, m3]) agg.set_resonance_coupling(0, 1, qr.convert(150, "1/cm", to="int")) agg.set_resonance_coupling(1, 2, qr.convert(50, "1/cm", to="int")) agg_el.build() agg.build() hame = agg_el.get_Hamiltonian() ham = agg.get_Hamiltonian() # calculate relaxation tensor with qr.eigenbasis_of(hame): # # Operator describing relaxation # K = qr.qm.ProjectionOperator(1, 2, dim=hame.dim) # # System bath interaction with prescribed rate # from quantarhei.qm import SystemBathInteraction sbi = SystemBathInteraction(sys_operators=[K], rates=(1.0/100.0,)) sbi.set_system(agg) #agg.set_SystemBathInteraction(sbi) with qr.eigenbasis_of(ham): # # Corresponding Lindblad form # from quantarhei.qm import ElectronicLindbladForm LF = ElectronicLindbladForm(ham, sbi, as_operators=True) # # Evolution of reduced density matrix # prop = qr.ReducedDensityMatrixPropagator(time, ham, LF) # # Evolution by superoperator # eSO = qr.qm.EvolutionSuperOperator(time, ham, LF) eSO.set_dense_dt(5) eSO.calculate() # compare the two propagations pairs = [(5,4), (5,5), (6,5), (7,5)] for p in pairs: rho_i1 = qr.ReducedDensityMatrix(dim=ham.dim) rho_i1.data[p[0],p[1]] = 1.0 rho_t1 = prop.propagate(rho_i1) exp_rho_t2 = eSO.data[:,:,:,p[0],p[1]] #import matplotlib.pyplot as plt #plt.plot(rho_t1.TimeAxis.data, numpy.real(rho_t1.data[:,p[0],p[1]]), "-r") #plt.plot(rho_t1.TimeAxis.data, numpy.real(exp_rho_t2[:,p[0],p[1]]), "--g") #plt.show() #for kk in range(rho_t1.TimeAxis.length): # print(kk, numpy.real(rho_t1.data[kk,p[0],p[1]]),numpy.real(exp_rho_t2[kk,p[0],p[1]])) #numpy.testing.assert_allclose(RRT.data, rtd) numpy.testing.assert_allclose(numpy.real(rho_t1.data[:,:,:]), numpy.real(exp_rho_t2[:,:,:]), rtol=5.0e-2, atol=1.0e-3)
eUt = qr.qm.EvolutionSuperOperator(time2, HH, relt=LF, pdeph=p_deph, mode="all") eUt.set_dense_dt(fine_splitting) # # We calculate evolution superoperator # eUt.calculate(show_progress=False) olow_cm = omega - 10.0 / 2.0 ohigh_cm = omega + 10.0 / 2.0 olow = qr.convert(olow_cm, "1/cm", "int") ohigh = qr.convert(ohigh_cm, "1/cm", "int") print("---") print("Calculating 2D spectra") for t2 in time2.data: # this could save some memory of pathways become too big pways = dict() print("T2 =", t2, "fs (of T2_max =", time2.max, "fs)") twod = msc.calculate_one_system(t2, agg, eUt, lab,
# set bath correlation functions to the molecules for i_m in range(N_molecules): mols[i_m].set_transition_environment((0, 1), cf) # aggregate of molecules agg = qr.Aggregate(mols) agg.set_coupling_by_dipole_dipole() # Building the aggregate qr.log_report("Building aggregate") agg.build() qr.log_report("...done") qr.log_detail("Resonance coupling matrix: ") qr.log_detail(qr.convert(agg.resonance_coupling, "int", "1/cm"), use_indent=False) # Dimension of the problem HH = agg.get_Hamiltonian() Nr = HH.dim qr.log_detail("Hamiltonian has a rank:", Nr) benchmark_report["Dimension"] = Nr qr.log_report("Calculating Relaxation tensor:") t1 = time.time() (RT, ham) = agg.get_RelaxationTensor(timea, relaxation_theory="standard_Redfield", as_operators=True) t2 = time.time()
Np = 13 ex2Dfile = "test.png" plot_window = [11000, 13500, 11000, 13500] t1axis = qr.TimeAxis(0.0, 1000, 1.0) t2axis = qr.TimeAxis(0.0, 100, 10.0) t3axis = qr.TimeAxis(0.0, 1000, 1.0) pws = qr.load_parcel(os.path.join(pre_in,filename)) print(len(pws)) mscal = qr.MockTwoDSpectrumCalculator(t1axis, t2axis, t3axis) mscal.bootstrap(rwa=qr.convert(12200,"1/cm","int")) pw = pws[Np] mscal.set_pathways([pw]) twod = mscal.calculate() eUt = qr.load_parcel(os.path.join(pre_in,"eUt.qrp")) oset = qr.load_parcel(os.path.join(dirn,"A_saved_state.qrp")) with qr.energy_units("1/cm"): print(pw) twod.plot(window=plot_window, Npos_contours=10, stype="total", spart="real") plt.show()
def run(omega, HR, dE, JJ, rate, E0, vib_loc="up", use_vib=True, stype=qr.signal_REPH, make_movie=False, save_eUt=False, t2_save_pathways=[], dname=None, trimer=None, disE=None): """Runs a complete set of simulations for a single set of parameters If disE is not None it tries to run averaging over Gaussian energetic disorder. """ if dname is None: dname = "sim_" + vib_loc use_trimer = trimer["useit"] rate_sp = trimer["rate"] # # PARAMETERS FROM INPUT FILE # dip1 = INP.dip1 # [1.5, 0.0, 0.0] dip2 = INP.dip2 # [-1.0, -1.0, 0.0] width = INP.feature_width # 100.0 width2 = INP.feature_width2 normalize_maps_to_maximu = False trim_maps = False units = "1/cm" with qr.energy_units(units): data_descr = "_dO=" + str(dE) + "_omega=" + str(omega) + "_HR=" + str( HR) + "_J=" + str(JJ) if use_vib: sys_char = "_vib" else: sys_char = "_ele" data_ext = sys_char + ".png" obj_ext = sys_char + ".qrp" # parameters of the SP if use_trimer: E2 = trimer["E2"] epsa = (E0 + E2) / 2.0 DE = trimer["DE"] J2 = 0.5 * numpy.sqrt(((E0 - E2)**2) - (DE**2)) ESP2 = epsa + DE / 2.0 ESP1 = epsa - DE / 2.0 # # Model system is a dimer of molecules # with qr.energy_units("1/cm"): if not use_trimer: mol1 = qr.Molecule([0.0, E0]) mol2 = qr.Molecule([0.0, E0 + dE]) print("Monomer 1 energy:", E0) print("Monomer 2 energy:", E0 + dE) else: if disE is not None: mol1 = qr.Molecule([0.0, ESP2 + disE[0]]) mol2 = qr.Molecule([0.0, E0 + dE + disE[1]]) print("Monomer 1 (SP_high) energy:", ESP2 + disE[0]) print("Monomer 2 (B) energy:", E0 + dE + disE[1]) else: mol1 = qr.Molecule([0.0, ESP2]) mol2 = qr.Molecule([0.0, E0 + dE]) print("Monomer 1 (SP_high) energy:", ESP2) print("Monomer 2 (B) energy:", E0 + dE) if disE is not None: mol3 = qr.Molecule([0.0, ESP1 + disE[2]]) print("Monomer 3 (SP_low) energy:", ESP1 + disE[2]) else: mol3 = qr.Molecule([0.0, ESP1]) print("Monomer 3 (SP_low) energy:", ESP1) mol3.set_transition_width((0, 1), width2) mol3.set_dipole(0, 1, trimer["dipsp"]) mol1.set_transition_width((0, 1), width2) mol1.set_dipole(0, 1, dip1) mol2.set_transition_width((0, 1), width) mol2.set_dipole(0, 1, dip2) if use_trimer: agg = qr.Aggregate([mol1, mol2, mol3]) else: agg = qr.Aggregate([mol1, mol2]) if use_trimer: with qr.energy_units("1/cm"): agg.set_resonance_coupling(0, 1, JJ) print("B - SP_high coupling:", JJ) agg.set_resonance_coupling(0, 2, J2) print("SP coupling:", J2) else: with qr.energy_units("1/cm"): agg.set_resonance_coupling(0, 1, JJ) # # Electronic only aggregate # agg_el = agg.deepcopy() # # if nuclear vibrations are to be added, do it here # if use_vib: with qr.energy_units("1/cm"): mod1 = qr.Mode(omega) mod2 = qr.Mode(omega) if vib_loc == "down": set_vib = [True, False] elif vib_loc == "up": set_vib = [False, True] elif vib_loc == "both": set_vib = [True, True] else: raise Exception("Unknown location of the vibrations") if set_vib[0]: print("Vibrations set for SP_high molecule") mol1.add_Mode(mod1) mod1.set_nmax(0, INP.no_g_vib) mod1.set_nmax(1, INP.no_e_vib) mod1.set_HR(1, HR) if set_vib[1]: print("Vibrations set for B molecule") mol2.add_Mode(mod2) mod2.set_nmax(0, INP.no_g_vib) mod2.set_nmax(1, INP.no_e_vib) mod2.set_HR(1, HR) agg3 = agg.deepcopy() agg.build(mult=1) agg_el.build(mult=1) HH = agg.get_Hamiltonian() He = agg_el.get_Hamiltonian() # # Laboratory setup # lab = qr.LabSetup() lab.set_polarizations(pulse_polarizations=[X, X, X], detection_polarization=X) t2_N_steps = INP.t2_N_steps t2_time_step = INP.t2_time_step time2 = qr.TimeAxis(0.0, t2_N_steps, t2_time_step) cont_p = qr.TwoDResponseContainer(t2axis=time2) cont_m = qr.TwoDResponseContainer(t2axis=time2) # # spectra will be indexed by the times in the time axis `time2` # cont_p.use_indexing_type(time2) # # We define two-time axes, which will be FFTed and will define # the omega_1 and omega_3 axes of the 2D spectrum # t1_N_steps = INP.t1_N_steps t1_time_step = INP.t1_time_step t3_N_steps = INP.t3_N_steps t3_time_step = INP.t3_time_step t1axis = qr.TimeAxis(0.0, t1_N_steps, t1_time_step) t3axis = qr.TimeAxis(0.0, t3_N_steps, t3_time_step) # # This calculator calculated 2D spectra from the effective width # msc = qr.MockTwoDResponseCalculator(t1axis, time2, t3axis) with qr.energy_units("1/cm"): msc.bootstrap(rwa=E0, shape="Gaussian") # # System-bath interaction including vibrational states # operators = [] rates = [] if use_trimer: print("Relaxation rates: ", rate, rate_sp) with qr.eigenbasis_of(He): if He.data[3, 3] < He.data[2, 2]: Exception("Electronic states not orderred!") operators.append(qr.qm.ProjectionOperator(2, 3, dim=He.dim)) with qr.energy_units("1/cm"): print("2<-3", He.data[2, 2], He.data[3, 3]) rates.append(rate) print("Transfer time B -> SP:", 1.0 / rate) if He.data[2, 2] < He.data[1, 1]: Exception("Electronic states not orderred!") operators.append(qr.qm.ProjectionOperator(1, 2, dim=He.dim)) with qr.energy_units("1/cm"): print("1<-2", He.data[1, 1], He.data[2, 2]) rates.append(rate_sp) print("Transfer time P+ -> P-:", 1.0 / rate_sp) # include detailed balace if detailed_balance: with qr.eigenbasis_of(He): T = INP.temperature #77.0 Den = (He.data[3, 3] - He.data[2, 2]) / (kB_int * T) operators.append(qr.qm.ProjectionOperator(3, 2, dim=He.dim)) thermal_fac = numpy.exp(-Den) rates.append(rate * thermal_fac) else: with qr.eigenbasis_of(He): if He.data[2, 2] < He.data[1, 1]: Exception("Electronic states not orderred!") operators.append(qr.qm.ProjectionOperator(1, 2, dim=He.dim)) rates.append(rate) # include detailed balace if detailed_balance: with qr.eigenbasis_of(He): T = INP.temperature #77.0 Den = (He.data[2, 2] - He.data[1, 1]) / (kB_int * T) operators.append(qr.qm.ProjectionOperator(2, 1, dim=He.dim)) thermal_fac = numpy.exp(-Den) rates.append(rate * thermal_fac) sbi = qr.qm.SystemBathInteraction(sys_operators=operators, rates=rates) sbi.set_system(agg) # # Liouville form for relaxation # LF = qr.qm.ElectronicLindbladForm(HH, sbi, as_operators=True) # # Pure dephasing # p_deph = qr.qm.ElectronicPureDephasing(agg, dtype="Gaussian") # we simplify calculations by converting dephasing to # corresponding Lorentzian form p_deph.convert_to("Lorentzian") eUt = qr.qm.EvolutionSuperOperator(time2, HH, relt=LF, pdeph=p_deph, mode="all") eUt.set_dense_dt(INP.fine_splitting) # # We calculate evolution superoperator # eUt.calculate(show_progress=False) # save the evolution operator if save_eUt: eut_name = os.path.join( dname, "eUt" + "_omega2=" + str(omega) + data_descr + obj_ext) eUt.save(eut_name) # # Prepare aggregate with all states (including 2-EX band) # agg3.build(mult=2) agg3.diagonalize() pways = dict() olow_cm = omega - INP.omega_uncertainty / 2.0 ohigh_cm = omega + INP.omega_uncertainty / 2.0 olow = qr.convert(olow_cm, "1/cm", "int") ohigh = qr.convert(ohigh_cm, "1/cm", "int") for t2 in time2.data: # this could save some memory of pathways become too big pways = dict() print("T2 =", t2) twod = msc.calculate_one_system(t2, agg3, eUt, lab, pways=pways, dtol=1.0e-12, selection=[["omega2", [olow, ohigh]]]) pws = pways[str(t2)] npa = len(pws) print(" p:", npa) has_R = False has_NR = False for pw in pws: if pw.pathway_type == "NR": has_NR = True elif pw.pathway_type == "R": has_R = True print(" R:", has_R, ", NR:", has_NR) if t2 in t2_save_pathways: pws_name = os.path.join( dname, "pws_t2=" + str(t2) + "_omega2=" + str(omega) + data_descr + obj_ext) qr.save_parcel(pways[str(t2)], pws_name) cont_p.set_spectrum(twod) twod = msc.calculate_one_system(t2, agg3, eUt, lab, pways=pways, dtol=1.0e-12, selection=[["omega2", [-ohigh, -olow]]]) pws = pways[str(t2)] npa = len(pws) print(" m:", npa) has_R = False has_NR = False for pw in pws: if pw.pathway_type == "NR": has_NR = True elif pw.pathway_type == "R": has_R = True print(" R:", has_R, ", NR:", has_NR) if t2 in t2_save_pathways: pws_name = os.path.join( dname, "pws_t2=" + str(t2) + "_omega2=" + str(-omega) + data_descr + obj_ext) qr.save_parcel(pways[str(t2)], pws_name) cont_m.set_spectrum(twod) if make_movie: with qr.energy_units("1/cm"): cont_p.make_movie("mov.mp4") # # Save aggregate when a single calculation is done # if save_eUt: fname = os.path.join(dname, "aggregate.qrp") agg3.save(fname) # # Window function for subsequenty FFT # window = func.Tukey(time2, r=INP.tukey_window_r, sym=False) # # FFT with the window function # # Specify REPH, NONR or `total` to get different types of spectra # print("Calculating FFT of the 2D maps") #fcont = cont.fft(window=window, dtype=stype) #, dpart="real", offset=0.0) fcont_p_re = cont_p.fft(window=window, dtype=qr.signal_REPH) fcont_p_nr = cont_p.fft(window=window, dtype=qr.signal_NONR) fcont_p_to = cont_p.fft(window=window, dtype=qr.signal_TOTL) if normalize_maps_to_maximu: fcont_p_re.normalize2(dpart=qr.part_ABS) fcont_p_nr.normalize2(dpart=qr.part_ABS) fcont_p_to.normalize2(dpart=qr.part_ABS) fcont_m_re = cont_m.fft(window=window, dtype=qr.signal_REPH) fcont_m_nr = cont_m.fft(window=window, dtype=qr.signal_NONR) fcont_m_to = cont_m.fft(window=window, dtype=qr.signal_TOTL) if normalize_maps_to_maximu: fcont_m_re.normalize2(dpart=qr.part_ABS) fcont_m_nr.normalize2(dpart=qr.part_ABS) fcont_m_to.normalize2(dpart=qr.part_ABS) if trim_maps: twin = INP.trim_maps_to with qr.energy_units("1/cm"): fcont_p_re.trimall_to(window=twin) fcont_p_nr.trimall_to(window=twin) fcont_p_to.trimall_to(window=twin) show_omega = omega with qr.frequency_units("1/cm"): sp1_p_re, show_Npoint1 = fcont_p_re.get_nearest(show_omega) sp2_p_re, show_Npoint2 = fcont_p_re.get_nearest(-show_omega) sp1_p_nr, show_Npoint1 = fcont_p_nr.get_nearest(show_omega) sp2_p_nr, show_Npoint2 = fcont_p_nr.get_nearest(-show_omega) sp1_p_to, show_Npoint1 = fcont_p_to.get_nearest(show_omega) sp2_p_to, show_Npoint2 = fcont_p_to.get_nearest(-show_omega) sp1_m_re, show_Npoint1 = fcont_m_re.get_nearest(show_omega) sp2_m_re, show_Npoint2 = fcont_m_re.get_nearest(-show_omega) sp1_m_nr, show_Npoint1 = fcont_m_nr.get_nearest(show_omega) sp2_m_nr, show_Npoint2 = fcont_m_nr.get_nearest(-show_omega) sp1_m_to, show_Npoint1 = fcont_m_to.get_nearest(show_omega) sp2_m_to, show_Npoint2 = fcont_m_to.get_nearest(-show_omega) with qr.energy_units(units): if show_plots: # # Spots to look at in detail # with qr.energy_units("1/cm"): with qr.eigenbasis_of(He): Ep_l = He.data[1, 1] Ep_u = He.data[2, 2] Ep = numpy.zeros((4, 2)) Ep[0, 0] = Ep_l Ep[0, 1] = Ep_l Ep[1, 0] = Ep_l Ep[1, 1] = Ep_u Ep[2, 0] = Ep_u Ep[2, 1] = Ep_l Ep[3, 0] = Ep_u Ep[3, 1] = Ep_u print("\nPlotting and saving spectrum at frequency:", fcont_p_re.axis.data[show_Npoint1], units) fftf_1 = os.path.join( dname, "twod_fft" + data_descr + "_stype=REPH" + "_omega=" + str(omega) + data_ext) sp1_p_re.plot(Npos_contours=10, spart=qr.part_ABS, label="Rephasing\n $\omega=" + str(omega) + "$ cm$^{-1}$", text_loc=[0.05, 0.1], show_states=[Ep_l, Ep_u, Ep_u + numpy.abs(omega)], show_diagonal="-k") sp1_p_re.savefig(fftf_1) print("... saved into: ", fftf_1) fftf_2 = os.path.join( dname, "twod_fft" + data_descr + "_stype=NONR" + "_omega=" + str(omega) + data_ext) sp1_p_nr.plot(Npos_contours=10, spart=qr.part_ABS, label="Non-rephasing\n $\omega=" + str(omega) + "$ cm$^{-1}$", text_loc=[0.05, 0.1], show_states=[Ep_l, Ep_u, Ep_u + numpy.abs(omega)], show_diagonal="-k") sp1_p_nr.savefig(fftf_2) print("... saved into: ", fftf_2) fftf_3 = os.path.join( dname, "twod_fft" + data_descr + "_stype=tot" + "_omega=" + str(omega) + data_ext) sp1_p_to.plot(Npos_contours=10, spart=qr.part_ABS, label="Total\n $\omega=" + str(omega) + "$ cm$^{-1}$", text_loc=[0.05, 0.1], show_states=[Ep_l, Ep_u, Ep_u + numpy.abs(omega)], show_diagonal="-k") sp1_p_to.savefig(fftf_3) print("... saved into: ", fftf_3) # # Point evolutions at the expected peak positions # for ii in range(4): points = fcont_p_re.get_point_evolution( Ep[ii, 0], Ep[ii, 1], fcont_p_re.axis) points.apply_to_data(numpy.abs) if ii >= 3: points.plot(show=True) else: points.plot(show=False) print("\nPlotting and saving spectrum at frequency:", fcont_m_re.axis.data[show_Npoint2], units) fftf_4 = os.path.join( dname, "twod_fft" + data_descr + "_stype=REPH" + "_omega=" + str(-omega) + data_ext) sp2_m_re.plot(Npos_contours=10, spart=qr.part_ABS, label="Rephasing\n $\omega=" + str(-omega) + "$ cm$^{-1}$", text_loc=[0.05, 0.1], show_states=[Ep_l, Ep_u, Ep_u + numpy.abs(omega)], show_diagonal="-k") sp2_m_re.savefig(fftf_4) print("... saved into: ", fftf_4) fftf_5 = os.path.join( dname, "twod_fft" + data_descr + "_stype=NONR" + "_omega=" + str(-omega) + data_ext) sp2_m_nr.plot(Npos_contours=10, spart=qr.part_ABS, label="Non-rephasing\n $\omega=" + str(-omega) + "$ cm$^{-1}$", text_loc=[0.05, 0.1], show_states=[Ep_l, Ep_u, Ep_u + numpy.abs(omega)], show_diagonal="-k") sp2_m_nr.savefig(fftf_5) print("... saved into: ", fftf_5) fftf_6 = os.path.join( dname, "twod_fft" + data_descr + "_stype=tot" + "_omega=" + str(-omega) + data_ext) sp2_m_to.plot(Npos_contours=10, spart=qr.part_ABS, label="Total\n $\omega=" + str(-omega) + "$ cm$^{-1}$", text_loc=[0.05, 0.1], show_states=[Ep_l, Ep_u, Ep_u + numpy.abs(omega)], show_diagonal="-k") sp2_m_to.savefig(fftf_6) print("... saved into: ", fftf_6) # # Point evolutions at the expected peak positions # for ii in range(4): points = fcont_p_re.get_point_evolution( Ep[ii, 0], Ep[ii, 1], fcont_m_re.axis) points.apply_to_data(numpy.abs) if ii >= 3: points.plot(show=True) else: points.plot(show=False) save_containers = False if save_containers: fname = os.path.join(dname, "cont_p" + data_descr + obj_ext) print("Saving container into: " + fname) cont_p.save(fname) fname = os.path.join(dname, "cont_m" + data_descr + obj_ext) print("Saving container into: " + fname) cont_m.save(fname) import resource memo = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss / (1024 * 1024) print("Memory usage: ", memo, "in MB") return (sp1_p_re, sp1_p_nr, sp2_m_re, sp2_m_nr)
print("Fitted population decay time (exciton basis): ", 1.0/popt_p_e[1]) print("Fitted population decay time (site basis): ", 1.0/popt_p_s[1]) else: popt_p_e = [0.0, 10000.0] popt_p_s = [0.0, 10000.0] if J == 0.0: rat = 0.0 balance = 0.0 else: rat = popt_p_e[1] kBT = qr.core.units.kB_int*Temperature print("kBT = ", qr.convert(kBT,"int","1/cm"),"cm^-1") with qr.eigenbasis_of(ham): balance = rat*numpy.exp(-(ham.data[2,2]-ham.data[1,1])/kBT) print("Uphill decay time from canonical detailed balance: ", 1.0/balance) rate_predicted = 0.5*balance + 0.5*rat print("Prediction for the decoherence time"+ " based on population transfer:", 1.0/rate_predicted) # # Exponential fitting of opt_coh and ext_coh # # Define Quantarhei DFunction which can fit itself
# Create an aggregate # agg = qr.Aggregate(molecules=[mol]) agg.build() # # Time axes and the calculator # t1axis = qr.TimeAxis(0.0, 1000, 10.0) t3axis = qr.TimeAxis(0.0, 1000, 10.0) t2axis = qr.TimeAxis(0.0, Nt2, dt2) # FIXME: TwoDResponseCalculator msc = qr.MockTwoDResponseCalculator(t1axis, t2axis, t3axis) msc.bootstrap(rwa=qr.convert(E1, "1/cm", "int"), shape="Gaussian") # # Laboratory setup # lab = LabSetup() lab.set_polarizations(pulse_polarizations=[X, X, X], detection_polarization=X) # # Hamiltonian is required # H = agg.get_Hamiltonian() # # Evolution superoperator
# Aggregate with vibrational states, Hamiltonian generated up to single # exciton states in a Two-particle approximation # This object is used for calculation of dynamics # agg.build(mult=1, vibgen_approx="TPA") # # agg2 object will be used for calculation of 2D spectra # so it needs to know how to represent the spectra (what width it should have). # It also has to be built with # two-exciton states (in two-particle approximation) # for mol_name in transition_widths: width = qr.convert(transition_widths[mol_name], "1/cm", "int") mol = agg2.get_Molecule_by_name(mol_name) mol.set_transition_width((0, 1), width) print("Aggregate has ", agg2.nmono, "single excited electronic states") agg2.build(mult=2, vibgen_approx="TPA") print("and ", agg2.Ntot, " (electro-vibrational) states in total") print("Number of single exciton states :", agg2.Nb[0] + agg2.Nb[1]) qr.save_parcel(agg2, os.path.join(pre_out, "agg2_built.qrp")) # # Electronic aggregate is built with single exciton states only #
# This object is used for calculation of dynamics # agg.build(mult=1, vibgen_approx="TPA") # # width of the spectral features in 1/cm # wincm = 500 # # agg2 object will be used for calculation of 2D spectra # so it needs to know how to represent the spectra (what # width it should have), and it has to be built with # two-exciton states (in two-particle approximation) # width = qr.convert(wincm, "1/cm", "int") PM = agg2.get_Molecule_by_name("PM") PM.set_transition_width((0, 1), width) PL = agg2.get_Molecule_by_name("PL") PL.set_transition_width((0, 1), width) width = qr.convert(wincm, "1/cm", "int") BM = agg2.get_Molecule_by_name("BM") BM.set_transition_width((0, 1), width) BL = agg2.get_Molecule_by_name("BL") BL.set_transition_width((0, 1), width) width = qr.convert(wincm, "1/cm", "int") PCT1 = agg2.get_Molecule_by_name("PCT1") PCT1.set_transition_width((0, 1), width) PCT2 = agg2.get_Molecule_by_name("PCT2")