Source code for quantarhei.builders.aggregate_test

"""Class to support tests on Aggregate class

This class provides an easy access to a prefilled, but not initiallized
object of the Aggregate class. These can be used for testing and
demonstration. There are several types of aggregates available,
distinguished by the `name` argument of the constructor.


TestAggregates Provided
-----------------------

Below we list the valid values for the `name` argument of the TestAggregate
constructor:

dimer-2 :
Dimer of two-level molecules, with positions in space
and transition dipole moments specified. No environment
is defined.

dimer-2-env :
Dimer of two-level molecules, with positions in space and
transition dipole moments specified. For each molecule
we define energy gap correlation function (energy gao
correlation functions on different sites are not correlated).

homodimer-2 :
Homo-dimer of two-level molecules (molecules with the same energy
gaps), with positions in space
and transition dipole moments specified. No environment
is defined.

homodimer-2-env :
Homo-dimer of two-level molecules, with positions in space and
transition dipole moments specified. For each molecule
we define energy gap correlation function (energy gao
correlation functions on different sites are not correlated).

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

"""

from __future__ import annotations

import numpy

from ..core.managers import energy_units
from ..core.time import TimeAxis
from ..core.units import convert
from ..exceptions import QuantarheiError
from ..qm.corfunctions.correlationfunctions import CorrelationFunction
from .aggregates import Aggregate
from .modes import Mode
from .molecules import Molecule


[docs] class TestAggregate(Aggregate): """Class to support tests on Aggregate class Parameters ---------- name : str Name characterizing the test aggregate. Examples -------- General dimers >>> # Dimer of two-level systems >>> tagg = TestAggregate(name="dimer-2") >>> tagg.build() >>> tagg.has_SystemBathInteraction() False >>> # Dimer of two-level systems with an environment >>> tagg = TestAggregate(name="dimer-2-env") >>> tagg.build() >>> tagg.has_SystemBathInteraction() True Homo-dimers >>> # Dimer of two-level systems >>> tagg = TestAggregate(name="homodimer-2") >>> tagg.build() >>> tagg.has_SystemBathInteraction() False >>> # Dimer of two-level systems with an environment >>> tagg = TestAggregate(name="homodimer-2-env") >>> tagg.build() >>> tagg.has_SystemBathInteraction() True >>> # Trimer of two-level systems without an environment >>> tagg = TestAggregate(name="trimer-2") >>> tagg.build() >>> tagg.has_SystemBathInteraction() False """
[docs] def __init__(self, name: str | None = None) -> None: """Some more doctests >>> TestAggregate() Traceback (most recent call last): ... quantarhei.exceptions.QuantarheiError: Aggregate name not specified """ if name is None: raise QuantarheiError("Aggregate name not specified") # # Test dimer # if name == "dimer-2-env": m1, m2 = self._molecules(N=2, nst=2) # set their environment time = TimeAxis(0, 1000, 1.0) cpar = dict(ftype="OverdampedBrownian", reorg=20, cortime=100, T=300) with energy_units("1/cm"): cfce = CorrelationFunction(time, cpar) m1.set_transition_environment((0, 1), cfce) m2.set_transition_environment((0, 1), cfce) super().__init__(molecules=[m1, m2]) elif name == "trimer-2-env": m1, m2, m3 = self._molecules(N=3, nst=2) # set their environment time = TimeAxis(0, 1000, 1.0) cpar = dict(ftype="OverdampedBrownian", reorg=20, cortime=100, T=300) with energy_units("1/cm"): cfce = CorrelationFunction(time, cpar) m1.set_transition_environment((0, 1), cfce) m2.set_transition_environment((0, 1), cfce) m3.set_transition_environment((0, 1), cfce) super().__init__(molecules=[m1, m2, m3]) elif name == "dimer-2": m1, m2 = self._molecules(N=2, nst=2) # set their environment # nothing here super().__init__(molecules=[m1, m2]) elif name == "trimer-2": m1, m2, m3 = self._molecules(N=3, nst=2, homo=False) super().__init__(molecules=[m1, m2, m3]) elif name == "homodimer-2-env": m1, m2 = self._molecules(N=2, nst=2, homo=True) # set their environment time = TimeAxis(0, 1000, 1.0) cpar = dict(ftype="OverdampedBrownian", reorg=20, cortime=100, T=300) with energy_units("1/cm"): cfce = CorrelationFunction(time, cpar) m1.set_transition_environment((0, 1), cfce) m2.set_transition_environment((0, 1), cfce) super().__init__(molecules=[m1, m2]) elif name == "homodimer-2": m1, m2 = self._molecules(N=2, nst=2, homo=True) # set their environment # nothing here super().__init__(molecules=[m1, m2]) elif name == "dimer-2-vib": m1, m2 = self._molecules(N=2, nst=2) with energy_units("1/cm"): mod1 = Mode(100.0) m1.add_Mode(mod1) mod1.set_HR(1, 0.1) mod2 = Mode(100.0) m2.add_Mode(mod2) mod2.set_HR(1, 0.1) super().__init__(molecules=[m1, m2])
def _molecules(self, N: int, nst: int, homo: bool = False) -> list | None: """Creates molecules to be filled into Aggregate Testing that None is returned for wrong arguments >>> tagg = TestAggregate("dimer-2") >>> mols = tagg._molecules(3, 5) >>> print(mols) None """ if (N == 2) and (nst == 2): nstates = nst # check inputs if nstates != 2: raise QuantarheiError() # set parameters gap1 = convert(12000, "1/cm", to="int") energies1 = numpy.zeros(nstates) for s in range(nstates): energies1[s] = s * gap1 if homo: gap2 = convert(12000, "1/cm", to="int") else: gap2 = convert(12300, "1/cm", to="int") energies2 = numpy.zeros(nstates) for s in range(nstates): energies2[s] = s * gap2 # molecules m1 = Molecule(elenergies=energies1) m2 = Molecule(elenergies=energies2) # set transition dipole moments dip1 = [0.0, 2.0, 0.0] dip2 = [0.0, 1.3, 1.4] m1.set_dipole(0, 1, dip1) m2.set_dipole(0, 1, dip2) # set molecular positions r1 = [0.0, 0.0, 0.0] r2 = [5.0, 0.0, 0.0] m1.position = r1 m2.position = r2 return [m1, m2] if (N == 3) and (nst == 2): nstates = nst # check inputs if nstates != 2: raise QuantarheiError() # set parameters gap1 = convert(12000, "1/cm", to="int") energies1 = numpy.zeros(nstates) for s in range(nstates): energies1[s] = s * gap1 if homo: gap2 = convert(12000, "1/cm", to="int") gap3 = gap2 else: gap2 = convert(12300, "1/cm", to="int") gap3 = convert(12350, "1/cm", to="int") energies2 = numpy.zeros(nstates) energies3 = numpy.zeros(nstates) for s in range(nstates): energies2[s] = s * gap2 energies3[s] = s * gap3 # molecules m1 = Molecule(elenergies=energies1) m2 = Molecule(elenergies=energies2) m3 = Molecule(elenergies=energies3) # set transition dipole moments dip1 = [0.0, 2.0, 0.0] dip2 = [0.0, 1.3, 1.4] dip3 = [1.0, 1.2, 0.0] m1.set_dipole(0, 1, dip1) m2.set_dipole(0, 1, dip2) m3.set_dipole(0, 1, dip3) # set molecular positions r1 = [0.0, 0.0, 0.0] r2 = [5.0, 0.0, 0.0] r3 = [0.0, 0.0, 5.0] m1.position = r1 m2.position = r2 m3.position = r3 return [m1, m2, m3] return None