Source code for quantarhei.builders.aggregate_spectroscopy

# -*- coding: utf-8 -*-
"""
    Class comprising the aggregate methods for support of spectroscopic simulations



    Class Details
    -------------

"""

import numpy

from .aggregate_base import AggregateBase
from ..spectroscopy import diagramatics as diag
from ..core.managers import eigenbasis_of

import quantarhei as qr

[docs]class AggregateSpectroscopy(AggregateBase): """ Class comprising the aggregate methods for support of spectroscopic simulations """ ######################################################################## # # SPECTROSCOPY # ########################################################################
[docs] def liouville_pathways_3(self, ptype="R3g", dtol=0.01, ptol=1.0e-3, lab=None, verbose=0): """ Generator of Liouville pathways """ ham = self.get_Hamiltonian() return self.liouville_pathways_3T(ptype, dtol=dtol, ptol=ptol, lab=lab, eUt2=qr.qm.SOpUnity(dim=ham.dim), verbose=verbose) # # Rest is ignored for now (may be valuabel in the future) # pop_tol = ptol dip_tol = numpy.sqrt(self.D2_max)*dtol # Check if the ptype is a tuple if not isinstance(ptype, (tuple,list)): ptype_tuple = (ptype,) else: ptype_tuple = ptype lst = [] for ptp in ptype_tuple: if ptp == "R3g": ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) k = 0 l = 0 for i1g in ngs: # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] < dip_tol: break for i3g in ngs: if self.D2[i3g,i2e] < dip_tol: break for i4e in nes: if ((self.D2[i4e,i1g] < dip_tol) and (self.D2[i3g,i4e] < dip_tol)) : break l += 1 # Diagram R3g # # # |g_i3> <g_i3| # <----|-----------| # |e_i4> <g_i3| # ---->|-----------| # |g_i1> <g_i3| # |-----------|----> # |g_i1> <e_i2| # |-----------|<---- # |g_i1> <g_i1| try: lp = \ diag.liouville_pathway("R", i1g, aggregate=self, order=3,pname=ptp) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),-1) # |g_i1> <e_i2| lp.add_transition((i3g,i2e),-1) # |g_i1> <g_i3| lp.add_transition((i4e,i1g),+1) # |e_i5> <g_i3| lp.add_transition((i3g,i4e),+1) # |g_i3> <g_i3| except: break lp.build() lst.append(lp) k += 1 if ptp == "R2g": ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) k = 0 l = 0 for i1g in ngs: # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] < dip_tol: break for i3e in nes: if self.D2[i3e,i1g] < dip_tol: break for i4g in ngs: if ((self.D2[i4g,i2e] < dip_tol) or (self.D2[i4g,i3e] < dip_tol)): break l += 1 # Diagram R2g # # # |g_i4> <g_i4| # <----|-----------| # |e_i3> <g_i4| # |-----------|----> # |e_i3> <e_i2| # ---->|-----------| # |g_i1> <e_i2| # |-----------|<---- # |g_i1> <g_i1| try: lp = \ diag.liouville_pathway("R", i1g, aggregate=self, order=3,pname=ptp, popt_band=1) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),-1) # |g_i1> <e_i2| lp.add_transition((i3e,i1g),+1) # |e_i3> <e_i2| lp.add_transition((i4g,i2e),-1) # |e_i3> <g_i4| lp.add_transition((i4g,i3e),+1) # |g_i4> <g_i4| except: break lp.build() lst.append(lp) k += 1 if ptp == "R1g": ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) #nrg = len(ngs) #nre = len(nes) #print("Ground state : ", nrg) #print("Excited state: ", nre) #print("R1g: ",nrg*nre*nre*nrg) k = 0 l = 0 for i1g in ngs: # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] < dip_tol: break for i3e in nes: if self.D2[i3e,i1g] < dip_tol: break for i4g in ngs: if ((self.D2[i4g,i3e] < dip_tol) or (self.D2[i4g,i2e] < dip_tol)): break l += 1 # Diagram R1g # # # |g_i4> <g_i4| # <----|-----------| # |e_i2> <g_i4| # |-----------|----> # |e_i2> <e_i3| # |-----------|<---- # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| try: lp = \ diag.liouville_pathway("NR",i1g, aggregate=self, order=3,pname=ptp, popt_band=1) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),+1) # |e_i2> <g_i1| lp.add_transition((i3e,i1g),-1) # |e_i2> <e_i3| lp.add_transition((i4g,i3e),-1) # |e_i2> <g_i4| lp.add_transition((i4g,i2e),+1) # |g_i4> <g_i4| except: break lp.build() lst.append(lp) k += 1 if ptp == "R4g": ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) #nrg = len(ngs) #nre = len(nes) #print("Ground state : ", nrg) #print("Excited state: ", nre) #print("R4g: ",nrg*nre*nrg*nrg*nre) k = 0 l = 0 for i1g in ngs: # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] < dip_tol: break for i3g in ngs: if self.D2[i3g,i2e] < dip_tol: break for i4e in nes: if ((self.D2[i4e,i3g] < dip_tol) or (self.D2[i1g,i4e] < dip_tol)): break l += 1 # Diagram R4g # # # |g_i1> <g_i1| # <----|-----------| # |e_i4> <g_i1| # ---->|-----------| # |g_i3> <g_i1| # <----|-----------| # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| try: lp = \ diag.liouville_pathway("NR",i1g, aggregate=self, order=3,pname=ptp) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),+1) # |e_i2> <g_i1| lp.add_transition((i3g,i2e),+1) # |g_i3> <g_i1| lp.add_transition((i4e,i3g),+1) # |e_i4> <g_i1| lp.add_transition((i1g,i4e),+1) # |g_i1> <g_i1| except: break lp.build() lst.append(lp) k += 1 if ptp == "R1f*": ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) try: nfs = self.get_excitonic_band(band=2) except: break # print(ngs) # print(nes) # print(nfs) # for a in nes: # for b in nfs: # print(a,b," : ",self.D2[a,b],self.D2[b,a]) k = 0 l = 0 for i1g in ngs: # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] < dip_tol: break for i3e in nes: if self.D2[i3e,i1g] < dip_tol: break for i4f in nfs: if ((self.D2[i4f,i3e] < dip_tol) or (self.D2[i2e,i4f] < dip_tol)): #print("Breaking") #print(self.D2[i4f,i3e],self.D2[i2e,i4f]) break l += 1 # Diagram R4g # # # |e_i2> <e_i2| # <----|-----------| # |f_i4> <e_i2| # ---->|-----------| # |e_i3> <e_i2| # ---->|-----------| # |g_i1> <e_i2| # |-----------|<---- # |g_i1> <g_i1| try: lp = \ diag.liouville_pathway("R",i1g, aggregate=self, order=3,pname=ptp, popt_band=1) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),-1) # |g_i1> <e_i2| lp.add_transition((i3e,i1g),+1) # |e_i3> <e_i2| lp.add_transition((i4f,i3e),+1) # |f_i4> <e_i2| lp.add_transition((i2e,i4f),+1) # |e_i2> <e_i2| except: break lp.build() lst.append(lp) k += 1 if ptp == "R2f*": ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) try: nfs = self.get_excitonic_band(band=2) except: break k = 0 l = 0 for i1g in ngs: # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] < dip_tol: break for i3e in nes: if self.D2[i3e,i1g] < dip_tol: break for i4f in nfs: if ((self.D2[i4f,i2e] < dip_tol) or (self.D2[i3e,i4f] < dip_tol)): break l += 1 # Diagram R4g # # # |e_i3> <e_i3| # <----|-----------| # |f_i4> <e_i3| # ---->|-----------| # |e_i2> <e_i3| # |-----------|<---- # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| try: lp = \ diag.liouville_pathway("NR",i1g, aggregate=self, order=3,pname=ptp, popt_band=1) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),+1) # |e_i2> <g_i1| lp.add_transition((i3e,i1g),-1) # |e_i2> <e_i3| lp.add_transition((i4f,i2e),+1) # |f_i4> <e_i3| lp.add_transition((i3e,i4f),+1) # |e_i3> <e_i3| except: break lp.build() lst.append(lp) k += 1 if ptp == "R2g->3g": ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) k = 0 l = 0 for i1g in ngs: # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] < dip_tol: break for i3e in nes: if self.D2[i3e,i1g] < dip_tol: break # relaxation for i4g in ngs: for i5g in ngs: for i6e in nes: if ((self.D2[i6e,i4g] < dip_tol) or (self.D2[i5g,i6e] < dip_tol)): break l += 1 # Diagram R2g_ETICS # (Compensates R3g) # # # |g_i5> <g_i5| # <----|-----------| # |e_i6> <g_i5| # ---->|-----------| # |g_i4> <g_i5| # |***********| # |e_i3> <e_i2| # ---->|-----------| # |g_i1> <e_i2| # |-----------|<---- # |g_i1> <g_i1| if True: #try: lp = \ diag.liouville_pathway("R_E", i1g, aggregate=self, order=3, relax_order=1, pname=ptp) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),-1) # |g_i1> <e_i2| lp.add_transition((i3e,i1g),+1) # |e_i3> <e_i2| lp.add_transfer((i4g,i5g), (i3e,i2e)) # |g_i4> <g_i5| lp.add_transition((i6e,i4g),+1) # |e_i6> <g_i5| lp.add_transition((i5g,i6e),+1) # |g_i5> <g_i5| #except: # break lp.build() lst.append(lp) k += 1 if ptp == "R1g->4g": ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) k = 0 l = 0 for i1g in ngs: # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] < dip_tol: break for i3e in nes: if self.D2[i3e,i1g] < dip_tol: break # relaxation for i4g in ngs: for i5g in ngs: for i6e in nes: if ((self.D2[i6e,i4g] < dip_tol) or (self.D2[i5g,i6e] < dip_tol)): break l += 1 # Diagram R2g_ETICS # (Compensates R3g) # # # |g_i5> <g_i5| # <----|-----------| # |e_i6> <g_i5| # ---->|-----------| # |g_i4> <g_i5| # |***********| # |e_i2> <e_i3| # |-----------|<---- # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| #if True: try: lp = \ diag.liouville_pathway("NR_E", i1g, aggregate=self, order=3, relax_order=1, pname=ptp) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),+1) # |e_i2> <g_i1| lp.add_transition((i3e,i1g),-1) # |e_i2> <e_i3| lp.add_transfer((i4g,i5g), (i2e,i3e)) # |g_i4> <g_i5| lp.add_transition((i6e,i4g),+1) # |e_i6> <g_i5| lp.add_transition((i5g,i6e),+1) # |g_i5> <g_i5| except: break lp.build() lst.append(lp) k += 1 if lab is not None: for l in lst: l.orientational_averaging(lab) return lst
[docs] def liouville_pathways_3T(self, ptype="R3g", eUt=None, ham=None, t2=0.0, dtol=1.0e-12, ptol=1.0e-3, etol=1.0e-6, verbose=0, lab=None): """ Generator of Liouville pathways with energy transfer Parameters ---------- ptype : tuple, list, str List of strings or a string representing one or more Liouville pathway types that are to be calculated eUt : EvolutionSuperOperator Evolution superoperator representing the energy transfer in the system t2 : float Waiting time at which the spectrum is calculated dtol : float Minimum acceptable strength of the transition from ground to excited state, relative to the maximum dipole strength available in the system ptol : float Minimum acceptable population of the ground state (e.g. states not thermally populated are excluded) lab : LaboratorySetup Object representing laboratory setup - number of pulses, polarization etc. Returns ------- lst : list List of LiouvillePathway objects """ if self._diagonalized: if verbose > 0: print("Diagonalizing aggregate") self.diagonalize() if verbose > 0: print("..done") pop_tol = ptol dip_tol = numpy.sqrt(self.D2_max)*dtol evf_tol = etol # Check if the ptype is a tuple if not isinstance(ptype, (tuple,list)): ptype_tuple = (ptype,) else: ptype_tuple = ptype lst = [] if verbose > 0: print("Pathways", ptype_tuple) # # data of the evolution superoperator in eigenstate basis # try: # either the eUt is a complete evolution superoperator eUt2 = eUt.at(t2) eUt2_dat = numpy.zeros(eUt2.data.shape, dtype=eUt2.data.dtype) HH = eUt.get_Hamiltonian() with eigenbasis_of(HH): eUt2_dat[:,:,:,:] = eUt2.data except: # or it is only a super operator at a given time t2 # in this case 'ham' must be specified eUt2 = eUt eUt2_dat = numpy.zeros(eUt2.data.shape, dtype=eUt2.data.dtype) with eigenbasis_of(ham): eUt2_dat[:,:,:,:] = eUt2.data for ptp in ptype_tuple: if ptp == "R1g": generate_R1g(self, lst, eUt2_dat, pop_tol, dip_tol, evf_tol, verbose) elif ptp == "R2g": generate_R2g(self, lst, eUt2_dat, pop_tol, dip_tol, evf_tol, verbose) elif ptp == "R3g": generate_R3g(self, lst, eUt2_dat, pop_tol, dip_tol, verbose) elif ptp == "R4g": generate_R4g(self, lst, eUt2_dat, pop_tol, dip_tol, verbose) elif ptp == "R1f*": generate_R1f(self, lst, eUt2_dat, pop_tol, dip_tol, evf_tol, verbose) elif ptp == "R2f*": generate_R2f(self, lst, eUt2_dat, pop_tol, dip_tol, evf_tol, verbose) else: raise Exception("Unknown pythway type: "+str(ptp)) if lab is not None: for l in lst: l.orientational_averaging(lab) return lst
[docs] def liouville_pathways_1(self, eUt=None, ham=None, dtol=0.01, ptol=1.0e-3, etol=1.0e-6, verbose=0, lab=None): """ Generator of the first order Liouville pathways Generator of the pathways for an absorption spectrum calculation. Parameters ---------- eUt : EvolutionSuperOperator Evolution superoperator representing the evolution of optical coherence in the system dtol : float Minimum acceptable strength of the transition from ground to excited state, relative to the maximum dipole strength available in the system ptol : float Minimum acceptable population of the ground state (e.g. states not thermally populated are excluded) lab : LaboratorySetup Object representing laboratory setup - number of pulses, polarization etc. Returns ------- lst : list List of LiouvillePathway objects """ if self._diagonalized: if verbose > 0: print("Diagonalizing aggregate") self.diagonalize() if verbose > 0: print("..done") pop_tol = ptol dip_tol = numpy.sqrt(self.D2_max)*dtol evf_tol = etol if eUt is None: # secular absorption spectrum calculation eUt2_dat = None sec = True else: raise Exception("Not implemented yet") lst = [] if sec: generate_1orderP_sec(self, lst, pop_tol, dip_tol, verbose) else: raise Exception("Not implemented yet") if lab is not None: for l in lst: l.orientational_averaging(lab) return lst
def generate_R1g(self, lst, eUt2, pop_tol, dip_tol, evf_tol, verbose=0): ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) ver = verbose if verbose > 0: print("Liouville pathway R1g") print("Population tolerance: ", pop_tol) print("Dipole tolerance: ", dip_tol) print("Evolution amplitude: ", evf_tol) k = 0 l = 0 for i1g in ngs: if verbose > 0: print("Ground state: ", i1g, "of", len(ngs)) # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if verbose > 1: print("Excited state: ", i2e, "of", len(nes)) if self.D2[i2e, i1g] > dip_tol: for i3e in nes: if self.D2[i3e, i1g] > dip_tol: for i2d in nes: for i3d in nes: evf = eUt2[i2d, i3d, i2e, i3e] if abs(evf) > evf_tol: for i4g in ngs: if ((self.D2[i4g,i3d] > dip_tol) and (self.D2[i4g,i2d] > dip_tol)): l += 1 lp = _generate_R1g(self, i1g, i2e, i3e, i2d, i3d, i4g, evf, verbose=ver) lp.build() lst.append(lp) k += 1 def _generate_R1g(self, i1g, i2e, i3e, i2d, i3d, i4g, evf, verbose=0): # Diagram R1g # # # |g_i4> <g_i4| # <----|-----------| # |d_i2> <g_i4| # |-----------|----> # |d_i2> <d_i3| # |***********| # |e_i2> <e_i3| # |-----------|<---- # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| try: if verbose > 5: print(" * Generating R1g", i1g, i2e, i3e) lp = \ diag.liouville_pathway("NR", i1g, aggregate=self, order=3, pname="R1g", popt_band=1, relax_order=1) # first transition lineshape width1 = \ self.get_transition_width((i2e, i1g)) deph1 = \ self.get_transition_dephasing((i2e, i1g)) # third transition lineshape width3 = \ self.get_transition_width((i2d, i4g)) deph3 = \ self.get_transition_dephasing((i2d, i4g)) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),+1, interval=1, width=width1, deph=deph1) # |e_i2> <g_i1| lp.add_transition((i3e,i1g),-1) # |e_i2> <e_i3| lp.add_transfer(((i2d, i3d)), (i2e, i3e)) lp.set_evolution_factor(evf) # |d_i2> <d_i3| lp.add_transition((i4g,i3d),-1) # |d_i2> <g_i4| lp.add_transition((i4g,i2d),+1, interval=3, width=width3, deph=deph3) # |g_i4> <g_i4| except: raise Exception("Pathway generation failed") return lp def generate_R2g(self, lst, eUt2, pop_tol, dip_tol, evf_tol, verbose=0): ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) if verbose > 0: print("Liouville pathway R2g") print("Population tolerance: ", pop_tol) print("Dipole tolerance: ", dip_tol) print("Evolution amplitude: ", evf_tol) k = 0 l = 0 for i1g in ngs: if verbose > 0: print("Ground state: ", i1g, "of", len(ngs)) # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if verbose > 1: print("Excited state: ", i2e, "of", len(nes)) if self.D2[i2e,i1g] > dip_tol: for i3e in nes: if self.D2[i3e,i1g] > dip_tol: for i3d in nes: for i2d in nes: evf = eUt2[i3d, i2d, i3e, i2e] if abs(evf) > evf_tol: for i4g in ngs: if ((self.D2[i4g,i2e] > dip_tol) and (self.D2[i4g,i3e] > dip_tol)): l += 1 # Diagram R2g # # # |g_i4> <g_i4| # <----|-----------| # |d_i3> <g_i4| # |-----------|----> # |d_i3> <d_i2| # |***********| # |e_i3> <e_i2| # ---->|-----------| # |g_i1> <e_i2| # |-----------|<---- # |g_i1> <g_i1| try: if verbose > 5: print(" * Generating R2g", i1g, i2e, i3e) lp = \ diag.liouville_pathway("R", i1g, aggregate=self, order=3,pname="R2g", popt_band=1, relax_order=1) # first transition lineshape width1 = \ self.get_transition_width((i2e, i1g)) deph1 = \ self.get_transition_dephasing((i2e, i1g)) # third transition lineshape width3 = \ self.get_transition_width((i3d, i4g)) deph3 = \ self.get_transition_dephasing((i3d, i4g)) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),-1, interval=1, width=width1, deph=deph1) # |g_i1> <e_i2| lp.add_transition((i3e,i1g),+1) # |e_i3> <e_i2| lp.add_transfer(((i3d, i2d)), (i3e, i2e)) lp.set_evolution_factor(evf) lp.add_transition((i4g,i2d),-1) # |e_i3> <g_i4| lp.add_transition((i4g,i3d),+1, interval=3, width=width3, deph=deph3) # |g_i4> <g_i4| except: raise Exception() break lp.build() lst.append(lp) k += 1 def generate_R3g(self, lst, eUt2, pop_tol, dip_tol, verbose=0): ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) if verbose > 0: print("Liouville pathway R3g") print("Population tolerance: ", pop_tol) print("Dipole tolerance: ", dip_tol) #print("Evolution amplitude: ", evf_tol) k = 0 l = 0 for i1g in ngs: if verbose > 0: print("Ground state: ", i1g, "of", len(ngs)) # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if verbose > 1: print("Excited state: ", i2e, "of", len(nes)) if self.D2[i2e,i1g] > dip_tol: for i3g in ngs: if self.D2[i3g,i2e] > dip_tol: evf = eUt2[i1g, i3g, i1g, i3g] for i4e in nes: if ((self.D2[i4e,i1g] > dip_tol) and (self.D2[i3g,i4e] > dip_tol)) : l += 1 # Diagram R3g # # # |g_i3> <g_i3| # <----|-----------| # |e_i4> <g_i3| # ---->|-----------| # |g_i1> <g_i3| # |-----------|----> # |g_i1> <e_i2| # |-----------|<---- # |g_i1> <g_i1| try: if verbose > 5: print(" * Generating R3g", i1g, i2e) lp = \ diag.liouville_pathway("R", i1g, aggregate=self, order=3, pname="R3g") # first transition lineshape width1 = \ self.get_transition_width((i2e, i1g)) deph1 = \ self.get_transition_dephasing((i2e, i1g)) # third transition lineshape width3 = \ self.get_transition_width((i4e,i3g)) deph3 = \ self.get_transition_dephasing((i4e, i3g)) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),-1, interval=1, width=width1, deph=deph1) # |g_i1> <e_i2| lp.add_transition((i3g,i2e),-1) # |g_i1> <g_i3| lp.add_transition((i4e,i1g),+1) # |e_i5> <g_i3| lp.add_transition((i3g,i4e),+1, interval=3, width=width3, deph=deph3) # |g_i3> <g_i3| lp.set_evolution_factor(evf) except: raise Exception("Generation of pathway failed") lp.build() lst.append(lp) k += 1 def generate_R4g(self, lst, eUt2, pop_tol, dip_tol, verbose=0): ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) if verbose > 0: print("Liouville pathway R4g") print("Population tolerance: ", pop_tol) print("Dipole tolerance: ", dip_tol) k = 0 l = 0 for i1g in ngs: if verbose > 0: print("Ground state: ", i1g, "of", len(ngs)) # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if verbose > 1: print("Excited state: ", i2e, "of", len(nes)) #if i2e == 4: # print("Changing verbosity to 10") # verbose = 10 #print(self.D2[i2e,i1g], dip_tol, self.D2[i2e,i1g] > dip_tol) if self.D2[i2e,i1g] > dip_tol: for i3g in ngs: if self.D2[i3g,i2e] > dip_tol: evf = eUt2[i1g, i3g, i1g, i3g] for i4e in nes: if ((self.D2[i4e,i3g] > dip_tol) and (self.D2[i1g,i4e] > dip_tol)): l += 1 # Diagram R4g # # # |g_i1> <g_i1| # <----|-----------| # |e_i4> <g_i1| # ---->|-----------| # |g_i3> <g_i1| # <----|-----------| # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| try: if verbose > 5: print(" * Generating R4g", i1g, i2e) lp = \ diag.liouville_pathway("NR",i1g, aggregate=self, order=3,pname="R4g") # first transition lineshape width1 = \ self.get_transition_width((i2e, i1g)) deph1 = \ self.get_transition_dephasing((i2e, i1g)) # third transition lineshape width3 = \ self.get_transition_width((i4e,i1g)) deph3 = \ self.get_transition_dephasing((i4e, i1g)) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),+1, interval=1, width=width1, deph=deph1) # |e_i2> <g_i1| lp.add_transition((i3g,i2e),+1) # |g_i3> <g_i1| lp.add_transition((i4e,i3g),+1) # |e_i4> <g_i1| lp.add_transition((i1g,i4e),+1, interval=3, width=width3, deph=deph3) # |g_i1> <g_i1| lp.set_evolution_factor(evf) except: break lp.build() lst.append(lp) k += 1 #if verbose == 10: # print("////") # qr.stop() def generate_R1f(self, lst, eUt2, pop_tol, dip_tol, evf_tol, verbose=0): ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) try: nfs = self.get_excitonic_band(band=2) except: raise Exception("Excited states not available for R1f* pathway"+ " generation") if verbose > 0: print("Liouville pathway R1f*") print("Population tolerance: ", pop_tol) print("Dipole tolerance: ", dip_tol) print("Evolution amplitude: ", evf_tol) k = 0 l = 0 for i1g in ngs: if verbose > 0: print("Ground state: ", i1g, "of", len(ngs)) # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] > dip_tol: for i3e in nes: if self.D2[i3e,i1g] > dip_tol: if verbose > 2: print("Excited state: ", i2e, i3e, "of", nes[len(nes)-1]) for i3d in nes: for i2d in nes: evf = eUt2[i3d, i2d, i3e, i2e] if abs(evf) > evf_tol: for i4f in nfs: if ((self.D2[i4f,i3d] > dip_tol) and (self.D2[i2d,i4f] > dip_tol)): l += 1 # Diagram R1f* # # # |d_i2> <d_i2| # <----|-----------| # |f_i4> <d_i2| # ---->|-----------| # |d_i3> <d_i2| # |***********| # |e_i3> <e_i2| # ---->|-----------| # |g_i1> <e_i2| # |-----------|<---- # |g_i1> <g_i1| try: if verbose > 5: print(" * Generating R1f*", i1g, i2e) lp = \ diag.liouville_pathway("R",i1g, aggregate=self, order=3,pname="R1f*", popt_band=1, relax_order=1) # first transition lineshape width1 = \ self.get_transition_width((i2e, i1g)) deph1 = \ self.get_transition_dephasing((i2e, i1g)) # third transition lineshape width3 = \ self.get_transition_width((i4f,i2d)) deph3 = \ self.get_transition_dephasing((i4f, i2d)) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),-1, interval=1, width=width1, deph=deph1) # |g_i1> <e_i2| lp.add_transition((i3e,i1g),+1) # |e_i3> <e_i2| lp.add_transfer(((i3d, i2d)), (i3e, i2e)) lp.set_evolution_factor(evf) # |d_i3> <d_i2| lp.add_transition((i4f,i3d),+1) # |f_i4> <d_i2| lp.add_transition((i2d,i4f),+1, interval=3, width=width3, deph=deph3) # |d_i2> <d_i2| except: raise Exception("Construction"+ "relaxation pathway failed") lp.build() lst.append(lp) k += 1 def generate_R2f(self, lst, eUt2, pop_tol, dip_tol, evf_tol, verbose=0): ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) try: nfs = self.get_excitonic_band(band=2) except: raise Exception("Excited states not available for R2f* pathway"+ " generation") if verbose > 0: print("Liouville pathway R2f*") print("Population tolerance: ", pop_tol) print("Dipole tolerance: ", dip_tol) print("Evolution amplitude: ", evf_tol) k = 0 l = 0 for i1g in ngs: if verbose > 0: print("Ground state: ", i1g, "of", len(ngs)) # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] > dip_tol: for i3e in nes: if self.D2[i3e,i1g] > dip_tol: if verbose > 2: print("Excited state: ", i2e, i3e, "of", nes[len(nes)-1]) for i2d in nes: for i3d in nes: evf = eUt2[i2d, i3d, i2e, i3e] if abs(evf) > evf_tol: for i4f in nfs: if ((self.D2[i4f,i2d] > dip_tol) and (self.D2[i3d,i4f] > dip_tol)): l += 1 # Diagram R2f* # # # |d_i3> <d_i3| # <----|-----------| # |f_i4> <d_i3| # ---->|-----------| # |d_i2> <d_i3| # |***********| # |e_i2> <e_i3| # |-----------|<---- # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| try: if verbose > 5: print(" * Generating R1f*", i1g, i2e) lp = \ diag.liouville_pathway("NR", i1g, aggregate=self, order=3,pname="R2f*", popt_band=1, relax_order=1) # first transition lineshape width1 = \ self.get_transition_width((i2e, i1g)) deph1 = \ self.get_transition_dephasing((i2e, i1g)) # third transition lineshape width3 = \ self.get_transition_width((i4f,i3d)) deph3 = \ self.get_transition_dephasing((i4f, i3d)) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),+1, interval=1, width=width1, deph=deph1) # |e_i2> <g_i1| lp.add_transition((i3e,i1g),-1) # |e_i2> <e_i3| lp.add_transfer(((i2d, i3d)), (i2e, i3e)) lp.set_evolution_factor(evf) # |d_i2> <d_i3| lp.add_transition((i4f,i2d),+1) # |f_i4> <d_i3| lp.add_transition((i3d,i4f),+1, interval=3, width=width3, deph=deph3) # |d_i3> <d_i3| except: break lp.build() lst.append(lp) k += 1 def generate_1orderP_sec(self, lst, pop_tol, dip_tol, verbose=0): ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) if verbose > 0: print("Liouville pathway of first order") print("Population tolerance: ", pop_tol) print("Dipole tolerance: ", dip_tol) k = 0 l = 0 for i1g in ngs: if verbose > 0: print("Ground state: ", i1g, "of", len(ngs)) # Only thermally allowed starting states are considered if self.rho0[i1g,i1g] > pop_tol: for i2e in nes: if self.D2[i2e,i1g] > dip_tol: l += 1 # Diagram P1 # # # |g_i1> <g_i1| # <----|-----------| # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| try: if verbose > 5: print(" * Generating P1", i1g, i2e) lp = \ diag.liouville_pathway("NR", i1g, aggregate=self, order=1,pname="P1", popt_band=1, relax_order=1) # first transition lineshape width1 = \ self.get_transition_width((i2e, i1g)) deph1 = \ self.get_transition_dephasing((i2e, i1g)) # |g_i1> <g_i1| lp.add_transition((i2e,i1g),+1, interval=1, width=width1, deph=deph1) # |e_i2> <g_i1| lp.add_transition((i1g,i2e),+1, interval=1, width=width1, deph=deph1) # |g_i1> <g_i1| except: break lp.build() lst.append(lp) k += 1