Source code for quantarhei.builders.aggregate_spectroscopy

"""Class comprising the aggregate methods for support of spectroscopic simulations



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

"""

from __future__ import annotations

from typing import Any

import numpy

from ..core.managers import eigenbasis_of
from ..exceptions import ImplementationError, QuantarheiError
from ..qm.liouvillespace.supopunity import SOpUnity
from ..spectroscopy import diagramatics as diag
from .aggregate_base import AggregateBase


[docs] class AggregateSpectroscopy(AggregateBase): """Class comprising the aggregate methods for support of spectroscopic simulations""" ######################################################################## # # SPECTROSCOPY # ########################################################################
[docs] def liouville_pathways_3( self, ptype: str | tuple | list = "R3g", dtol: float = 0.01, ptol: float = 1.0e-3, lab: object = None, verbose: int = 0, ) -> list: """Generator of Liouville pathways""" ham = self.get_Hamiltonian() self.lab = lab return self.liouville_pathways_3T( ptype, dtol=dtol, ptol=ptol, lab=lab, eUt=SOpUnity(dim=ham.dim), verbose=verbose, )
[docs] def liouville_pathways_3T( self, ptype: str | tuple | list = "R3g", eUt: Any = None, ham: Any = None, t2: float = 0.0, dtol: float = 1.0e-12, ptol: float = 1.0e-3, etol: float = 1.0e-6, verbose: int = 0, lab: Any = None, ) -> list: """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 """ self.lab = lab 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 ptype_tuple: Any if not isinstance(ptype, (tuple, list)): ptype_tuple = (ptype,) else: ptype_tuple = ptype lst: list[Any] = [] 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) # # TODO: Check this part I had before without eigenbasis of and used the evolution superoperator values directly # ---------------------------------------------- eUt2_dat = numpy.zeros(eUt2.data.shape, dtype=eUt2.data.dtype) # HH = eUt.get_Hamiltonian() # with eigenbasis_of(HH): # eUt2_dat[:, :, :, :] = eUt2.data # # ---------------------------------------------- except AttributeError: # 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) elif ptp == "R1gE": generate_R1gE(self, lst, eUt2_dat, pop_tol, dip_tol, evf_tol, verbose) elif ptp == "R2gE": generate_R2gE(self, lst, eUt2_dat, pop_tol, dip_tol, evf_tol, verbose) elif ptp == "R1f*E": generate_R1fE(self, lst, eUt2_dat, pop_tol, dip_tol, evf_tol, verbose) elif ptp == "R2f*E": generate_R2fE(self, lst, eUt2_dat, pop_tol, dip_tol, evf_tol, verbose) else: raise QuantarheiError("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: object = None, ham: object = None, dtol: float = 0.01, ptol: float = 1.0e-3, etol: float = 1.0e-6, verbose: int = 0, lab: object = None, ) -> list: """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 ImplementationError("Not implemented yet") lst: list[Any] = [] if sec: generate_1orderP_sec(self, lst, pop_tol, dip_tol, verbose) else: raise ImplementationError("Not implemented yet") if lab is not None: for l in lst: l.orientational_averaging(lab) return lst
[docs] def generate_R1g( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, evf_tol: float, verbose: int = 0, ) -> None: 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: Any, i1g: int, i2e: int, i3e: int, i2d: int, i3d: int, i4g: int, evf: complex, verbose: int = 0, ) -> Any: # 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 Exception: raise QuantarheiError("Pathway generation failed") return lp
[docs] def generate_R1gE( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, evf_tol: float, verbose: int = 0, ) -> None: ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) if verbose > 0: print("Liouville pathway R1g_ETICS") 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 i4g in ngs: for i5g in ngs: evf = eUt2[i4g, i5g, i2e, i3e] if abs(evf) > evf_tol: for i6e in nes: if (self.D2[i4g, i6e] > dip_tol) and ( self.D2[i5g, i6e] > dip_tol ): # if ((self.D2[i5g,i2e] > dip_tol) # and (self.D2[i5g,i3e] > dip_tol)): l += 1 # Diagram R1g_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| try: if verbose > 5: print( " * Generating R1g_ETICS", i1g, i2e, i3e, ) lp = diag.liouville_pathway( "NR", i1g, aggregate=self, order=3, pname="R1gE", 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( (i6e, i4g) ) deph3 = ( self.get_transition_dephasing( (i6e, 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( ((i4g, i5g)), (i2e, i3e) ) lp.set_evolution_factor(evf) lp.add_transition((i6e, i4g), +1) # |e_i6> <g_i4| lp.add_transition( (i5g, i6e), +1, interval=3, width=width3, deph=deph3, ) # |g_i4> <g_i4| except Exception: raise QuantarheiError() break lp.build() lst.append(lp) k += 1
[docs] def generate_R2g( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, evf_tol: float, verbose: int = 0, ) -> None: 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 Exception: raise QuantarheiError() break lp.build() lst.append(lp) k += 1
[docs] def generate_R2gE( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, evf_tol: float, verbose: int = 0, ) -> None: ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) if verbose > 0: print("Liouville pathway R2g_ETICS") 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 i4g in ngs: for i5g in ngs: evf = eUt2[i4g, i5g, i3e, i2e] if verbose > 4: print( "Evolution factor", i4g, i5g, i3e, i2e, evf ) if abs(evf) > evf_tol: for i6e in nes: if (self.D2[i4g, i6e] > dip_tol) and ( self.D2[i5g, i6e] > dip_tol ): # if ((self.D2[i5g,i2e] > dip_tol) # and (self.D2[i5g,i3e] > dip_tol)): 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| try: if verbose > 5: print( " * Generating R2g_ETICS", i1g, i2e, i3e, ) lp = diag.liouville_pathway( "R", i1g, aggregate=self, order=3, pname="R2gE", 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( (i6e, i4g) ) deph3 = ( self.get_transition_dephasing( (i6e, 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( ((i4g, i5g)), (i3e, i2e) ) lp.set_evolution_factor(evf) lp.add_transition((i6e, i4g), +1) # |e_i3> <g_i4| lp.add_transition( (i5g, i6e), +1, interval=3, width=width3, deph=deph3, ) # |g_i4> <g_i4| except Exception: raise QuantarheiError() break lp.build() lst.append(lp) k += 1
[docs] def generate_R3g( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, verbose: int = 0, ) -> None: 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) 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 Exception: raise QuantarheiError( "Generation of pathway failed" ) lp.build() lst.append(lp) k += 1
[docs] def generate_R4g( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, verbose: int = 0, ) -> None: 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 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 Exception: break lp.build() lst.append(lp) k += 1
# if verbose == 10: # print("////") # qr.stop()
[docs] def generate_R1f( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, evf_tol: float, verbose: int = 0, ) -> None: ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) try: nfs = self.get_excitonic_band(band=2) except Exception: raise QuantarheiError( "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 Exception: raise QuantarheiError( "Construction" "relaxation pathway failed" ) lp.build() lst.append(lp) k += 1
[docs] def generate_R2f( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, evf_tol: float, verbose: int = 0, ) -> None: ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) try: nfs = self.get_excitonic_band(band=2) except Exception: raise QuantarheiError( "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 Exception: break lp.build() lst.append(lp) k += 1
[docs] def generate_R1fE( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, evf_tol: float, verbose: int = 0, ) -> None: ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) if verbose > 0: print("Liouville pathway R1f*E") 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 i3g in ngs: for i2g in ngs: evf = eUt2[i3g, i2g, i3e, i2e] if abs(evf) > evf_tol: for i4e in nes: if (self.D2[i4e, i3g] > dip_tol) and ( self.D2[i2g, i4e] > dip_tol ): l += 1 # Diagram R1f* # # # |g_i2> <g_i2| # <----|-----------| # |e_i4> <g_i2| # ---->|-----------| # |g_i3> <g_i2| # |***********| # |e_i3> <e_i2| # ---->|-----------| # |g_i1> <e_i2| # |-----------|<---- # |g_i1> <g_i1| try: if verbose > 5: print( " * Generating R1f*E", i1g, i2e, ) lp = diag.liouville_pathway( "R", i1g, aggregate=self, order=3, pname="R1f*E", 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( (i4e, i2g) ) deph3 = ( self.get_transition_dephasing( (i4e, i2g) ) ) # |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( ((i3g, i2g)), (i3e, i2e) ) lp.set_evolution_factor(evf) # |g_i3> <g_i2| lp.add_transition((i4e, i3g), +1) # |e_i4> <g_i2| lp.add_transition( (i2g, i4e), +1, interval=3, width=width3, deph=deph3, ) # |g_i2> <g_i2| except Exception: raise QuantarheiError( "Construction" "relaxation pathway failed" ) lp.build() lst.append(lp) k += 1
[docs] def generate_R2fE( self: Any, lst: list, eUt2: numpy.ndarray, pop_tol: float, dip_tol: float, evf_tol: float, verbose: int = 0, ) -> None: ngs = self.get_electronic_groundstate() nes = self.get_excitonic_band(band=1) if verbose > 0: print("Liouville pathway R2f*E") 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 i2g in ngs: for i3g in ngs: evf = eUt2[i2g, i3g, i2e, i3e] if abs(evf) > evf_tol: for i4e in nes: if (self.D2[i4e, i2g] > dip_tol) and ( self.D2[i3g, i4e] > dip_tol ): l += 1 # Diagram R2f*E # # # |g_i3> <g_i3| # <----|-----------| # |e_i4> <g_i3| # ---->|-----------| # |g_i2> <g_i3| # |***********| # |e_i2> <e_i3| # |-----------|<---- # |e_i2> <g_i1| # ---->|-----------| # |g_i1> <g_i1| try: if verbose > 5: print( " * Generating R1f*E", i1g, i2e, ) lp = diag.liouville_pathway( "NR", i1g, aggregate=self, order=3, pname="R2f*E", 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( (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, ) # |e_i2> <g_i1| lp.add_transition((i3e, i1g), -1) # |e_i2> <e_i3| lp.add_transfer( ((i2g, i3g)), (i2e, i3e) ) lp.set_evolution_factor(evf) # |g_i2> <g_i3| lp.add_transition((i4e, i2g), +1) # |e_i4> <g_i3| lp.add_transition( (i3g, i4e), +1, interval=3, width=width3, deph=deph3, ) # |g_i3> <g_i3| except Exception: break lp.build() lst.append(lp) k += 1
[docs] def generate_1orderP_sec( self: Any, lst: list, pop_tol: float, dip_tol: float, verbose: int = 0 ) -> None: 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 Exception: break lp.build() lst.append(lp) k += 1